Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

리브/이서연 10주차 워크북 #56

Open
wants to merge 3 commits into
base: 리브/이서연
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package umc.spring.config.security;

import lombok.RequiredArgsConstructor;
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;
import umc.spring.domain.enums.Role;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Service
@RequiredArgsConstructor
public class CustomOAuth2UserService extends DefaultOAuth2UserService {

private final MemberRepository memberRepository;
private final PasswordEncoder passwordEncoder;

@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
OAuth2User oAuth2User = super.loadUser(userRequest);

Map<String, Object> attributes = oAuth2User.getAttributes();
Map<String, Object> properties = (Map<String, Object>) attributes.get("properties");

String nickname = (String) properties.get("nickname");
String email = nickname + "@kakao.com"; // 임시 이메일 생성

// 사용자 정보 저장 또는 업데이트
Member member = saveOrUpdateUser(email, nickname);

// 이메일을 Principal로 사용하기 위해 attributes 수정
Map<String, Object> modifiedAttributes = new HashMap<>(attributes);
modifiedAttributes.put("email", email);

return new DefaultOAuth2User(
oAuth2User.getAuthorities(),
modifiedAttributes,
"email" // email Principal로 설정
);
}

private Member saveOrUpdateUser(String email, String nickname) {
Member member = memberRepository.findByEmail(email)
.orElse(Member.builder()
.email(email)
.name(nickname)
.password(passwordEncoder.encode("OAUTH_USER_" + UUID.randomUUID()))
.gender(Gender.NONE) // 기본값 설정
.address("소셜로그인") // 기본값 설정
.specAddress("소셜로그인") // 기본값 설정
.role(Role.USER)
.build());

return memberRepository.save(member);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package umc.spring.config.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@EnableWebSecurity
@Configuration
public class SecurityConfig {

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((requests) -> requests
.requestMatchers("/", "/home", "/signup", "/css/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin((form) -> form
.loginPage("/login")
.defaultSuccessUrl("/home", true)
.permitAll()
)
.logout((logout) -> logout
.logoutUrl("/logout")
.logoutSuccessUrl("/login?logout")
.permitAll()
)
.oauth2Login(oauth2 -> oauth2
.loginPage("/login")
.defaultSuccessUrl("/home", true)
.permitAll()
);

return http.build();
}

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package umc.spring.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import umc.spring.web.dto.MemberRequestDTO;

@Controller
public class MemberViewController {

@GetMapping("/login")
public String loginPage() {
return "login";
}

@GetMapping("/signup")
public String signupPage(Model model) {
model.addAttribute("memberJoinDto", new MemberRequestDTO.JoinDto());
return "signup";
}

@GetMapping("/home")
public String home() {
return "home";
}

@GetMapping("/admin")
public String admin() {
return "admin";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package umc.spring.web.dto;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;
import umc.spring.domain.enums.Role;

import java.util.List;

public class MemberRequestDTO {
@Getter
@Setter // thymeleaf에서 사용하기 위해 추가
public static class JoinDto {
@NotBlank
String name;
@NotBlank
@Email
String email; // 이메일 필드 추가
@NotBlank
String password; // 비밀번호 필드 추가
@NotNull
Integer gender;
@NotNull
Integer birthYear;
@NotNull
Integer birthMonth;
@NotNull
Integer birthDay;
@Size(min = 5, max = 12)
String address;
@Size(min = 5, max = 12)
String specAddress;
List<Long> preferCategory;
@NotNull
Role role; // 역할 필드 추가
}
}
10 changes: 10 additions & 0 deletions week10/week10_mission/resources/templates/admin.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Admin Page</title>
</head>
<body>
<h2>Admin Page</h2>
<p>관리자만 접근할 수 있는 페이지입니다.</p>
</body>
</html>
17 changes: 17 additions & 0 deletions week10/week10_mission/resources/templates/home.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Home</title>
</head>
<body>
<h2>Welcome to Home Page!</h2>
<p th:text="'반가워, ' + ${#authentication.name} + '!'"></p>
<!-- 관리자 권한이 있을 때만 관리자 페이지 버튼 표시 -->
<div th:if="${#authorization.expression('hasRole(''ADMIN'')')}">
<a th:href="@{/admin}">관리자 페이지로 이동</a>
</div>
<!-- 로그아웃 버튼 추가 -->
<form th:action="@{/logout}" method="post">
<button type="submit">Logout</button>
</form>
</body>
27 changes: 27 additions & 0 deletions week10/week10_mission/resources/templates/login.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Login</title>
</head>
<body>
<h2>Login</h2>
<form th:action="@{/login}" method="post">
<div>
<label for="username">Email:</label>
<input type="text" id="username" name="username" required>
</div>
<div>
<label for="password">Password:</label>
<input type="password" id="password" name="password" required>
</div>
<button type="submit">Login</button>
</form>
<p th:if="${param.error}">사용자 이름 또는 비밀번호가 잘못되었습니다.</p>
<p th:if="${param.logout}">로그아웃되었습니다.</p>
<!-- 회원가입 링크 수정 -->
<p>계정이 없나요? <a th:href="@{/signup}">Sign up</a></p>

<a th:href="@{/oauth2/authorization/kakao}">카카오로 로그인</a>

</body>
</html>
71 changes: 71 additions & 0 deletions week10/week10_mission/resources/templates/signup.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>회원가입</title>
<style>
/* 기존 스타일 유지 */
</style>
</head>
<body>
<h2>회원가입</h2>
<form th:action="@{/members/signup}" th:object="${memberJoinDto}" method="post">
<div th:if="${error}" th:text="${error}" style="color: red;"></div>
<div>
<label for="name">이름:</label>
<input type="text" id="name" th:field="*{name}" required>
</div>
<div>
<label for="email">이메일:</label>
<input type="email" id="email" th:field="*{email}" required>
</div>
<div>
<label for="password">비밀번호:</label>
<input type="password" id="password" th:field="*{password}" required>
</div>
<div>
<label for="gender">성별:</label>
<select id="gender" th:field="*{gender}">
<option value="1">남성</option>
<option value="2">여성</option>
<option value="3">선택안함</option>
</select>
</div>
<div>
<label for="birthYear">출생년도:</label>
<input type="number" id="birthYear" th:field="*{birthYear}" required>
</div>
<div>
<label for="birthMonth">출생월:</label>
<input type="number" id="birthMonth" th:field="*{birthMonth}" min="1" max="12" required>
</div>
<div>
<label for="birthDay">출생일:</label>
<input type="number" id="birthDay" th:field="*{birthDay}" min="1" max="31" required>
</div>
<div>
<label for="address">주소:</label>
<input type="text" id="address" th:field="*{address}" required>
</div>
<div>
<label for="specAddress">상세주소:</label>
<input type="text" id="specAddress" th:field="*{specAddress}" required>
</div>
<div>
<label>선호 카테고리:</label>
<div class="preferCategory">
<label><input type="checkbox" name="preferCategory" value="1"> 한식</label>
<label><input type="checkbox" name="preferCategory" value="2"> 중식</label>
<label><input type="checkbox" name="preferCategory" value="3"> 일식</label>
</div>
</div>
<div>
<label for="role">역할:</label>
<select id="role" th:field="*{role}">
<option value="USER">일반 사용자</option>
<option value="ADMIN">관리자</option>
</select>
</div>
<button type="submit">가입하기</button>
</form>
</body>
</html>
Loading