Skip to content
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
5 changes: 5 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ dependencies {

implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-security'
testImplementation 'org.springframework.security:spring-security-test'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6:3.1.1.RELEASE'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
}

tasks.named('test') {
Expand Down
4 changes: 4 additions & 0 deletions src/main/generated/umc/spring/domain/Quser.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,14 @@ public class Quser extends EntityPathBase<user> {

public final StringPath name = createString("name");

public final StringPath password = createString("password");

public final StringPath phone_num = createString("phone_num");

public final NumberPath<Long> point = createNumber("point", Long.class);

public final EnumPath<umc.spring.domain.enums.Role> role = createEnum("role", umc.spring.domain.enums.Role.class);

public final ListPath<umc.spring.domain.mapping.user_favorite, umc.spring.domain.mapping.Quser_favorite> user_favoriteList = this.<umc.spring.domain.mapping.user_favorite, umc.spring.domain.mapping.Quser_favorite>createList("user_favoriteList", umc.spring.domain.mapping.user_favorite.class, umc.spring.domain.mapping.Quser_favorite.class, PathInits.DIRECT2);

public final ListPath<umc.spring.domain.mapping.user_mission, umc.spring.domain.mapping.Quser_mission> user_missionList = this.<umc.spring.domain.mapping.user_mission, umc.spring.domain.mapping.Quser_mission>createList("user_missionList", umc.spring.domain.mapping.user_mission.class, umc.spring.domain.mapping.Quser_mission.class, PathInits.DIRECT2);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package umc.spring.config.security;

import jakarta.validation.constraints.Null;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
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.Gender;
import umc.spring.domain.enums.Role;
import umc.spring.domain.user;
import umc.spring.repository.UserRepository;

import java.lang.reflect.Member;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Service
@RequiredArgsConstructor
public class CustomOAuth2UserService extends DefaultOAuth2UserService {

private final UserRepository 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"; // 임시 이메일 생성

// 사용자 정보 저장 또는 업데이트
user 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 user saveOrUpdateUser(String email, String nickname) {
user member = memberRepository.findByEmail(email)
.orElse(user.builder()
.email(email)
.name(nickname)
.password(passwordEncoder.encode("OAUTH_USER_" + UUID.randomUUID()))
.gender(Gender.NULL) // 기본값 설정
.address("소셜로그인") // 기본값 설정
.role(Role.USER)
.build());

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

import lombok.RequiredArgsConstructor;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import umc.spring.domain.user;
import umc.spring.repository.UserRepository;

@Service
@RequiredArgsConstructor
public class CustomUserDetailsService implements UserDetailsService {

private final UserRepository memberRepository;

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
user member = memberRepository.findByEmail(username)
.orElseThrow(() -> new UsernameNotFoundException("해당 이메일을 가진 유저가 존재하지 않습니다: " + username));

return org.springframework.security.core.userdetails.User
.withUsername(member.getEmail())
.password(member.getPassword())
.roles(member.getRole().name())
.build();
}
}
45 changes: 45 additions & 0 deletions src/main/java/umc/spring/config/security/SecurityConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package umc.spring.config.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@EnableWebSecurity
@Configuration
public class SecurityConfig {

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((requests) -> requests
.requestMatchers("/", "/home", "/signup", "/members/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();
}
}
30 changes: 30 additions & 0 deletions src/main/java/umc/spring/converter/UserConverter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package umc.spring.converter;

import org.apache.catalina.User;
import umc.spring.domain.enums.Gender;
import umc.spring.domain.user;
import umc.spring.web.dto.UserRequestDTO;

import java.lang.reflect.Member;

public class UserConverter {
public static user toMember(UserRequestDTO.JoinDto request) {
Gender gender = null;
switch (request.getGender()) {
case MALE: gender = Gender.MALE; break;
case FEMALE: gender = Gender.FEMALE; break;
}
System.out.println(request.getPassword());

return user.builder()
.name(request.getName())
.email(request.getEmail()) // 추가된 코드
.password(request.getPassword()) // 추가된 코드
.gender(gender)
.birth(request.getBirth())
.address(request.getAddress())
.role(request.getRole()) // 추가된 코드
.build();
}
// ... 기타 메소드들 ...
}
2 changes: 1 addition & 1 deletion src/main/java/umc/spring/domain/enums/Gender.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package umc.spring.domain.enums;

public enum Gender {
MALE, FEMALE
MALE, FEMALE, NULL
}
5 changes: 5 additions & 0 deletions src/main/java/umc/spring/domain/enums/Role.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package umc.spring.domain.enums;

public enum Role {
ADMIN, USER
}
19 changes: 15 additions & 4 deletions src/main/java/umc/spring/domain/user.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import jakarta.persistence.*;
import lombok.*;
import umc.spring.domain.enums.Gender;
import umc.spring.domain.enums.Role;
import umc.spring.domain.mapping.mission;
import umc.spring.domain.mapping.user_favorite;
import umc.spring.domain.mapping.user_mission;
Expand Down Expand Up @@ -36,16 +37,22 @@ public class user {
@Column(nullable = false, length = 100)
private String address;

@Column(nullable = false, length = 30)
@Column(nullable = false, unique = true)
private String email;

@Column(nullable = false, length = 20)
@Column(nullable = false,length = 255)
private String password;

@Enumerated(EnumType.STRING)
private Role role;

@Column(length = 20)
private String phone_num;

@Column(nullable = false)
@Column()
private Long mission_count;

@Column(nullable = false)
@Column()
private Long point;

@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
Expand All @@ -56,4 +63,8 @@ public class user {

@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<user_review> user_reviewList = new ArrayList<>();

public void encodePassword(String password) {
this.password = password;
}
}
3 changes: 3 additions & 0 deletions src/main/java/umc/spring/repository/UserRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@
import umc.spring.domain.mapping.user_review;
import umc.spring.domain.user;

import java.util.Optional;

public interface UserRepository extends JpaRepository<user, Long> {
Optional<user> findByEmail(String email);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package umc.spring.service.RestaurantService;

import umc.spring.domain.user;
import umc.spring.web.dto.UserRequestDTO;

public interface MemberCommandService {
public user joinMember(UserRequestDTO.JoinDto request);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package umc.spring.service.RestaurantService;

import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import umc.spring.converter.UserConverter;
import umc.spring.converter.UserConverter;
import umc.spring.domain.user;
import umc.spring.repository.UserRepository;
import umc.spring.web.dto.UserRequestDTO;

@Service
@RequiredArgsConstructor
public class MemberCommandServiceImpl implements MemberCommandService{
private final PasswordEncoder passwordEncoder;

private final UserRepository userRepository;

@Override
@Transactional
public user joinMember(UserRequestDTO.JoinDto request) {

user newMember = UserConverter.toMember(request);

newMember.encodePassword(passwordEncoder.encode(request.getPassword()));

return userRepository.save(newMember);
}
}
60 changes: 60 additions & 0 deletions src/main/java/umc/spring/web/controller/MemberViewController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package umc.spring.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import umc.spring.service.RestaurantService.MemberCommandService;
import umc.spring.web.dto.UserRequestDTO;

@Controller
public class MemberViewController {
MemberCommandService memberCommandService;

public MemberViewController(MemberCommandService memberCommandService) {
this.memberCommandService = memberCommandService;
}

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

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

return "signup";
}

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

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

@PostMapping("/members/signup")
public String joinMember(@ModelAttribute("memberJoinDto") UserRequestDTO.JoinDto request, // 협업시에는 기존 RequestBody 어노테이션을 붙여주시면 됩니다!
BindingResult bindingResult,
Model model) {
if (bindingResult.hasErrors()) {
// 뷰에 데이터 바인딩이 실패할 경우 signup 페이지를 유지합니다.
return "signup";
}

try {
memberCommandService.joinMember(request);
return "redirect:/login";
} catch (Exception e) {
// 회원가입 과정에서 에러가 발생할 경우 에러 메시지를 보내고, signup 페이디를 유지합니다.
model.addAttribute("error", e.getMessage());
return "signup";
}
}
}
Loading