From e7183968411aa8d41e0356163ff48b52eb99eb84 Mon Sep 17 00:00:00 2001 From: ayoung-dev Date: Thu, 12 Sep 2024 11:38:56 +0900 Subject: [PATCH 1/2] =?UTF-8?q?Update:=20password=20String=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20passwordEncoder=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9=20=EC=99=84=EB=A3=8C=20Update:=20Member?= =?UTF-8?q?=EC=97=90=20Role=20=EB=B6=80=EC=97=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/build.gradle | 3 ++ .../coffee/backend/config/SecurityConfig.java | 49 +++++++++++++++++++ .../controller/member/MemberController.java | 1 + .../member/request/MemberLoginRequest.java | 2 +- .../member/request/MemberRegisterRequest.java | 6 ++- .../member/request/MemberUpdateRequest.java | 2 +- .../backend/model/entity/member/Member.java | 10 +++- .../model/entity/member/constant/ROLE.java | 14 ++++++ .../model/service/member/MemberService.java | 41 ++++++++++++++-- 9 files changed, 119 insertions(+), 9 deletions(-) create mode 100644 backend/src/main/java/grepp/coffee/backend/config/SecurityConfig.java create mode 100644 backend/src/main/java/grepp/coffee/backend/model/entity/member/constant/ROLE.java diff --git a/backend/build.gradle b/backend/build.gradle index d334be9..b908ac2 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -29,7 +29,10 @@ dependencies { // Spring Web implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-security' testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'org.springframework.security:spring-security-test' + runtimeOnly 'com.h2database:h2' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' // Bean Validation diff --git a/backend/src/main/java/grepp/coffee/backend/config/SecurityConfig.java b/backend/src/main/java/grepp/coffee/backend/config/SecurityConfig.java new file mode 100644 index 0000000..2ab1a02 --- /dev/null +++ b/backend/src/main/java/grepp/coffee/backend/config/SecurityConfig.java @@ -0,0 +1,49 @@ +package grepp.coffee.backend.config; + +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +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; + +@Configuration +@EnableWebSecurity +public class SecurityConfig { + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http + .csrf(csrf -> csrf.disable()) // CSRF 비활성화 + .authorizeHttpRequests(auth -> auth + // ADMIN 역할이 있는 사용자만 접근 가능 + .requestMatchers("/order/admin/**").hasRole("ADMIN") + // 나머지 요청은 누구나 접근 가능 + .anyRequest().permitAll() + ) + .logout(logout -> logout + .logoutUrl("/account/logout") + .logoutSuccessHandler((request, response, authentication) -> + response.setStatus(HttpServletResponse.SC_OK)) + ); + + return http.build(); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { + return authenticationConfiguration.getAuthenticationManager(); + } +} + + + diff --git a/backend/src/main/java/grepp/coffee/backend/controller/member/MemberController.java b/backend/src/main/java/grepp/coffee/backend/controller/member/MemberController.java index 2bcc4cf..99c2fc5 100644 --- a/backend/src/main/java/grepp/coffee/backend/controller/member/MemberController.java +++ b/backend/src/main/java/grepp/coffee/backend/controller/member/MemberController.java @@ -45,6 +45,7 @@ public ResponseEntity login(HttpServletRequest httpServletRequest, HttpSession session = httpServletRequest.getSession(); session.setAttribute("loginMember", member); + session.setAttribute("userRole", member.getRole()); session.setMaxInactiveInterval(60 * 10); return ResponseEntity.ok().body(member); diff --git a/backend/src/main/java/grepp/coffee/backend/controller/member/request/MemberLoginRequest.java b/backend/src/main/java/grepp/coffee/backend/controller/member/request/MemberLoginRequest.java index b0b6db6..f1f8f34 100644 --- a/backend/src/main/java/grepp/coffee/backend/controller/member/request/MemberLoginRequest.java +++ b/backend/src/main/java/grepp/coffee/backend/controller/member/request/MemberLoginRequest.java @@ -14,5 +14,5 @@ public class MemberLoginRequest { private String email; @NotNull - private byte[] password; + private String password; } diff --git a/backend/src/main/java/grepp/coffee/backend/controller/member/request/MemberRegisterRequest.java b/backend/src/main/java/grepp/coffee/backend/controller/member/request/MemberRegisterRequest.java index f99fe2e..b706690 100644 --- a/backend/src/main/java/grepp/coffee/backend/controller/member/request/MemberRegisterRequest.java +++ b/backend/src/main/java/grepp/coffee/backend/controller/member/request/MemberRegisterRequest.java @@ -1,5 +1,6 @@ package grepp.coffee.backend.controller.member.request; +import grepp.coffee.backend.model.entity.member.constant.ROLE; import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Getter; @@ -16,7 +17,10 @@ public class MemberRegisterRequest { private String email; @NotNull - private byte[] password; + private String password; + + @NotNull + private ROLE role; @NotNull private String address; diff --git a/backend/src/main/java/grepp/coffee/backend/controller/member/request/MemberUpdateRequest.java b/backend/src/main/java/grepp/coffee/backend/controller/member/request/MemberUpdateRequest.java index ae7bdfe..63573ed 100644 --- a/backend/src/main/java/grepp/coffee/backend/controller/member/request/MemberUpdateRequest.java +++ b/backend/src/main/java/grepp/coffee/backend/controller/member/request/MemberUpdateRequest.java @@ -11,7 +11,7 @@ public class MemberUpdateRequest { @NotNull - private byte[] password; + private String password; @NotNull private String address; diff --git a/backend/src/main/java/grepp/coffee/backend/model/entity/member/Member.java b/backend/src/main/java/grepp/coffee/backend/model/entity/member/Member.java index 8d8f41b..6e70c54 100644 --- a/backend/src/main/java/grepp/coffee/backend/model/entity/member/Member.java +++ b/backend/src/main/java/grepp/coffee/backend/model/entity/member/Member.java @@ -1,6 +1,7 @@ package grepp.coffee.backend.model.entity.member; import grepp.coffee.backend.model.entity.BaseEntity; +import grepp.coffee.backend.model.entity.member.constant.ROLE; import jakarta.persistence.*; import lombok.AccessLevel; import lombok.Builder; @@ -22,7 +23,11 @@ public class Member extends BaseEntity { private String email; @Column(name = "PASSWORD", nullable = false) - private byte[] password; + private String password; + + @Enumerated(EnumType.STRING) + @Column(name = "ROLE", length = 50, nullable = false, columnDefinition = "VARCHAR(50) DEFAULT 'MEMBER'") + private ROLE role; @Column(name = "POINT", nullable = true) private int point; @@ -34,10 +39,11 @@ public class Member extends BaseEntity { private String postcode; @Builder - public Member(Long memberId, String email, byte[] password, int point, String address, String postcode) { + public Member(Long memberId, String email, String password, ROLE role, int point, String address, String postcode) { this.memberId = memberId; this.email = email; this.password = password; + this.role = role; this.point = point; this.address = address; this.postcode = postcode; diff --git a/backend/src/main/java/grepp/coffee/backend/model/entity/member/constant/ROLE.java b/backend/src/main/java/grepp/coffee/backend/model/entity/member/constant/ROLE.java new file mode 100644 index 0000000..7d743b0 --- /dev/null +++ b/backend/src/main/java/grepp/coffee/backend/model/entity/member/constant/ROLE.java @@ -0,0 +1,14 @@ +package grepp.coffee.backend.model.entity.member.constant; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum ROLE { + ADMIN("ROLE_ADMIN"), + MEMBER("ROLE_MEMBER") + ; + + private final String text; +} \ No newline at end of file diff --git a/backend/src/main/java/grepp/coffee/backend/model/service/member/MemberService.java b/backend/src/main/java/grepp/coffee/backend/model/service/member/MemberService.java index cab474e..5aa814a 100644 --- a/backend/src/main/java/grepp/coffee/backend/model/service/member/MemberService.java +++ b/backend/src/main/java/grepp/coffee/backend/model/service/member/MemberService.java @@ -8,21 +8,53 @@ import grepp.coffee.backend.controller.member.request.MemberRegisterRequest; import grepp.coffee.backend.controller.member.request.MemberUpdateRequest; import grepp.coffee.backend.model.entity.member.Member; +import grepp.coffee.backend.model.entity.member.constant.ROLE; import grepp.coffee.backend.model.repository.member.MemberRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.support.BeanDefinitionDsl; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; @Slf4j @Service @Transactional(readOnly = true) @RequiredArgsConstructor -public class MemberService { +public class MemberService implements UserDetailsService { private final MemberRepository memberRepository; + private final PasswordEncoder passwordEncoder; + + // Spring Security의 UserDetailsService 구현 + @Override + public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { + Member member = memberRepository.findByEmail(email); + + if (member == null) { + throw new MemberException(ExceptionMessage.MEMBER_NOT_FOUND); + } + + return new org.springframework.security.core.userdetails.User( + member.getEmail(), + passwordEncoder.encode(member.getPassword()), + getAuthorities(member.getRole())); + } + + private Collection getAuthorities(ROLE role) { + return Collections.singletonList(new SimpleGrantedAuthority("ROLE_" + role.name())); + } + //회원가입 @Transactional @@ -38,7 +70,8 @@ public void registerMember(MemberRegisterRequest request) { // 새로운 member 생성 및 저장 Member member = Member.builder() .email(request.getEmail()) - .password(request.getPassword()) + .password(passwordEncoder.encode(request.getPassword())) + .role(request.getRole()) .address(request.getAddress()) .build(); memberRepository.save(member); @@ -56,10 +89,10 @@ public Member login(MemberLoginRequest request) { //회원 정보 조회 Member member = getMemberByEmail(request.getEmail()); - String password = (member == null) ? "" : Arrays.toString(member.getPassword()); + String password = (member == null) ? "" : member.getPassword(); //비밀번호 일치 시 회원 정보 리턴 - if (member != null && Arrays.toString(request.getPassword()).equals(password)) + if (member != null && passwordEncoder.matches(request.getPassword(), password)) return member; return null; From c4b39c30a313bb26b7ed1faf87ec5dc195ecfc3e Mon Sep 17 00:00:00 2001 From: ayoung-dev Date: Thu, 12 Sep 2024 12:17:24 +0900 Subject: [PATCH 2/2] =?UTF-8?q?Chore:=20authorizeHttpRequests=20=EB=B9=84?= =?UTF-8?q?=ED=99=9C=EC=84=B1=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../grepp/coffee/backend/config/SecurityConfig.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/src/main/java/grepp/coffee/backend/config/SecurityConfig.java b/backend/src/main/java/grepp/coffee/backend/config/SecurityConfig.java index 2ab1a02..dc531ed 100644 --- a/backend/src/main/java/grepp/coffee/backend/config/SecurityConfig.java +++ b/backend/src/main/java/grepp/coffee/backend/config/SecurityConfig.java @@ -19,12 +19,12 @@ public class SecurityConfig { public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf.disable()) // CSRF 비활성화 - .authorizeHttpRequests(auth -> auth - // ADMIN 역할이 있는 사용자만 접근 가능 - .requestMatchers("/order/admin/**").hasRole("ADMIN") - // 나머지 요청은 누구나 접근 가능 - .anyRequest().permitAll() - ) +// .authorizeHttpRequests(auth -> auth +// // ADMIN 역할이 있는 사용자만 접근 가능 +// .requestMatchers("/order/admin/**").hasRole("ADMIN") +// // 나머지 요청은 누구나 접근 가능 +// .anyRequest().permitAll() +// ) .logout(logout -> logout .logoutUrl("/account/logout") .logoutSuccessHandler((request, response, authentication) ->