From 3de880e91d9d6546894cf2d603f1b9323980ceeb Mon Sep 17 00:00:00 2001 From: jgmoon <6813821@tukorea.ac.kr> Date: Wed, 12 Jun 2024 01:44:39 +0900 Subject: [PATCH 1/7] =?UTF-8?q?chore:=20=EB=AF=B8=EC=82=AC=EC=9A=A9=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=A3=BC=EC=84=9D=20=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?(#10)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Oauth 관련 --- .../oauth2/controller/AuthController.java | 38 ++-- .../controller/CustomSuccessHandler.java | 108 +++++----- .../security/oauth2/dto/CustomOAuth2User.java | 104 +++++----- .../global/security/oauth2/dto/MemberDto.java | 26 +-- .../oauth2/dto/response/KakaoResponse.java | 80 ++++---- .../oauth2/dto/response/NaverResponse.java | 76 +++---- .../oauth2/dto/response/OAuth2Response.java | 24 +-- .../service/CustomOAuth2UserService.java | 188 +++++++++--------- 8 files changed, 322 insertions(+), 322 deletions(-) diff --git a/src/main/java/com/example/moreveiw/global/security/oauth2/controller/AuthController.java b/src/main/java/com/example/moreveiw/global/security/oauth2/controller/AuthController.java index f39cc54..6069577 100644 --- a/src/main/java/com/example/moreveiw/global/security/oauth2/controller/AuthController.java +++ b/src/main/java/com/example/moreveiw/global/security/oauth2/controller/AuthController.java @@ -1,19 +1,19 @@ -package com.example.moreveiw.global.security.oauth2.controller; - -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; - -@RequiredArgsConstructor -@RestController -public class AuthController { - - @GetMapping("/auth") - @ResponseBody - public String authAPI() { - - return "auth route"; - } -} +//package com.example.moreveiw.global.security.oauth2.controller; +// +//import lombok.RequiredArgsConstructor; +//import org.springframework.stereotype.Controller; +//import org.springframework.web.bind.annotation.GetMapping; +//import org.springframework.web.bind.annotation.ResponseBody; +//import org.springframework.web.bind.annotation.RestController; +// +//@RequiredArgsConstructor +//@RestController +//public class AuthController { +// +// @GetMapping("/auth") +// @ResponseBody +// public String authAPI() { +// +// return "auth route"; +// } +//} diff --git a/src/main/java/com/example/moreveiw/global/security/oauth2/controller/CustomSuccessHandler.java b/src/main/java/com/example/moreveiw/global/security/oauth2/controller/CustomSuccessHandler.java index c3b4a56..10d0bf7 100644 --- a/src/main/java/com/example/moreveiw/global/security/oauth2/controller/CustomSuccessHandler.java +++ b/src/main/java/com/example/moreveiw/global/security/oauth2/controller/CustomSuccessHandler.java @@ -1,54 +1,54 @@ -package com.example.moreveiw.global.security.oauth2.controller; - -import com.example.moreveiw.global.security.oauth2.dto.CustomOAuth2User; -import com.example.moreveiw.global.util.JwtUtil; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.Cookie; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import lombok.AllArgsConstructor; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; -import org.springframework.stereotype.Component; - -import java.io.IOException; -import java.util.Collection; -import java.util.Iterator; - -@Component -@AllArgsConstructor -public class CustomSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { - - private final JwtUtil jwtUtil; - - @Override - public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { - - // OAuth2User - CustomOAuth2User customUserDetails = (CustomOAuth2User) authentication.getPrincipal(); - - String memberName = customUserDetails.getMemberName(); - - Collection authorities = authentication.getAuthorities(); - Iterator iterator = authorities.iterator(); - GrantedAuthority auth = iterator.next(); - String role = auth.getAuthority(); - - String token = jwtUtil.createJwt(memberName, role, 60 * 60 * 60L); - - response.addCookie(createCookie("Authorization", token)); - response.sendRedirect("http://localhost:3000/"); - } - - private Cookie createCookie(String key, String value) { - - Cookie cookie = new Cookie(key, value); - cookie.setMaxAge(60*60*60); - // cookie.setSecure(true); - cookie.setPath("/"); - cookie.setHttpOnly(true); - - return cookie; - } -} +//package com.example.moreveiw.global.security.oauth2.controller; +// +//import com.example.moreveiw.global.security.oauth2.dto.CustomOAuth2User; +//import com.example.moreveiw.global.util.JwtUtil; +//import jakarta.servlet.ServletException; +//import jakarta.servlet.http.Cookie; +//import jakarta.servlet.http.HttpServletRequest; +//import jakarta.servlet.http.HttpServletResponse; +//import lombok.AllArgsConstructor; +//import org.springframework.security.core.Authentication; +//import org.springframework.security.core.GrantedAuthority; +//import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; +//import org.springframework.stereotype.Component; +// +//import java.io.IOException; +//import java.util.Collection; +//import java.util.Iterator; +// +//@Component +//@AllArgsConstructor +//public class CustomSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { +// +// private final JwtUtil jwtUtil; +// +// @Override +// public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { +// +// // OAuth2User +// CustomOAuth2User customUserDetails = (CustomOAuth2User) authentication.getPrincipal(); +// +// String memberName = customUserDetails.getMemberName(); +// +// Collection authorities = authentication.getAuthorities(); +// Iterator iterator = authorities.iterator(); +// GrantedAuthority auth = iterator.next(); +// String role = auth.getAuthority(); +// +// String token = jwtUtil.createJwt(memberName, role, 60 * 60 * 60L); +// +// response.addCookie(createCookie("Authorization", token)); +// response.sendRedirect("http://localhost:3000/"); +// } +// +// private Cookie createCookie(String key, String value) { +// +// Cookie cookie = new Cookie(key, value); +// cookie.setMaxAge(60*60*60); +// // cookie.setSecure(true); +// cookie.setPath("/"); +// cookie.setHttpOnly(true); +// +// return cookie; +// } +//} diff --git a/src/main/java/com/example/moreveiw/global/security/oauth2/dto/CustomOAuth2User.java b/src/main/java/com/example/moreveiw/global/security/oauth2/dto/CustomOAuth2User.java index c607e2e..9eb423a 100644 --- a/src/main/java/com/example/moreveiw/global/security/oauth2/dto/CustomOAuth2User.java +++ b/src/main/java/com/example/moreveiw/global/security/oauth2/dto/CustomOAuth2User.java @@ -1,52 +1,52 @@ -package com.example.moreveiw.global.security.oauth2.dto; - -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.oauth2.core.user.OAuth2User; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Map; - -public class CustomOAuth2User implements OAuth2User { - - private final MemberDto memberDto; - - public CustomOAuth2User(MemberDto memberDto) { - - this.memberDto = memberDto; - } - - @Override - public Map getAttributes() { - - return null; - } - - @Override - public Collection getAuthorities() { - - Collection collection = new ArrayList<>(); - - collection.add(new GrantedAuthority() { - - @Override - public String getAuthority() { - - return memberDto.getRole(); - } - }); - - return collection; - } - - @Override - public String getName() { - - return memberDto.getName(); - } - - public String getMemberName() { - - return memberDto.getMemberName(); - } -} +//package com.example.moreveiw.global.security.oauth2.dto; +// +//import org.springframework.security.core.GrantedAuthority; +//import org.springframework.security.oauth2.core.user.OAuth2User; +// +//import java.util.ArrayList; +//import java.util.Collection; +//import java.util.Map; +// +//public class CustomOAuth2User implements OAuth2User { +// +// private final MemberDto memberDto; +// +// public CustomOAuth2User(MemberDto memberDto) { +// +// this.memberDto = memberDto; +// } +// +// @Override +// public Map getAttributes() { +// +// return null; +// } +// +// @Override +// public Collection getAuthorities() { +// +// Collection collection = new ArrayList<>(); +// +// collection.add(new GrantedAuthority() { +// +// @Override +// public String getAuthority() { +// +// return memberDto.getRole(); +// } +// }); +// +// return collection; +// } +// +// @Override +// public String getName() { +// +// return memberDto.getName(); +// } +// +// public String getMemberName() { +// +// return memberDto.getMemberName(); +// } +//} diff --git a/src/main/java/com/example/moreveiw/global/security/oauth2/dto/MemberDto.java b/src/main/java/com/example/moreveiw/global/security/oauth2/dto/MemberDto.java index 9b331c5..0521bc8 100644 --- a/src/main/java/com/example/moreveiw/global/security/oauth2/dto/MemberDto.java +++ b/src/main/java/com/example/moreveiw/global/security/oauth2/dto/MemberDto.java @@ -1,13 +1,13 @@ -package com.example.moreveiw.global.security.oauth2.dto; - -import lombok.Builder; -import lombok.Getter; - -@Getter -@Builder -public class MemberDto { - - private String role; - private String name; - private String memberName; -} +//package com.example.moreveiw.global.security.oauth2.dto; +// +//import lombok.Builder; +//import lombok.Getter; +// +//@Getter +//@Builder +//public class MemberDto { +// +// private String role; +// private String name; +// private String memberName; +//} diff --git a/src/main/java/com/example/moreveiw/global/security/oauth2/dto/response/KakaoResponse.java b/src/main/java/com/example/moreveiw/global/security/oauth2/dto/response/KakaoResponse.java index 77f80c0..d574568 100644 --- a/src/main/java/com/example/moreveiw/global/security/oauth2/dto/response/KakaoResponse.java +++ b/src/main/java/com/example/moreveiw/global/security/oauth2/dto/response/KakaoResponse.java @@ -1,40 +1,40 @@ -package com.example.moreveiw.global.security.oauth2.dto.response; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -import java.util.Map; - -@Getter -@AllArgsConstructor -public class KakaoResponse implements OAuth2Response { - - private final Map attriute; - - @Override - public String getProvider() { - - return "kakao"; - } - - @Override - public String getProviderId() { - - return attriute.get("id").toString(); - } - - @Override - public String getEmail() { - Map kakaoAccount = (Map) attriute.get("kakao_account"); - return (String) kakaoAccount.get("email"); - } - - @Override - public String getName() { - Map kakaoAccount = (Map) attriute.get("kakao_account"); - Map profile = (Map) kakaoAccount.get("profile"); - return (String) profile.get("nickname"); - } - - -} +//package com.example.moreveiw.global.security.oauth2.dto.response; +// +//import lombok.AllArgsConstructor; +//import lombok.Getter; +// +//import java.util.Map; +// +//@Getter +//@AllArgsConstructor +//public class KakaoResponse implements OAuth2Response { +// +// private final Map attriute; +// +// @Override +// public String getProvider() { +// +// return "kakao"; +// } +// +// @Override +// public String getProviderId() { +// +// return attriute.get("id").toString(); +// } +// +// @Override +// public String getEmail() { +// Map kakaoAccount = (Map) attriute.get("kakao_account"); +// return (String) kakaoAccount.get("email"); +// } +// +// @Override +// public String getName() { +// Map kakaoAccount = (Map) attriute.get("kakao_account"); +// Map profile = (Map) kakaoAccount.get("profile"); +// return (String) profile.get("nickname"); +// } +// +// +//} diff --git a/src/main/java/com/example/moreveiw/global/security/oauth2/dto/response/NaverResponse.java b/src/main/java/com/example/moreveiw/global/security/oauth2/dto/response/NaverResponse.java index 861686a..d54064d 100644 --- a/src/main/java/com/example/moreveiw/global/security/oauth2/dto/response/NaverResponse.java +++ b/src/main/java/com/example/moreveiw/global/security/oauth2/dto/response/NaverResponse.java @@ -1,38 +1,38 @@ -package com.example.moreveiw.global.security.oauth2.dto.response; - - -import java.util.Map; - -public class NaverResponse implements OAuth2Response { - - private final Map attribute; - - public NaverResponse(Map attribute) { - - this.attribute = (Map) attribute.get("response"); - } - - @Override - public String getProvider() { - - return "naver"; - } - - @Override - public String getProviderId() { - - return attribute.get("id").toString(); - } - - @Override - public String getEmail() { - - return attribute.get("email").toString(); - } - - @Override - public String getName() { - - return attribute.get("name").toString(); - } -} +//package com.example.moreveiw.global.security.oauth2.dto.response; +// +// +//import java.util.Map; +// +//public class NaverResponse implements OAuth2Response { +// +// private final Map attribute; +// +// public NaverResponse(Map attribute) { +// +// this.attribute = (Map) attribute.get("response"); +// } +// +// @Override +// public String getProvider() { +// +// return "naver"; +// } +// +// @Override +// public String getProviderId() { +// +// return attribute.get("id").toString(); +// } +// +// @Override +// public String getEmail() { +// +// return attribute.get("email").toString(); +// } +// +// @Override +// public String getName() { +// +// return attribute.get("name").toString(); +// } +//} diff --git a/src/main/java/com/example/moreveiw/global/security/oauth2/dto/response/OAuth2Response.java b/src/main/java/com/example/moreveiw/global/security/oauth2/dto/response/OAuth2Response.java index 54e4869..8680d08 100644 --- a/src/main/java/com/example/moreveiw/global/security/oauth2/dto/response/OAuth2Response.java +++ b/src/main/java/com/example/moreveiw/global/security/oauth2/dto/response/OAuth2Response.java @@ -1,12 +1,12 @@ -package com.example.moreveiw.global.security.oauth2.dto.response; - -public interface OAuth2Response { - - String getProvider(); // 제공자 (Ex. naver, kakao) - - String getProviderId(); // 제공자에서 발급해주는 아이디(번호) - - String getEmail(); // 이메일 - - String getName(); // 사용자 실명 (설정한 이름) -} +//package com.example.moreveiw.global.security.oauth2.dto.response; +// +//public interface OAuth2Response { +// +// String getProvider(); // 제공자 (Ex. naver, kakao) +// +// String getProviderId(); // 제공자에서 발급해주는 아이디(번호) +// +// String getEmail(); // 이메일 +// +// String getName(); // 사용자 실명 (설정한 이름) +//} diff --git a/src/main/java/com/example/moreveiw/global/security/oauth2/service/CustomOAuth2UserService.java b/src/main/java/com/example/moreveiw/global/security/oauth2/service/CustomOAuth2UserService.java index 979d9ee..b2b1902 100644 --- a/src/main/java/com/example/moreveiw/global/security/oauth2/service/CustomOAuth2UserService.java +++ b/src/main/java/com/example/moreveiw/global/security/oauth2/service/CustomOAuth2UserService.java @@ -1,94 +1,94 @@ -package com.example.moreveiw.global.security.oauth2.service; - -import com.example.moreveiw.domain.member.editor.MemberEditor; -import com.example.moreveiw.domain.member.model.dao.Member; -import com.example.moreveiw.domain.member.repository.MemberRepository; -import com.example.moreveiw.global.security.oauth2.dto.CustomOAuth2User; -import com.example.moreveiw.global.security.oauth2.dto.response.KakaoResponse; -import com.example.moreveiw.global.security.oauth2.dto.MemberDto; -import com.example.moreveiw.global.security.oauth2.dto.response.NaverResponse; -import com.example.moreveiw.global.security.oauth2.dto.response.OAuth2Response; -import lombok.AllArgsConstructor; -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.OAuth2User; -import org.springframework.stereotype.Service; - -@Service -@AllArgsConstructor -public class CustomOAuth2UserService extends DefaultOAuth2UserService { - - private final MemberRepository memberRepository; - - @Override - public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { - - OAuth2User oAuth2User = super.loadUser(userRequest); - - String registrationId = userRequest.getClientRegistration().getRegistrationId(); - - OAuth2Response oAuth2Response = null; - - if (registrationId.equals("naver")) { - - oAuth2Response = new NaverResponse(oAuth2User.getAttributes()); - } - else if (registrationId.equals("kakao")) { - - oAuth2Response = new KakaoResponse(oAuth2User.getAttributes()); - } - else { - - return null; - } - - // 리소스 서버에서 발급 받은 정보로 사용자를 특정할 아이디값을 만듦 - String memberName = oAuth2Response.getProvider()+" "+oAuth2Response.getProviderId(); - - Member existData = memberRepository.findByMemberName(memberName); - - if (existData == null) { - - Member member = Member.builder() - .memberName(memberName) - .name(oAuth2Response.getName()) - .email(oAuth2Response.getEmail()) - .role("ROLE_MEMBER") - .build(); - - memberRepository.save(member); - - MemberDto memberDto = MemberDto.builder() - .memberName(memberName) - .name(oAuth2Response.getName()) - .role("ROLE_MEMBER") - .build(); - - return new CustomOAuth2User(memberDto); - } - - MemberEditor memberEditor = MemberEditor.builder() - .name(oAuth2Response.getName()) - .email(oAuth2Response.getEmail()) - .build(); - - existData.toEditor() - .name(memberEditor.getName()) - .email(memberEditor.getEmail()) - .build(); - - - memberRepository.save(existData); - - MemberDto memberDto = MemberDto.builder() - .memberName(memberName) - .name(oAuth2Response.getName()) - .role(existData.getRole()) - .build(); - - - return new CustomOAuth2User(memberDto); - - } -} +//package com.example.moreveiw.global.security.oauth2.service; +// +//import com.example.moreveiw.domain.member.editor.MemberEditor; +//import com.example.moreveiw.domain.member.model.dao.Member; +//import com.example.moreveiw.domain.member.repository.MemberRepository; +//import com.example.moreveiw.global.security.oauth2.dto.CustomOAuth2User; +//import com.example.moreveiw.global.security.oauth2.dto.response.KakaoResponse; +//import com.example.moreveiw.global.security.oauth2.dto.MemberDto; +//import com.example.moreveiw.global.security.oauth2.dto.response.NaverResponse; +//import com.example.moreveiw.global.security.oauth2.dto.response.OAuth2Response; +//import lombok.AllArgsConstructor; +//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.OAuth2User; +//import org.springframework.stereotype.Service; +// +//@Service +//@AllArgsConstructor +//public class CustomOAuth2UserService extends DefaultOAuth2UserService { +// +// private final MemberRepository memberRepository; +// +// @Override +// public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { +// +// OAuth2User oAuth2User = super.loadUser(userRequest); +// +// String registrationId = userRequest.getClientRegistration().getRegistrationId(); +// +// OAuth2Response oAuth2Response = null; +// +// if (registrationId.equals("naver")) { +// +// oAuth2Response = new NaverResponse(oAuth2User.getAttributes()); +// } +// else if (registrationId.equals("kakao")) { +// +// oAuth2Response = new KakaoResponse(oAuth2User.getAttributes()); +// } +// else { +// +// return null; +// } +// +// // 리소스 서버에서 발급 받은 정보로 사용자를 특정할 아이디값을 만듦 +// String memberName = oAuth2Response.getProvider()+" "+oAuth2Response.getProviderId(); +// +// Member existData = memberRepository.findByMemberName(memberName); +// +// if (existData == null) { +// +// Member member = Member.builder() +// .memberName(memberName) +// .name(oAuth2Response.getName()) +// .email(oAuth2Response.getEmail()) +// .role("ROLE_MEMBER") +// .build(); +// +// memberRepository.save(member); +// +// MemberDto memberDto = MemberDto.builder() +// .memberName(memberName) +// .name(oAuth2Response.getName()) +// .role("ROLE_MEMBER") +// .build(); +// +// return new CustomOAuth2User(memberDto); +// } +// +// MemberEditor memberEditor = MemberEditor.builder() +// .name(oAuth2Response.getName()) +// .email(oAuth2Response.getEmail()) +// .build(); +// +// existData.toEditor() +// .name(memberEditor.getName()) +// .email(memberEditor.getEmail()) +// .build(); +// +// +// memberRepository.save(existData); +// +// MemberDto memberDto = MemberDto.builder() +// .memberName(memberName) +// .name(oAuth2Response.getName()) +// .role(existData.getRole()) +// .build(); +// +// +// return new CustomOAuth2User(memberDto); +// +// } +//} From 67eb375f6420f4f5924082de3e6752b5f739a64a Mon Sep 17 00:00:00 2001 From: jgmoon <6813821@tukorea.ac.kr> Date: Wed, 12 Jun 2024 02:26:08 +0900 Subject: [PATCH 2/7] =?UTF-8?q?setting:=20=20jwt,=20Spring=20Security=20?= =?UTF-8?q?=EA=B8=B0=EB=B3=B8=20=EC=84=B8=ED=8C=85=20(#10)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/model/dto/CustomUserDetails.java | 70 +++++++++++++++ .../global/config/SecurityConfig.java | 89 ++++++++----------- .../global/security/jwt/JwtFilter.java | 61 ++++--------- .../global/security/jwt/LoginFilter.java | 63 +++++++++++++ .../example/moreveiw/global/util/JwtUtil.java | 2 +- 5 files changed, 190 insertions(+), 95 deletions(-) create mode 100644 src/main/java/com/example/moreveiw/domain/member/model/dto/CustomUserDetails.java create mode 100644 src/main/java/com/example/moreveiw/global/security/jwt/LoginFilter.java diff --git a/src/main/java/com/example/moreveiw/domain/member/model/dto/CustomUserDetails.java b/src/main/java/com/example/moreveiw/domain/member/model/dto/CustomUserDetails.java new file mode 100644 index 0000000..b56f134 --- /dev/null +++ b/src/main/java/com/example/moreveiw/domain/member/model/dto/CustomUserDetails.java @@ -0,0 +1,70 @@ +package com.example.moreveiw.domain.member.model.dto; + +import com.example.moreveiw.domain.member.model.dao.Member; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.ArrayList; +import java.util.Collection; + +@RequiredArgsConstructor +public class CustomUserDetails implements UserDetails { + + private final Member member; + + @Override + public Collection getAuthorities() { + + Collection collection = new ArrayList<>(); + + collection.add(new GrantedAuthority() { + + @Override + public String getAuthority() { + + return member.getRole(); + } + }); + + return collection; + } + + @Override + public String getPassword() { + + return member.getPassword(); + } + + @Override + public String getUsername() { + + return member.getMemberName(); + } + + @Override + public boolean isAccountNonExpired() { + + return true; + } + + @Override + public boolean isAccountNonLocked() { + + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + + return true; + } + + @Override + public boolean isEnabled() { + + return true; + } + + +} diff --git a/src/main/java/com/example/moreveiw/global/config/SecurityConfig.java b/src/main/java/com/example/moreveiw/global/config/SecurityConfig.java index be5765a..5c9325e 100644 --- a/src/main/java/com/example/moreveiw/global/config/SecurityConfig.java +++ b/src/main/java/com/example/moreveiw/global/config/SecurityConfig.java @@ -1,94 +1,79 @@ package com.example.moreveiw.global.config; import com.example.moreveiw.global.security.jwt.JwtFilter; -import com.example.moreveiw.global.security.oauth2.controller.CustomSuccessHandler; -import com.example.moreveiw.global.security.oauth2.service.CustomOAuth2UserService; +import com.example.moreveiw.global.security.jwt.LoginFilter; import com.example.moreveiw.global.util.JwtUtil; -import jakarta.servlet.http.HttpServletRequest; -import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; 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.config.http.SessionCreationPolicy; -import org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import org.springframework.web.cors.CorsConfiguration; -import org.springframework.web.cors.CorsConfigurationSource; - -import java.util.Collections; @Configuration @EnableWebSecurity -@AllArgsConstructor public class SecurityConfig { - private final CustomOAuth2UserService customOAuth2UserService; - private final CustomSuccessHandler customSuccessHandler; + private final AuthenticationConfiguration authenticationConfiguration; private final JwtUtil jwtUtil; + public SecurityConfig(AuthenticationConfiguration authenticationConfiguration, JwtUtil jwtUtil) { + + this.authenticationConfiguration = authenticationConfiguration; + this.jwtUtil = jwtUtil; + } + @Bean - public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception { + + return configuration.getAuthenticationManager(); + } + @Bean + public BCryptPasswordEncoder bCryptPasswordEncoder() { + + return new BCryptPasswordEncoder(); + } - // csrf disable + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + + //csrf disable http .csrf((auth) -> auth.disable()); - // From 로그인 방식 disable + //From 로그인 방식 disable http .formLogin((auth) -> auth.disable()); - // HTTP Basic 인증 방식 disable + //http basic 인증 방식 disable http .httpBasic((auth) -> auth.disable()); - // JwtFilter 추가 - http - .addFilterAfter(new JwtFilter(jwtUtil), OAuth2LoginAuthenticationFilter.class); -// .addFilterBefore(new JwtFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class); - - // oauth2 - http - .oauth2Login((oauth2) -> oauth2 - .userInfoEndpoint(userInfoEndpointConfig -> userInfoEndpointConfig - .userService(customOAuth2UserService)) - .successHandler(customSuccessHandler)); - // 경로별 인가 작업 http .authorizeHttpRequests((auth) -> auth - .requestMatchers("/").permitAll() + .requestMatchers("/login", "/", "/join").permitAll() + .requestMatchers("/admin").hasRole("ADMIN") .anyRequest().authenticated()); - // 세션 설정 : STATELESS http - .sessionManagement((session) -> session - .sessionCreationPolicy(SessionCreationPolicy.STATELESS)); - - // cors 설정 + .addFilterBefore(new JwtFilter(jwtUtil), LoginFilter.class); http - .cors(corsCustomizer -> corsCustomizer.configurationSource(new CorsConfigurationSource() { - - @Override - public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { - - CorsConfiguration configuration = new CorsConfiguration(); + .addFilterAt(new LoginFilter(authenticationManager(authenticationConfiguration), jwtUtil), UsernamePasswordAuthenticationFilter.class); - configuration.setAllowedOrigins(Collections.singletonList("http://localhost:3000")); - configuration.setAllowedMethods(Collections.singletonList("*")); - configuration.setAllowCredentials(true); - configuration.setAllowedHeaders(Collections.singletonList("*")); - configuration.setMaxAge(3600L); - - configuration.setExposedHeaders(Collections.singletonList("Set-Cookie")); - configuration.setExposedHeaders(Collections.singletonList("Authorization")); - - return configuration; - } - })); + //세션 설정 + http + .sessionManagement((session) -> session + .sessionCreationPolicy(SessionCreationPolicy.STATELESS)); return http.build(); } + + } diff --git a/src/main/java/com/example/moreveiw/global/security/jwt/JwtFilter.java b/src/main/java/com/example/moreveiw/global/security/jwt/JwtFilter.java index cc86397..02aa7b0 100644 --- a/src/main/java/com/example/moreveiw/global/security/jwt/JwtFilter.java +++ b/src/main/java/com/example/moreveiw/global/security/jwt/JwtFilter.java @@ -1,11 +1,11 @@ package com.example.moreveiw.global.security.jwt; -import com.example.moreveiw.global.security.oauth2.dto.CustomOAuth2User; -import com.example.moreveiw.global.security.oauth2.dto.MemberDto; +import com.example.moreveiw.domain.member.editor.MemberEditor; +import com.example.moreveiw.domain.member.model.dao.Member; +import com.example.moreveiw.domain.member.model.dto.CustomUserDetails; import com.example.moreveiw.global.util.JwtUtil; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; -import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.AllArgsConstructor; @@ -26,70 +26,47 @@ public class JwtFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - String requestUri = request.getRequestURI(); + //request에서 Authorization 헤더를 찾음 + String authorization= request.getHeader("Authorization"); - if (requestUri.matches("^\\/login(?:\\/.*)?$")) { - - filterChain.doFilter(request, response); - return; - } - if (requestUri.matches("^\\/oauth2(?:\\/.*)?$")) { - - filterChain.doFilter(request, response); - return; - } - - // cookie들을 불러온 뒤 Authorization Key에 담긴 쿠키를 찾음 - String authorization = null; - Cookie[] cookies = request.getCookies(); - for (Cookie cookie : cookies) { - - System.out.println(cookie.getName()); - if (cookie.getName().equals("Authorization")) { - - authorization = cookie.getValue(); - } - } - - // Authorization 헤더 검증 - if (authorization == null) { + //Authorization 헤더 검증 + if (authorization == null || !authorization.startsWith("Bearer ")) { System.out.println("token null"); filterChain.doFilter(request, response); - // 조건이 해당되면 메소드 종료 (필수) + //조건이 해당되면 메소드 종료 (필수) return; } - // 토큰 - String token = authorization; + String token = authorization.split(" ")[1]; - // 토큰 소멸 시간 검증 + //토큰 소멸 시간 검증 if (jwtUtil.isExpired(token)) { System.out.println("token expired"); filterChain.doFilter(request, response); - // 조건이 해당되면 메소드 종료 (필수) + //조건이 해당되면 메소드 종료 (필수) return; } - // 토큰에서 memberName과 role 획득 + String memberName = jwtUtil.getMemberName(token); String role = jwtUtil.getRole(token); - // memberDt를 생성하여 값 수정 - MemberDto memberDto = MemberDto.builder() + // MemberEditorBuilder를 사용하여 MemberEditor 객체 생성 + MemberEditor memberEditor = MemberEditor.builder() .memberName(memberName) + .password("temppassword") .role(role) .build(); - // UserDetails에 회원 정보 객체 담기 - CustomOAuth2User customOAuth2User = new CustomOAuth2User(memberDto); - // 스프링 시큐리티 인증 토큰 생성 - Authentication authToken = new UsernamePasswordAuthenticationToken(customOAuth2User, null, customOAuth2User.getAuthorities()); - // 세션에 사용자 등록 + CustomUserDetails customUserDetails = new CustomUserDetails(Member.builder().build()); + + Authentication authToken = new UsernamePasswordAuthenticationToken(customUserDetails, null, customUserDetails.getAuthorities()); + SecurityContextHolder.getContext().setAuthentication(authToken); filterChain.doFilter(request, response); diff --git a/src/main/java/com/example/moreveiw/global/security/jwt/LoginFilter.java b/src/main/java/com/example/moreveiw/global/security/jwt/LoginFilter.java new file mode 100644 index 0000000..ac152e2 --- /dev/null +++ b/src/main/java/com/example/moreveiw/global/security/jwt/LoginFilter.java @@ -0,0 +1,63 @@ +package com.example.moreveiw.global.security.jwt; + +import com.example.moreveiw.domain.member.model.dto.CustomUserDetails; +import com.example.moreveiw.global.util.JwtUtil; +import jakarta.servlet.FilterChain; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +import java.util.Collection; +import java.util.Iterator; + +@RequiredArgsConstructor +public class LoginFilter extends UsernamePasswordAuthenticationFilter { + + private final AuthenticationManager authenticationManager; + private final JwtUtil jwtUtil; + + @Override + public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { + + String memberName = obtainUsername(request); + String password = obtainPassword(request); + + System.out.println(memberName); + + UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(memberName, password, null); + + return authenticationManager.authenticate(authToken); + } + + @Override + protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) { + + CustomUserDetails customUserDetails = (CustomUserDetails) authentication.getPrincipal(); + + String membername = customUserDetails.getUsername(); + + Collection authorities = authentication.getAuthorities(); + Iterator iterator = authorities.iterator(); + GrantedAuthority auth = iterator.next(); + + String role = auth.getAuthority(); + + + String token = jwtUtil.createJwt(membername, role, 60*60*10L); + + response.addHeader("Authorization", "Bearer " + token); + } + + @Override + protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) { + + response.setStatus(401); + } + +} diff --git a/src/main/java/com/example/moreveiw/global/util/JwtUtil.java b/src/main/java/com/example/moreveiw/global/util/JwtUtil.java index 7294904..dab258b 100644 --- a/src/main/java/com/example/moreveiw/global/util/JwtUtil.java +++ b/src/main/java/com/example/moreveiw/global/util/JwtUtil.java @@ -14,7 +14,7 @@ public class JwtUtil { private SecretKey secretKey; - public JwtUtil(@Value("${JWT_SECRET_KEY}") String secret) { + public JwtUtil(@Value("${jwt.secret_key}") String secret) { secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), Jwts.SIG.HS256.key().build().getAlgorithm()); From 71faea0d1e21dc760842e2cf4309900ee77df0a5 Mon Sep 17 00:00:00 2001 From: jgmoon <6813821@tukorea.ac.kr> Date: Wed, 12 Jun 2024 02:26:42 +0900 Subject: [PATCH 3/7] =?UTF-8?q?feat:=20=20Member=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=97=94=ED=8B=B0=ED=8B=B0=20=EC=88=98=EC=A0=95=20(#10)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Member, MemberEditor --- .../domain/member/editor/MemberEditor.java | 31 ++++++++++++------- .../domain/member/model/dao/Member.java | 7 ++--- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/example/moreveiw/domain/member/editor/MemberEditor.java b/src/main/java/com/example/moreveiw/domain/member/editor/MemberEditor.java index 2775afb..7f4c425 100644 --- a/src/main/java/com/example/moreveiw/domain/member/editor/MemberEditor.java +++ b/src/main/java/com/example/moreveiw/domain/member/editor/MemberEditor.java @@ -8,36 +8,45 @@ @RequiredArgsConstructor public class MemberEditor { - private final String name; - private final String email; + private final String memberName; + private final String password; + private final String role; public static MemberEditorBuilder builder() { return new MemberEditorBuilder(); } public static class MemberEditorBuilder { - private String name; - private String email; + private String memberName; + private String password; + private String role; MemberEditorBuilder() { } - public MemberEditorBuilder name(final String name) { - if (StringUtils.hasText(name)) { - this.name = name; + public MemberEditorBuilder memberName(final String memberName) { + if (StringUtils.hasText(memberName)) { + this.memberName = memberName; } return this; } - public MemberEditorBuilder email(final String email) { - if (StringUtils.hasText(email)) { - this.email = email; + public MemberEditorBuilder password(final String password) { + if (StringUtils.hasText(password)) { + this.password = password; + } + return this; + } + + public MemberEditorBuilder role(final String role) { + if (StringUtils.hasText(role)) { + this.role = role; } return this; } public MemberEditor build() { - return new MemberEditor(name, email); + return new MemberEditor(memberName, password, role); } } } diff --git a/src/main/java/com/example/moreveiw/domain/member/model/dao/Member.java b/src/main/java/com/example/moreveiw/domain/member/model/dao/Member.java index 391fe7a..25f48cf 100644 --- a/src/main/java/com/example/moreveiw/domain/member/model/dao/Member.java +++ b/src/main/java/com/example/moreveiw/domain/member/model/dao/Member.java @@ -21,8 +21,7 @@ public class Member extends BaseEntity { private Long id; private String memberName; - - private String name; + private String password; @Email private String email; @@ -31,8 +30,8 @@ public class Member extends BaseEntity { public MemberEditor.MemberEditorBuilder toEditor() { return MemberEditor.builder() - .name(name) - .email(email); + .memberName(memberName) + .password(password); } } From 95853dd88cf22bcb92833f5465a0232ceafb985c Mon Sep 17 00:00:00 2001 From: jgmoon <6813821@tukorea.ac.kr> Date: Wed, 12 Jun 2024 03:10:41 +0900 Subject: [PATCH 4/7] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=ED=95=84=ED=84=B0=20(#10)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit toDO 그냥 setter로 하기 --- build.gradle | 8 +++- .../member/controller/AdminController.java | 16 ++++++++ .../member/controller/JoinController.java | 24 ++++++++++++ .../member/controller/MainController.java | 16 ++++++++ .../member/model/dto/CustomUserDetails.java | 6 ++- .../domain/member/model/dto/JoinDto.java | 10 +++++ .../member/repository/MemberRepository.java | 2 + .../service/CustomUserDetailService.java | 31 +++++++++++++++ .../domain/member/service/JoinService.java | 38 +++++++++++++++++++ .../global/config/SecurityConfig.java | 1 - .../global/security/jwt/JwtFilter.java | 10 ++--- .../example/moreveiw/global/util/JwtUtil.java | 3 +- 12 files changed, 153 insertions(+), 12 deletions(-) create mode 100644 src/main/java/com/example/moreveiw/domain/member/controller/AdminController.java create mode 100644 src/main/java/com/example/moreveiw/domain/member/controller/JoinController.java create mode 100644 src/main/java/com/example/moreveiw/domain/member/controller/MainController.java create mode 100644 src/main/java/com/example/moreveiw/domain/member/model/dto/JoinDto.java create mode 100644 src/main/java/com/example/moreveiw/domain/member/service/CustomUserDetailService.java create mode 100644 src/main/java/com/example/moreveiw/domain/member/service/JoinService.java diff --git a/build.gradle b/build.gradle index 1193953..6e3371b 100644 --- a/build.gradle +++ b/build.gradle @@ -27,9 +27,11 @@ dependencies { compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' - + implementation 'org.springframework.boot:spring-boot-starter-jdbc' + runtimeOnly 'com.mysql:mysql-connector-j' implementation 'org.springframework.boot:spring-boot-starter-websocket' + //websocket implementation 'org.webjars:sockjs-client' implementation 'org.webjars:sockjs-client:1.5.1' @@ -47,7 +49,9 @@ dependencies { // Spring Security implementation 'org.springframework.boot:spring-boot-starter-security' testImplementation 'org.springframework.security:spring-security-test' - + implementation 'org.springframework.security:spring-security-config:6.3.0' + implementation 'org.springframework.security:spring-security-web:6.3.0' + implementation 'org.springframework.security:spring-security-oauth2-client' // oauth implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' diff --git a/src/main/java/com/example/moreveiw/domain/member/controller/AdminController.java b/src/main/java/com/example/moreveiw/domain/member/controller/AdminController.java new file mode 100644 index 0000000..3bf0d53 --- /dev/null +++ b/src/main/java/com/example/moreveiw/domain/member/controller/AdminController.java @@ -0,0 +1,16 @@ +package com.example.moreveiw.domain.member.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@ResponseBody +public class AdminController { + + @GetMapping("/admin") + public String adminP() { + + return "Admin Controller"; + } +} diff --git a/src/main/java/com/example/moreveiw/domain/member/controller/JoinController.java b/src/main/java/com/example/moreveiw/domain/member/controller/JoinController.java new file mode 100644 index 0000000..f38093e --- /dev/null +++ b/src/main/java/com/example/moreveiw/domain/member/controller/JoinController.java @@ -0,0 +1,24 @@ +package com.example.moreveiw.domain.member.controller; + +import com.example.moreveiw.domain.member.model.dto.JoinDto; +import com.example.moreveiw.domain.member.service.JoinService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@ResponseBody +@RequiredArgsConstructor +public class JoinController { + + private final JoinService joinService; + + @PostMapping("/join") + public String joinProcess(JoinDto joinDto) { + + joinService.joinProcess(joinDto); + + return "ok"; + } +} diff --git a/src/main/java/com/example/moreveiw/domain/member/controller/MainController.java b/src/main/java/com/example/moreveiw/domain/member/controller/MainController.java new file mode 100644 index 0000000..c1416cf --- /dev/null +++ b/src/main/java/com/example/moreveiw/domain/member/controller/MainController.java @@ -0,0 +1,16 @@ +package com.example.moreveiw.domain.member.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@ResponseBody +public class MainController { + + @GetMapping("/") + public String mainP() { + + return "Main Controller"; + } +} diff --git a/src/main/java/com/example/moreveiw/domain/member/model/dto/CustomUserDetails.java b/src/main/java/com/example/moreveiw/domain/member/model/dto/CustomUserDetails.java index b56f134..497c7e8 100644 --- a/src/main/java/com/example/moreveiw/domain/member/model/dto/CustomUserDetails.java +++ b/src/main/java/com/example/moreveiw/domain/member/model/dto/CustomUserDetails.java @@ -8,11 +8,15 @@ import java.util.ArrayList; import java.util.Collection; -@RequiredArgsConstructor public class CustomUserDetails implements UserDetails { private final Member member; + public CustomUserDetails(Member member) { + + this.member = member; + } + @Override public Collection getAuthorities() { diff --git a/src/main/java/com/example/moreveiw/domain/member/model/dto/JoinDto.java b/src/main/java/com/example/moreveiw/domain/member/model/dto/JoinDto.java new file mode 100644 index 0000000..75b87e4 --- /dev/null +++ b/src/main/java/com/example/moreveiw/domain/member/model/dto/JoinDto.java @@ -0,0 +1,10 @@ +package com.example.moreveiw.domain.member.model.dto; + +import lombok.Getter; + +@Getter +public class JoinDto { + + private String memberName; + private String password; +} diff --git a/src/main/java/com/example/moreveiw/domain/member/repository/MemberRepository.java b/src/main/java/com/example/moreveiw/domain/member/repository/MemberRepository.java index 8e44807..e8957d5 100644 --- a/src/main/java/com/example/moreveiw/domain/member/repository/MemberRepository.java +++ b/src/main/java/com/example/moreveiw/domain/member/repository/MemberRepository.java @@ -7,5 +7,7 @@ @Repository public interface MemberRepository extends JpaRepository { + Boolean existsByMemberName(String memberName); + Member findByMemberName(String memberName); } diff --git a/src/main/java/com/example/moreveiw/domain/member/service/CustomUserDetailService.java b/src/main/java/com/example/moreveiw/domain/member/service/CustomUserDetailService.java new file mode 100644 index 0000000..04bcb25 --- /dev/null +++ b/src/main/java/com/example/moreveiw/domain/member/service/CustomUserDetailService.java @@ -0,0 +1,31 @@ +package com.example.moreveiw.domain.member.service; + +import com.example.moreveiw.domain.member.model.dao.Member; +import com.example.moreveiw.domain.member.repository.MemberRepository; +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 com.example.moreveiw.domain.member.model.dto.CustomUserDetails; + +@Service +@RequiredArgsConstructor +public class CustomUserDetailService implements UserDetailsService { + + private final MemberRepository memberRepository; + + @Override + public UserDetails loadUserByUsername(String memberName) throws UsernameNotFoundException { + + Member memberData = memberRepository.findByMemberName(memberName); + + if (memberData != null) { + + return new CustomUserDetails(memberData); + } + + + return null; + } +} diff --git a/src/main/java/com/example/moreveiw/domain/member/service/JoinService.java b/src/main/java/com/example/moreveiw/domain/member/service/JoinService.java new file mode 100644 index 0000000..9aa1bd1 --- /dev/null +++ b/src/main/java/com/example/moreveiw/domain/member/service/JoinService.java @@ -0,0 +1,38 @@ +package com.example.moreveiw.domain.member.service; + +import com.example.moreveiw.domain.member.editor.MemberEditor; +import com.example.moreveiw.domain.member.model.dao.Member; +import com.example.moreveiw.domain.member.model.dto.JoinDto; +import com.example.moreveiw.domain.member.repository.MemberRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class JoinService { + + private final BCryptPasswordEncoder bCryptPasswordEncoder; + private final MemberRepository memberRepository; + + public void joinProcess(JoinDto joinDto) { + + String memberName = joinDto.getMemberName(); + String password = joinDto.getPassword(); + + Boolean isExist = memberRepository.existsByMemberName(memberName); + + if (isExist) { + + return; + } + + MemberEditor memberEditor = MemberEditor.builder() + .memberName(memberName) + .password(bCryptPasswordEncoder.encode(password)) + .role("ROLE_ADMIN") + .build(); + + memberRepository.save(Member.builder().build()); + } +} diff --git a/src/main/java/com/example/moreveiw/global/config/SecurityConfig.java b/src/main/java/com/example/moreveiw/global/config/SecurityConfig.java index 5c9325e..11bdce4 100644 --- a/src/main/java/com/example/moreveiw/global/config/SecurityConfig.java +++ b/src/main/java/com/example/moreveiw/global/config/SecurityConfig.java @@ -3,7 +3,6 @@ import com.example.moreveiw.global.security.jwt.JwtFilter; import com.example.moreveiw.global.security.jwt.LoginFilter; import com.example.moreveiw.global.util.JwtUtil; -import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; diff --git a/src/main/java/com/example/moreveiw/global/security/jwt/JwtFilter.java b/src/main/java/com/example/moreveiw/global/security/jwt/JwtFilter.java index 02aa7b0..bbba870 100644 --- a/src/main/java/com/example/moreveiw/global/security/jwt/JwtFilter.java +++ b/src/main/java/com/example/moreveiw/global/security/jwt/JwtFilter.java @@ -1,15 +1,14 @@ package com.example.moreveiw.global.security.jwt; -import com.example.moreveiw.domain.member.editor.MemberEditor; -import com.example.moreveiw.domain.member.model.dao.Member; import com.example.moreveiw.domain.member.model.dto.CustomUserDetails; +import com.example.moreveiw.domain.member.model.dao.Member; +import com.example.moreveiw.domain.member.editor.MemberEditor; import com.example.moreveiw.global.util.JwtUtil; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import lombok.AllArgsConstructor; -import lombok.Builder; +import lombok.RequiredArgsConstructor; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; @@ -17,8 +16,7 @@ import java.io.IOException; -@Builder -@AllArgsConstructor +@RequiredArgsConstructor public class JwtFilter extends OncePerRequestFilter { private final JwtUtil jwtUtil; diff --git a/src/main/java/com/example/moreveiw/global/util/JwtUtil.java b/src/main/java/com/example/moreveiw/global/util/JwtUtil.java index dab258b..2dcd955 100644 --- a/src/main/java/com/example/moreveiw/global/util/JwtUtil.java +++ b/src/main/java/com/example/moreveiw/global/util/JwtUtil.java @@ -16,8 +16,7 @@ public class JwtUtil { public JwtUtil(@Value("${jwt.secret_key}") String secret) { - - secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), Jwts.SIG.HS256.key().build().getAlgorithm()); + this.secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), Jwts.SIG.HS256.key().build().getAlgorithm()); } public String getMemberName(String token) { From 0b8f3cdbbf7c8659886b25c7c51578657d2eb80f Mon Sep 17 00:00:00 2001 From: jgmoon <6813821@tukorea.ac.kr> Date: Wed, 12 Jun 2024 23:11:49 +0900 Subject: [PATCH 5/7] =?UTF-8?q?feat:=20CorsConfig=20=EC=B6=94=EA=B0=80=20(?= =?UTF-8?q?#10)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../moreveiw/global/config/CorsConfig.java | 26 +++++++++++++++++++ .../moreveiw/global/config/CorsMvcConfig.java | 18 ------------- 2 files changed, 26 insertions(+), 18 deletions(-) create mode 100644 src/main/java/com/example/moreveiw/global/config/CorsConfig.java delete mode 100644 src/main/java/com/example/moreveiw/global/config/CorsMvcConfig.java diff --git a/src/main/java/com/example/moreveiw/global/config/CorsConfig.java b/src/main/java/com/example/moreveiw/global/config/CorsConfig.java new file mode 100644 index 0000000..a54a44d --- /dev/null +++ b/src/main/java/com/example/moreveiw/global/config/CorsConfig.java @@ -0,0 +1,26 @@ +package com.example.moreveiw.global.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +import java.util.Collections; + +@Configuration +public class CorsConfig { + + @Bean + public CorsFilter corsFilter() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + CorsConfiguration config = new CorsConfiguration(); + config.setAllowCredentials(true); + config.setAllowedOriginPatterns(Collections.singletonList("*")); + config.setAllowedHeaders(Collections.singletonList("*")); + config.setAllowedMethods(Collections.singletonList("*")); + + source.registerCorsConfiguration("/api/**", config); + return new CorsFilter(source); + } +} diff --git a/src/main/java/com/example/moreveiw/global/config/CorsMvcConfig.java b/src/main/java/com/example/moreveiw/global/config/CorsMvcConfig.java deleted file mode 100644 index 41572b5..0000000 --- a/src/main/java/com/example/moreveiw/global/config/CorsMvcConfig.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.example.moreveiw.global.config; - -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.CorsRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -@Configuration -public class CorsMvcConfig implements WebMvcConfigurer { - - @Override - public void addCorsMappings(CorsRegistry corsRegistry) { - - corsRegistry.addMapping("/**") - .exposedHeaders("Set-Cookie") - .allowedOrigins("http://localhost:3000"); - } - -} From a85a10c7f2e46a92a090f7058fc2dc0f9b5d2a78 Mon Sep 17 00:00:00 2001 From: jgmoon <6813821@tukorea.ac.kr> Date: Thu, 13 Jun 2024 00:49:10 +0900 Subject: [PATCH 6/7] =?UTF-8?q?feat:=20Member=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20(#10)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 34 +++---- .../moreveiw/domain/base/BaseEntity.java | 1 - .../member/controller/AdminController.java | 16 ---- .../member/controller/JoinController.java | 24 ----- .../member/controller/MainController.java | 16 ---- .../controller/MemberApiController.java | 43 --------- .../member/controller/MemberController.java | 59 ++++++++++++ .../exception/DuplicateMemberException.java | 20 ++++ .../exception/NotFoundMemberException.java | 20 ++++ .../domain/member/model/dao/Authority.java | 18 ++++ .../domain/member/model/dao/Member.java | 25 +++-- .../domain/member/model/dao/MemberMapper.java | 48 ++++++++++ .../domain/member/model/dao/Role.java | 5 + .../domain/member/model/dto/AuthorityDto.java | 12 +++ .../member/model/dto/CustomUserDetails.java | 74 --------------- .../domain/member/model/dto/JoinDto.java | 10 -- .../domain/member/model/dto/TokenDto.java | 13 +++ .../model/dto/request/AddMemberRequest.java | 14 --- .../model/dto/request/MemberLoginRequest.java | 18 ++++ .../model/dto/request/MemberRequest.java | 22 +++++ .../dto/response/MemberListResponse.java | 15 +++ .../model/dto/response/MemberResponse.java | 19 ++++ .../member/repository/MemberRepository.java | 8 +- .../service/CustomUserDetailService.java | 31 ------ .../service/CustomUserDetailsService.java | 43 +++++++++ .../domain/member/service/JoinService.java | 38 -------- .../member/service/MemberDetailService.java | 20 ---- .../domain/member/service/MemberService.java | 77 ++++++++------- .../websocket/handler/WebSocketHandler.java | 2 + .../global/config/SecurityConfig.java | 90 +++++++++--------- .../global/config/WebSocketConfig.java | 2 +- .../security/jwt/JwtAccessDeniedHandler.java | 20 ++++ .../jwt/JwtAuthenticationEntryPoint.java | 20 ++++ .../global/security/jwt/JwtFilter.java | 82 +++++++--------- .../security/jwt/JwtSecurityConfig.java | 21 +++++ .../global/security/jwt/LoginFilter.java | 63 ------------- .../global/security/jwt/TokenProvider.java | 94 +++++++++++++++++++ .../example/moreveiw/global/util/JwtUtil.java | 47 ---------- .../moreveiw/global/util/SecurityUtil.java | 38 ++++++++ 39 files changed, 661 insertions(+), 561 deletions(-) delete mode 100644 src/main/java/com/example/moreveiw/domain/member/controller/AdminController.java delete mode 100644 src/main/java/com/example/moreveiw/domain/member/controller/JoinController.java delete mode 100644 src/main/java/com/example/moreveiw/domain/member/controller/MainController.java delete mode 100644 src/main/java/com/example/moreveiw/domain/member/controller/MemberApiController.java create mode 100644 src/main/java/com/example/moreveiw/domain/member/controller/MemberController.java create mode 100644 src/main/java/com/example/moreveiw/domain/member/exception/DuplicateMemberException.java create mode 100644 src/main/java/com/example/moreveiw/domain/member/exception/NotFoundMemberException.java create mode 100644 src/main/java/com/example/moreveiw/domain/member/model/dao/Authority.java create mode 100644 src/main/java/com/example/moreveiw/domain/member/model/dao/MemberMapper.java create mode 100644 src/main/java/com/example/moreveiw/domain/member/model/dao/Role.java create mode 100644 src/main/java/com/example/moreveiw/domain/member/model/dto/AuthorityDto.java delete mode 100644 src/main/java/com/example/moreveiw/domain/member/model/dto/CustomUserDetails.java delete mode 100644 src/main/java/com/example/moreveiw/domain/member/model/dto/JoinDto.java create mode 100644 src/main/java/com/example/moreveiw/domain/member/model/dto/TokenDto.java delete mode 100644 src/main/java/com/example/moreveiw/domain/member/model/dto/request/AddMemberRequest.java create mode 100644 src/main/java/com/example/moreveiw/domain/member/model/dto/request/MemberLoginRequest.java create mode 100644 src/main/java/com/example/moreveiw/domain/member/model/dto/request/MemberRequest.java create mode 100644 src/main/java/com/example/moreveiw/domain/member/model/dto/response/MemberListResponse.java create mode 100644 src/main/java/com/example/moreveiw/domain/member/model/dto/response/MemberResponse.java delete mode 100644 src/main/java/com/example/moreveiw/domain/member/service/CustomUserDetailService.java create mode 100644 src/main/java/com/example/moreveiw/domain/member/service/CustomUserDetailsService.java delete mode 100644 src/main/java/com/example/moreveiw/domain/member/service/JoinService.java delete mode 100644 src/main/java/com/example/moreveiw/domain/member/service/MemberDetailService.java create mode 100644 src/main/java/com/example/moreveiw/global/security/jwt/JwtAccessDeniedHandler.java create mode 100644 src/main/java/com/example/moreveiw/global/security/jwt/JwtAuthenticationEntryPoint.java create mode 100644 src/main/java/com/example/moreveiw/global/security/jwt/JwtSecurityConfig.java delete mode 100644 src/main/java/com/example/moreveiw/global/security/jwt/LoginFilter.java create mode 100644 src/main/java/com/example/moreveiw/global/security/jwt/TokenProvider.java delete mode 100644 src/main/java/com/example/moreveiw/global/util/JwtUtil.java create mode 100644 src/main/java/com/example/moreveiw/global/util/SecurityUtil.java diff --git a/build.gradle b/build.gradle index 6e3371b..d1ffb0d 100644 --- a/build.gradle +++ b/build.gradle @@ -23,48 +23,50 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation('commons-io:commons-io:2.11.0') + compileOnly 'org.projectlombok:lombok' - annotationProcessor 'org.projectlombok:lombok' - testImplementation 'org.springframework.boot:spring-boot-starter-test' + + developmentOnly 'org.springframework.boot:spring-boot-devtools' + implementation 'org.springframework.boot:spring-boot-starter-jdbc' runtimeOnly 'com.mysql:mysql-connector-j' - implementation 'org.springframework.boot:spring-boot-starter-websocket' - - //websocket + // websocket implementation 'org.webjars:sockjs-client' implementation 'org.webjars:sockjs-client:1.5.1' implementation 'org.webjars:stomp-websocket:2.3.3' + implementation 'org.springframework.boot:spring-boot-starter-websocket' - //mariaDB - runtimeOnly 'org.mariadb.jdbc:mariadb-java-client' + // mariaDB + runtimeOnly 'org.mariadb.jdbc:mariadb-java-client' // Gradle - implementation 'javax.persistence:javax.persistence-api:2.2' + implementation 'javax.persistence:javax.persistence-api:2.2' // Swagger implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0' // Spring Security - implementation 'org.springframework.boot:spring-boot-starter-security' + testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' - implementation 'org.springframework.security:spring-security-config:6.3.0' - implementation 'org.springframework.security:spring-security-web:6.3.0' - implementation 'org.springframework.security:spring-security-oauth2-client' // oauth implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' // jwt - implementation 'io.jsonwebtoken:jjwt-api:0.12.3' - implementation 'io.jsonwebtoken:jjwt-impl:0.12.3' - implementation 'io.jsonwebtoken:jjwt-jackson:0.12.3' + implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.5' + runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.5' + runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5' // Annotation Processor annotationProcessor "org.springframework.boot:spring-boot-configuration-processor" + annotationProcessor 'org.projectlombok:lombok' - //validation + // validation implementation 'org.springframework.boot:spring-boot-starter-validation' } diff --git a/src/main/java/com/example/moreveiw/domain/base/BaseEntity.java b/src/main/java/com/example/moreveiw/domain/base/BaseEntity.java index 693289a..0b69dd8 100644 --- a/src/main/java/com/example/moreveiw/domain/base/BaseEntity.java +++ b/src/main/java/com/example/moreveiw/domain/base/BaseEntity.java @@ -2,7 +2,6 @@ import lombok.Getter; import org.springframework.data.annotation.CreatedBy; -import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedBy; import org.springframework.data.jpa.domain.support.AuditingEntityListener; diff --git a/src/main/java/com/example/moreveiw/domain/member/controller/AdminController.java b/src/main/java/com/example/moreveiw/domain/member/controller/AdminController.java deleted file mode 100644 index 3bf0d53..0000000 --- a/src/main/java/com/example/moreveiw/domain/member/controller/AdminController.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.example.moreveiw.domain.member.controller; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@ResponseBody -public class AdminController { - - @GetMapping("/admin") - public String adminP() { - - return "Admin Controller"; - } -} diff --git a/src/main/java/com/example/moreveiw/domain/member/controller/JoinController.java b/src/main/java/com/example/moreveiw/domain/member/controller/JoinController.java deleted file mode 100644 index f38093e..0000000 --- a/src/main/java/com/example/moreveiw/domain/member/controller/JoinController.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.example.moreveiw.domain.member.controller; - -import com.example.moreveiw.domain.member.model.dto.JoinDto; -import com.example.moreveiw.domain.member.service.JoinService; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@ResponseBody -@RequiredArgsConstructor -public class JoinController { - - private final JoinService joinService; - - @PostMapping("/join") - public String joinProcess(JoinDto joinDto) { - - joinService.joinProcess(joinDto); - - return "ok"; - } -} diff --git a/src/main/java/com/example/moreveiw/domain/member/controller/MainController.java b/src/main/java/com/example/moreveiw/domain/member/controller/MainController.java deleted file mode 100644 index c1416cf..0000000 --- a/src/main/java/com/example/moreveiw/domain/member/controller/MainController.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.example.moreveiw.domain.member.controller; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@ResponseBody -public class MainController { - - @GetMapping("/") - public String mainP() { - - return "Main Controller"; - } -} diff --git a/src/main/java/com/example/moreveiw/domain/member/controller/MemberApiController.java b/src/main/java/com/example/moreveiw/domain/member/controller/MemberApiController.java deleted file mode 100644 index ac3628d..0000000 --- a/src/main/java/com/example/moreveiw/domain/member/controller/MemberApiController.java +++ /dev/null @@ -1,43 +0,0 @@ -//package com.moreview.domain.member.controller; -// -//import com.moreview.domain.member.dto.request.AddMemberRequest; -//import com.moreview.domain.member.service.MemberService; -//import jakarta.servlet.http.HttpServletRequest; -//import jakarta.servlet.http.HttpServletResponse; -//import lombok.RequiredArgsConstructor; -//import org.springframework.security.core.context.SecurityContextHolder; -//import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; -//import org.springframework.stereotype.Controller; -//import org.springframework.web.bind.annotation.GetMapping; -//import org.springframework.web.bind.annotation.PostMapping; -//import org.springframework.web.bind.annotation.RequestMapping; -// -//@Controller -//@RequiredArgsConstructor -//@RequestMapping("api/v1") -//public class MemberApiController { -// -// private final MemberService memberService; -// -// @PostMapping("/members") -// public String singup(AddMemberRequest request) { -// memberService.save(request); -// return "redirect:/login"; -// } -// -// @GetMapping("/signup") -// public String signup() { -// return "signup"; -// } -// -// @GetMapping("/login") -// public String login() { -// return "oauthLogin"; -// } -// -// @GetMapping("/logout") -// public String logout(HttpServletRequest request, HttpServletResponse response) { -// new SecurityContextLogoutHandler().logout(request, response, SecurityContextHolder.getContext().getAuthentication()); -// return "redirect:/login"; -// } -//} diff --git a/src/main/java/com/example/moreveiw/domain/member/controller/MemberController.java b/src/main/java/com/example/moreveiw/domain/member/controller/MemberController.java new file mode 100644 index 0000000..1d57183 --- /dev/null +++ b/src/main/java/com/example/moreveiw/domain/member/controller/MemberController.java @@ -0,0 +1,59 @@ +package com.example.moreveiw.domain.member.controller; + +import com.example.moreveiw.domain.member.model.dto.TokenDto; +import com.example.moreveiw.domain.member.model.dto.request.MemberLoginRequest; +import com.example.moreveiw.domain.member.model.dto.request.MemberRequest; +import com.example.moreveiw.domain.member.model.dto.response.MemberResponse; +import com.example.moreveiw.domain.member.service.MemberService; +import com.example.moreveiw.global.security.jwt.JwtFilter; +import com.example.moreveiw.global.security.jwt.TokenProvider; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api") +@RequiredArgsConstructor +public class MemberController { + + private final TokenProvider tokenProvider; + private final AuthenticationManagerBuilder authenticationManagerBuilder; + private final MemberService memberService; + + @PostMapping("/sign-in") + public ResponseEntity signIn(@Valid @RequestBody MemberRequest request) { + return ResponseEntity.ok(memberService.signup(request)); + } + + @PostMapping("/login") + public ResponseEntity authorize(@Valid @RequestBody MemberLoginRequest request) { + + UsernamePasswordAuthenticationToken authenticationToken = + new UsernamePasswordAuthenticationToken(request.getEmail(), request.getPassword()); + + Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); + SecurityContextHolder.getContext().setAuthentication(authentication); + + String jwt = tokenProvider.createToken(authentication); + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.add(JwtFilter.AUTHORIZATION_HEADER, "Bearer " + jwt); + + return new ResponseEntity<>(new TokenDto(jwt), httpHeaders, HttpStatus.OK); + } + + @GetMapping("/user") + @PreAuthorize("hasAnyRole('USER','ADMIN')") + public ResponseEntity getMyUserInfo(HttpServletRequest request) { + return ResponseEntity.ok(memberService.getMyMemberWithAuthorities()); + } +} diff --git a/src/main/java/com/example/moreveiw/domain/member/exception/DuplicateMemberException.java b/src/main/java/com/example/moreveiw/domain/member/exception/DuplicateMemberException.java new file mode 100644 index 0000000..edf6e2b --- /dev/null +++ b/src/main/java/com/example/moreveiw/domain/member/exception/DuplicateMemberException.java @@ -0,0 +1,20 @@ +package com.example.moreveiw.domain.member.exception; + +public class DuplicateMemberException extends RuntimeException { + + public DuplicateMemberException() { + super(); + } + + public DuplicateMemberException(String message, Throwable cause) { + super(message, cause); + } + + public DuplicateMemberException(String message) { + super(message); + } + + public DuplicateMemberException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/example/moreveiw/domain/member/exception/NotFoundMemberException.java b/src/main/java/com/example/moreveiw/domain/member/exception/NotFoundMemberException.java new file mode 100644 index 0000000..96d21b1 --- /dev/null +++ b/src/main/java/com/example/moreveiw/domain/member/exception/NotFoundMemberException.java @@ -0,0 +1,20 @@ +package com.example.moreveiw.domain.member.exception; + +public class NotFoundMemberException extends RuntimeException { + + public NotFoundMemberException() { + super(); + } + + public NotFoundMemberException(String message, Throwable cause) { + super(message, cause); + } + + public NotFoundMemberException(String message) { + super(message); + } + + public NotFoundMemberException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/example/moreveiw/domain/member/model/dao/Authority.java b/src/main/java/com/example/moreveiw/domain/member/model/dao/Authority.java new file mode 100644 index 0000000..d7d5004 --- /dev/null +++ b/src/main/java/com/example/moreveiw/domain/member/model/dao/Authority.java @@ -0,0 +1,18 @@ +package com.example.moreveiw.domain.member.model.dao; + +import jakarta.persistence.*; +import lombok.*; + +@Entity +@Table(name = "authority") +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Authority { + + @Id + @Column(name = "authority_name", length = 50) + private String authorityName; +} diff --git a/src/main/java/com/example/moreveiw/domain/member/model/dao/Member.java b/src/main/java/com/example/moreveiw/domain/member/model/dao/Member.java index 25f48cf..0c391b9 100644 --- a/src/main/java/com/example/moreveiw/domain/member/model/dao/Member.java +++ b/src/main/java/com/example/moreveiw/domain/member/model/dao/Member.java @@ -1,26 +1,25 @@ package com.example.moreveiw.domain.member.model.dao; import com.example.moreveiw.domain.base.BaseEntity; -import com.example.moreveiw.domain.member.editor.MemberEditor; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; +import jakarta.persistence.*; import jakarta.validation.constraints.Email; import lombok.*; +import java.util.Set; + +@Entity @Getter @Builder -@Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor public class Member extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "user_id") private Long id; - private String memberName; + private String name; private String password; @Email @@ -28,10 +27,10 @@ public class Member extends BaseEntity { private String role; - public MemberEditor.MemberEditorBuilder toEditor() { - return MemberEditor.builder() - .memberName(memberName) - .password(password); - } - + @JoinTable( + name = "user_authority", + joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "user_id")}, + inverseJoinColumns = {@JoinColumn(name = "authority_name", referencedColumnName = "authority_name")}) + @ManyToMany + private Set authorities; } diff --git a/src/main/java/com/example/moreveiw/domain/member/model/dao/MemberMapper.java b/src/main/java/com/example/moreveiw/domain/member/model/dao/MemberMapper.java new file mode 100644 index 0000000..b10bcb2 --- /dev/null +++ b/src/main/java/com/example/moreveiw/domain/member/model/dao/MemberMapper.java @@ -0,0 +1,48 @@ +package com.example.moreveiw.domain.member.model.dao; + +import com.example.moreveiw.domain.member.model.dto.request.MemberRequest; +import com.example.moreveiw.domain.member.model.dto.response.MemberListResponse; +import com.example.moreveiw.domain.member.model.dto.response.MemberResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +@Component +@RequiredArgsConstructor +public class MemberMapper { + + private final PasswordEncoder passwordEncoder; + + public Member toEntity(MemberRequest request) { + + Member member = Member.builder() + .name(request.getName()) + .email(request.getEmail()) + .password(passwordEncoder.encode(request.getPassword())) + .build(); + + return member; + } + + public MemberResponse toResponse(Member member) { + if (member == null) return null; + + return MemberResponse.builder() + .email(member.getEmail()) + .role(member.getRole()) + .name(member.getName()) + .build(); + } + + public MemberListResponse toListResponse(List memberList) { + List memberResponseList = + memberList.stream().map(this::toResponse).collect(Collectors.toList()); + return MemberListResponse.builder() + .memberList(memberResponseList) + .build(); + } +} diff --git a/src/main/java/com/example/moreveiw/domain/member/model/dao/Role.java b/src/main/java/com/example/moreveiw/domain/member/model/dao/Role.java new file mode 100644 index 0000000..a5faa87 --- /dev/null +++ b/src/main/java/com/example/moreveiw/domain/member/model/dao/Role.java @@ -0,0 +1,5 @@ +package com.example.moreveiw.domain.member.model.dao; + +public enum Role { + ADMIN, USER +} diff --git a/src/main/java/com/example/moreveiw/domain/member/model/dto/AuthorityDto.java b/src/main/java/com/example/moreveiw/domain/member/model/dto/AuthorityDto.java new file mode 100644 index 0000000..92975a4 --- /dev/null +++ b/src/main/java/com/example/moreveiw/domain/member/model/dto/AuthorityDto.java @@ -0,0 +1,12 @@ +package com.example.moreveiw.domain.member.model.dto; + +import lombok.*; + +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class AuthorityDto { + private String authorityName; +} \ No newline at end of file diff --git a/src/main/java/com/example/moreveiw/domain/member/model/dto/CustomUserDetails.java b/src/main/java/com/example/moreveiw/domain/member/model/dto/CustomUserDetails.java deleted file mode 100644 index 497c7e8..0000000 --- a/src/main/java/com/example/moreveiw/domain/member/model/dto/CustomUserDetails.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.example.moreveiw.domain.member.model.dto; - -import com.example.moreveiw.domain.member.model.dao.Member; -import lombok.RequiredArgsConstructor; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; - -import java.util.ArrayList; -import java.util.Collection; - -public class CustomUserDetails implements UserDetails { - - private final Member member; - - public CustomUserDetails(Member member) { - - this.member = member; - } - - @Override - public Collection getAuthorities() { - - Collection collection = new ArrayList<>(); - - collection.add(new GrantedAuthority() { - - @Override - public String getAuthority() { - - return member.getRole(); - } - }); - - return collection; - } - - @Override - public String getPassword() { - - return member.getPassword(); - } - - @Override - public String getUsername() { - - return member.getMemberName(); - } - - @Override - public boolean isAccountNonExpired() { - - return true; - } - - @Override - public boolean isAccountNonLocked() { - - return true; - } - - @Override - public boolean isCredentialsNonExpired() { - - return true; - } - - @Override - public boolean isEnabled() { - - return true; - } - - -} diff --git a/src/main/java/com/example/moreveiw/domain/member/model/dto/JoinDto.java b/src/main/java/com/example/moreveiw/domain/member/model/dto/JoinDto.java deleted file mode 100644 index 75b87e4..0000000 --- a/src/main/java/com/example/moreveiw/domain/member/model/dto/JoinDto.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.example.moreveiw.domain.member.model.dto; - -import lombok.Getter; - -@Getter -public class JoinDto { - - private String memberName; - private String password; -} diff --git a/src/main/java/com/example/moreveiw/domain/member/model/dto/TokenDto.java b/src/main/java/com/example/moreveiw/domain/member/model/dto/TokenDto.java new file mode 100644 index 0000000..8e0247b --- /dev/null +++ b/src/main/java/com/example/moreveiw/domain/member/model/dto/TokenDto.java @@ -0,0 +1,13 @@ +package com.example.moreveiw.domain.member.model.dto; + +import lombok.*; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TokenDto { + + private String token; +} diff --git a/src/main/java/com/example/moreveiw/domain/member/model/dto/request/AddMemberRequest.java b/src/main/java/com/example/moreveiw/domain/member/model/dto/request/AddMemberRequest.java deleted file mode 100644 index fb2b81b..0000000 --- a/src/main/java/com/example/moreveiw/domain/member/model/dto/request/AddMemberRequest.java +++ /dev/null @@ -1,14 +0,0 @@ -//package com.moreview.domain.member.dto.request; -// -//import lombok.AllArgsConstructor; -//import lombok.Builder; -//import lombok.Getter; -// -//@Getter -//@Builder -//@AllArgsConstructor -//public class AddMemberRequest { -// -// private String email; -// private String password; -//} diff --git a/src/main/java/com/example/moreveiw/domain/member/model/dto/request/MemberLoginRequest.java b/src/main/java/com/example/moreveiw/domain/member/model/dto/request/MemberLoginRequest.java new file mode 100644 index 0000000..4277792 --- /dev/null +++ b/src/main/java/com/example/moreveiw/domain/member/model/dto/request/MemberLoginRequest.java @@ -0,0 +1,18 @@ +package com.example.moreveiw.domain.member.model.dto.request; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import lombok.*; + +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class MemberLoginRequest { + @NotBlank + @Email + private String email; + @NotBlank + private String password; +} diff --git a/src/main/java/com/example/moreveiw/domain/member/model/dto/request/MemberRequest.java b/src/main/java/com/example/moreveiw/domain/member/model/dto/request/MemberRequest.java new file mode 100644 index 0000000..2ed71af --- /dev/null +++ b/src/main/java/com/example/moreveiw/domain/member/model/dto/request/MemberRequest.java @@ -0,0 +1,22 @@ +package com.example.moreveiw.domain.member.model.dto.request; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class MemberRequest { + @Email + @NotBlank + private String email; + @NotBlank + private String password; + @NotBlank + private String name; +} diff --git a/src/main/java/com/example/moreveiw/domain/member/model/dto/response/MemberListResponse.java b/src/main/java/com/example/moreveiw/domain/member/model/dto/response/MemberListResponse.java new file mode 100644 index 0000000..bab2877 --- /dev/null +++ b/src/main/java/com/example/moreveiw/domain/member/model/dto/response/MemberListResponse.java @@ -0,0 +1,15 @@ +package com.example.moreveiw.domain.member.model.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; + +import java.util.List; + +@Getter +@Builder +@AllArgsConstructor +public class MemberListResponse { + + private List memberList; +} diff --git a/src/main/java/com/example/moreveiw/domain/member/model/dto/response/MemberResponse.java b/src/main/java/com/example/moreveiw/domain/member/model/dto/response/MemberResponse.java new file mode 100644 index 0000000..cd55376 --- /dev/null +++ b/src/main/java/com/example/moreveiw/domain/member/model/dto/response/MemberResponse.java @@ -0,0 +1,19 @@ +package com.example.moreveiw.domain.member.model.dto.response; + +import jakarta.validation.constraints.Email; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; + +import java.util.Set; + +@AllArgsConstructor +@Builder +@Getter +public class MemberResponse { + + private String name; + private String password; + private String email; + private String role; +} diff --git a/src/main/java/com/example/moreveiw/domain/member/repository/MemberRepository.java b/src/main/java/com/example/moreveiw/domain/member/repository/MemberRepository.java index e8957d5..ba4a028 100644 --- a/src/main/java/com/example/moreveiw/domain/member/repository/MemberRepository.java +++ b/src/main/java/com/example/moreveiw/domain/member/repository/MemberRepository.java @@ -1,13 +1,15 @@ package com.example.moreveiw.domain.member.repository; import com.example.moreveiw.domain.member.model.dao.Member; +import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.Optional; + @Repository public interface MemberRepository extends JpaRepository { - Boolean existsByMemberName(String memberName); - - Member findByMemberName(String memberName); + @EntityGraph(attributePaths = "authorities") + Optional findOneWithAuthoritiesByEmail(String email); } diff --git a/src/main/java/com/example/moreveiw/domain/member/service/CustomUserDetailService.java b/src/main/java/com/example/moreveiw/domain/member/service/CustomUserDetailService.java deleted file mode 100644 index 04bcb25..0000000 --- a/src/main/java/com/example/moreveiw/domain/member/service/CustomUserDetailService.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.example.moreveiw.domain.member.service; - -import com.example.moreveiw.domain.member.model.dao.Member; -import com.example.moreveiw.domain.member.repository.MemberRepository; -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 com.example.moreveiw.domain.member.model.dto.CustomUserDetails; - -@Service -@RequiredArgsConstructor -public class CustomUserDetailService implements UserDetailsService { - - private final MemberRepository memberRepository; - - @Override - public UserDetails loadUserByUsername(String memberName) throws UsernameNotFoundException { - - Member memberData = memberRepository.findByMemberName(memberName); - - if (memberData != null) { - - return new CustomUserDetails(memberData); - } - - - return null; - } -} diff --git a/src/main/java/com/example/moreveiw/domain/member/service/CustomUserDetailsService.java b/src/main/java/com/example/moreveiw/domain/member/service/CustomUserDetailsService.java new file mode 100644 index 0000000..5a4c644 --- /dev/null +++ b/src/main/java/com/example/moreveiw/domain/member/service/CustomUserDetailsService.java @@ -0,0 +1,43 @@ +package com.example.moreveiw.domain.member.service; + + +import com.example.moreveiw.domain.member.model.dao.Member; +import com.example.moreveiw.domain.member.repository.MemberRepository; +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.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +@Component("userDetailService") +public class CustomUserDetailsService implements UserDetailsService { + + private final MemberRepository memberRepository; + + public CustomUserDetailsService(MemberRepository memberRepository) { + this.memberRepository = memberRepository; + } + + @Override + @Transactional + public UserDetails loadUserByUsername(final String email) { + return memberRepository.findOneWithAuthoritiesByEmail(email) + .map(member -> createMember(email, member)) + .orElseThrow(() -> new UsernameNotFoundException(email + "데이터베이스에서 찾을 수 없습니다.")); + } + + private org.springframework.security.core.userdetails.User createMember(String email, Member member) { + + List grantedAuthorities = member.getAuthorities().stream() + .map(authority -> new SimpleGrantedAuthority(authority.getAuthorityName())) + .collect(Collectors.toList()); + + return new org.springframework.security.core.userdetails.User(member.getEmail(), member.getPassword() + , grantedAuthorities); + } +} diff --git a/src/main/java/com/example/moreveiw/domain/member/service/JoinService.java b/src/main/java/com/example/moreveiw/domain/member/service/JoinService.java deleted file mode 100644 index 9aa1bd1..0000000 --- a/src/main/java/com/example/moreveiw/domain/member/service/JoinService.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.example.moreveiw.domain.member.service; - -import com.example.moreveiw.domain.member.editor.MemberEditor; -import com.example.moreveiw.domain.member.model.dao.Member; -import com.example.moreveiw.domain.member.model.dto.JoinDto; -import com.example.moreveiw.domain.member.repository.MemberRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class JoinService { - - private final BCryptPasswordEncoder bCryptPasswordEncoder; - private final MemberRepository memberRepository; - - public void joinProcess(JoinDto joinDto) { - - String memberName = joinDto.getMemberName(); - String password = joinDto.getPassword(); - - Boolean isExist = memberRepository.existsByMemberName(memberName); - - if (isExist) { - - return; - } - - MemberEditor memberEditor = MemberEditor.builder() - .memberName(memberName) - .password(bCryptPasswordEncoder.encode(password)) - .role("ROLE_ADMIN") - .build(); - - memberRepository.save(Member.builder().build()); - } -} diff --git a/src/main/java/com/example/moreveiw/domain/member/service/MemberDetailService.java b/src/main/java/com/example/moreveiw/domain/member/service/MemberDetailService.java deleted file mode 100644 index a5df91b..0000000 --- a/src/main/java/com/example/moreveiw/domain/member/service/MemberDetailService.java +++ /dev/null @@ -1,20 +0,0 @@ -//package com.moreview.domain.member.service; -// -//import com.moreview.domain.member.Member; -//import com.moreview.domain.member.repository.MemberRepository; -//import lombok.RequiredArgsConstructor; -//import org.springframework.security.core.userdetails.UserDetailsService; -//import org.springframework.stereotype.Service; -// -//@Service -//@RequiredArgsConstructor -//public class MemberDetailService implements UserDetailsService { -// -// private final MemberRepository memberRepository; -// -// @Override -// public Member loadUserByUsername(String email) { -// return memberRepository.findByEmail(email) -// .orElseThrow(() -> new IllegalArgumentException((email))); -// } -//} diff --git a/src/main/java/com/example/moreveiw/domain/member/service/MemberService.java b/src/main/java/com/example/moreveiw/domain/member/service/MemberService.java index 975d7cb..3e0307e 100644 --- a/src/main/java/com/example/moreveiw/domain/member/service/MemberService.java +++ b/src/main/java/com/example/moreveiw/domain/member/service/MemberService.java @@ -1,34 +1,43 @@ -//package com.moreview.domain.member.service; -// -//import lombok.RequiredArgsConstructor; -//import com.moreview.domain.member.Member; -//import com.moreview.domain.member.dto.request.AddMemberRequest; -//import com.moreview.domain.member.repository.MemberRepository; -//import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -//import org.springframework.stereotype.Service; -// -//@Service -//@RequiredArgsConstructor -//public class MemberService { -// -// private final MemberRepository memberRepository; -// -// public Long save(AddMemberRequest dto) { -// BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); -// -// return memberRepository.save(Member.builder() -// .email(dto.getEmail()) -// .password(encoder.encode(dto.getPassword())) -// .build()).getId(); -// } -// -// public Member findById(Long userId) { -// return memberRepository.findById(userId) -// .orElseThrow(() -> new IllegalArgumentException("Unexpected user")); -// } -// -// public Member findByEmail(String email) { -// return memberRepository.findByEmail(email) -// .orElseThrow(() -> new IllegalArgumentException("Unexpected user")); -// } -//} +package com.example.moreveiw.domain.member.service; + +import com.example.moreveiw.domain.member.exception.DuplicateMemberException; +import com.example.moreveiw.domain.member.exception.NotFoundMemberException; +import com.example.moreveiw.domain.member.model.dao.Member; +import com.example.moreveiw.domain.member.model.dao.MemberMapper; +import com.example.moreveiw.domain.member.model.dto.request.MemberRequest; +import com.example.moreveiw.domain.member.model.dto.response.MemberResponse; +import com.example.moreveiw.domain.member.repository.MemberRepository; +import com.example.moreveiw.global.util.SecurityUtil; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + + +@Service +@RequiredArgsConstructor +public class MemberService { + + private final MemberRepository memberRepository; + private final MemberMapper memberMapper; + + @Transactional + public MemberResponse signup(MemberRequest request) { + if (memberRepository.findOneWithAuthoritiesByEmail(request.getEmail()).orElse(null) != null) { + throw new DuplicateMemberException("이미 가입되어 있는 회원입니다."); + } + + Member member = memberMapper.toEntity(request); + + return memberMapper.toResponse(memberRepository.save(member)); + } + + @Transactional(readOnly = true) + public MemberResponse getMyMemberWithAuthorities() { + return memberMapper.toResponse( + SecurityUtil.getCurrentUsername() + .flatMap(memberRepository::findOneWithAuthoritiesByEmail) + .orElseThrow(() -> new NotFoundMemberException("Member not found")) + ); + } + +} diff --git a/src/main/java/com/example/moreveiw/domain/websocket/handler/WebSocketHandler.java b/src/main/java/com/example/moreveiw/domain/websocket/handler/WebSocketHandler.java index 4701a9d..1ac0a3e 100644 --- a/src/main/java/com/example/moreveiw/domain/websocket/handler/WebSocketHandler.java +++ b/src/main/java/com/example/moreveiw/domain/websocket/handler/WebSocketHandler.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; @@ -14,6 +15,7 @@ @Component @RequiredArgsConstructor @Slf4j +@Primary public class WebSocketHandler extends TextWebSocketHandler { private final ProjectService chatService; diff --git a/src/main/java/com/example/moreveiw/global/config/SecurityConfig.java b/src/main/java/com/example/moreveiw/global/config/SecurityConfig.java index 11bdce4..5caa82c 100644 --- a/src/main/java/com/example/moreveiw/global/config/SecurityConfig.java +++ b/src/main/java/com/example/moreveiw/global/config/SecurityConfig.java @@ -1,78 +1,74 @@ package com.example.moreveiw.global.config; -import com.example.moreveiw.global.security.jwt.JwtFilter; -import com.example.moreveiw.global.security.jwt.LoginFilter; -import com.example.moreveiw.global.util.JwtUtil; +import com.example.moreveiw.global.security.jwt.JwtAccessDeniedHandler; +import com.example.moreveiw.global.security.jwt.JwtAuthenticationEntryPoint; +import com.example.moreveiw.global.security.jwt.JwtSecurityConfig; +import com.example.moreveiw.global.security.jwt.TokenProvider; +import org.springframework.boot.autoconfigure.security.servlet.PathRequest; 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.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.filter.CorsFilter; -@Configuration @EnableWebSecurity +@EnableMethodSecurity +@Configuration public class SecurityConfig { - private final AuthenticationConfiguration authenticationConfiguration; - private final JwtUtil jwtUtil; - - public SecurityConfig(AuthenticationConfiguration authenticationConfiguration, JwtUtil jwtUtil) { - - this.authenticationConfiguration = authenticationConfiguration; - this.jwtUtil = jwtUtil; - } - - @Bean - public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception { - - return configuration.getAuthenticationManager(); + private final TokenProvider tokenProvider; + private final CorsFilter corsFilter; + private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; + private final JwtAccessDeniedHandler jwtAccessDeniedHandler; + + public SecurityConfig(TokenProvider tokenProvider, + CorsFilter corsFilter, + JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint, + JwtAccessDeniedHandler jwtAccessDeniedHandler) { + this.tokenProvider = tokenProvider; + this.corsFilter = corsFilter; + this.jwtAccessDeniedHandler = jwtAccessDeniedHandler; + this.jwtAuthenticationEntryPoint = jwtAuthenticationEntryPoint; } @Bean - public BCryptPasswordEncoder bCryptPasswordEncoder() { - + public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - - //csrf disable http - .csrf((auth) -> auth.disable()); + .csrf(AbstractHttpConfigurer::disable) - //From 로그인 방식 disable - http - .formLogin((auth) -> auth.disable()); - - //http basic 인증 방식 disable - http - .httpBasic((auth) -> auth.disable()); + .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class) + .exceptionHandling(exceptionHandling -> exceptionHandling + .accessDeniedHandler(jwtAccessDeniedHandler) + .authenticationEntryPoint(jwtAuthenticationEntryPoint) + ) + .authorizeHttpRequests(authorizeHttpRequest -> authorizeHttpRequest + .requestMatchers("/api/sign-in", "api/login").permitAll() + .requestMatchers(PathRequest.toH2Console()).permitAll() + .anyRequest().authenticated() + ) - http - .authorizeHttpRequests((auth) -> auth - .requestMatchers("/login", "/", "/join").permitAll() - .requestMatchers("/admin").hasRole("ADMIN") - .anyRequest().authenticated()); - - http - .addFilterBefore(new JwtFilter(jwtUtil), LoginFilter.class); - http - .addFilterAt(new LoginFilter(authenticationManager(authenticationConfiguration), jwtUtil), UsernamePasswordAuthenticationFilter.class); + .sessionManagement(sessionManagement -> sessionManagement + .sessionCreationPolicy(SessionCreationPolicy.STATELESS)) - //세션 설정 - http - .sessionManagement((session) -> session - .sessionCreationPolicy(SessionCreationPolicy.STATELESS)); + .headers(headers -> + headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin) + ) + .with(new JwtSecurityConfig(tokenProvider), customizer -> {}); return http.build(); } - - } diff --git a/src/main/java/com/example/moreveiw/global/config/WebSocketConfig.java b/src/main/java/com/example/moreveiw/global/config/WebSocketConfig.java index 00d9ede..a405aae 100644 --- a/src/main/java/com/example/moreveiw/global/config/WebSocketConfig.java +++ b/src/main/java/com/example/moreveiw/global/config/WebSocketConfig.java @@ -1,8 +1,8 @@ package com.example.moreveiw.global.config; +import com.example.moreveiw.domain.websocket.handler.WebSocketHandler; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Configuration; -import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; diff --git a/src/main/java/com/example/moreveiw/global/security/jwt/JwtAccessDeniedHandler.java b/src/main/java/com/example/moreveiw/global/security/jwt/JwtAccessDeniedHandler.java new file mode 100644 index 0000000..e476fc1 --- /dev/null +++ b/src/main/java/com/example/moreveiw/global/security/jwt/JwtAccessDeniedHandler.java @@ -0,0 +1,20 @@ +package com.example.moreveiw.global.security.jwt; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.stereotype.Component; + +import java.io.IOException; + +@Component +public class JwtAccessDeniedHandler implements AccessDeniedHandler { + + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, + AccessDeniedException accessDeniedException) throws IOException, ServletException { + response.sendError(HttpServletResponse.SC_FORBIDDEN); + } +} diff --git a/src/main/java/com/example/moreveiw/global/security/jwt/JwtAuthenticationEntryPoint.java b/src/main/java/com/example/moreveiw/global/security/jwt/JwtAuthenticationEntryPoint.java new file mode 100644 index 0000000..4c8c0e3 --- /dev/null +++ b/src/main/java/com/example/moreveiw/global/security/jwt/JwtAuthenticationEntryPoint.java @@ -0,0 +1,20 @@ +package com.example.moreveiw.global.security.jwt; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import java.io.IOException; + +@Component +public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, + AuthenticationException authException) throws IOException, ServletException { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED); + } +} diff --git a/src/main/java/com/example/moreveiw/global/security/jwt/JwtFilter.java b/src/main/java/com/example/moreveiw/global/security/jwt/JwtFilter.java index bbba870..1136526 100644 --- a/src/main/java/com/example/moreveiw/global/security/jwt/JwtFilter.java +++ b/src/main/java/com/example/moreveiw/global/security/jwt/JwtFilter.java @@ -1,72 +1,54 @@ package com.example.moreveiw.global.security.jwt; -import com.example.moreveiw.domain.member.model.dto.CustomUserDetails; -import com.example.moreveiw.domain.member.model.dao.Member; -import com.example.moreveiw.domain.member.editor.MemberEditor; -import com.example.moreveiw.global.util.JwtUtil; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.web.filter.OncePerRequestFilter; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.GenericFilterBean; import java.io.IOException; @RequiredArgsConstructor -public class JwtFilter extends OncePerRequestFilter { +public class JwtFilter extends GenericFilterBean { - private final JwtUtil jwtUtil; + private static final Logger logger = LoggerFactory.getLogger(JwtFilter.class); + public static final String AUTHORIZATION_HEADER = "Authorization"; + private TokenProvider tokenProvider; - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - - //request에서 Authorization 헤더를 찾음 - String authorization= request.getHeader("Authorization"); - - //Authorization 헤더 검증 - if (authorization == null || !authorization.startsWith("Bearer ")) { - - System.out.println("token null"); - filterChain.doFilter(request, response); + public JwtFilter(TokenProvider tokenProvider) { + this.tokenProvider = tokenProvider; + } - //조건이 해당되면 메소드 종료 (필수) - return; + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + HttpServletRequest httpServletRequest = (HttpServletRequest) request; + String jwt = resolveToken(httpServletRequest); + String requestURI = httpServletRequest.getRequestURI(); + + if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) { + Authentication authentication = tokenProvider.getAuthentication(jwt); + SecurityContextHolder.getContext().setAuthentication(authentication); + logger.debug("Security Context에 '{}' 인증정보를 저장했습니다, uri: {}", authentication.getName(), requestURI); + } else { + logger.debug("유효한 JWT 토큰이 없습니다."); } - String token = authorization.split(" ")[1]; - - //토큰 소멸 시간 검증 - if (jwtUtil.isExpired(token)) { + chain.doFilter(request, response); + } - System.out.println("token expired"); - filterChain.doFilter(request, response); + private String resolveToken(HttpServletRequest httpServletRequest) { + String bearerToken = httpServletRequest.getHeader(AUTHORIZATION_HEADER); - //조건이 해당되면 메소드 종료 (필수) - return; + if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { + return bearerToken.substring(7); } - - - String memberName = jwtUtil.getMemberName(token); - String role = jwtUtil.getRole(token); - - // MemberEditorBuilder를 사용하여 MemberEditor 객체 생성 - MemberEditor memberEditor = MemberEditor.builder() - .memberName(memberName) - .password("temppassword") - .role(role) - .build(); - - - CustomUserDetails customUserDetails = new CustomUserDetails(Member.builder().build()); - - Authentication authToken = new UsernamePasswordAuthenticationToken(customUserDetails, null, customUserDetails.getAuthorities()); - - SecurityContextHolder.getContext().setAuthentication(authToken); - - filterChain.doFilter(request, response); + return null; } } diff --git a/src/main/java/com/example/moreveiw/global/security/jwt/JwtSecurityConfig.java b/src/main/java/com/example/moreveiw/global/security/jwt/JwtSecurityConfig.java new file mode 100644 index 0000000..82cbf8d --- /dev/null +++ b/src/main/java/com/example/moreveiw/global/security/jwt/JwtSecurityConfig.java @@ -0,0 +1,21 @@ +package com.example.moreveiw.global.security.jwt; + +import lombok.RequiredArgsConstructor; +import org.springframework.security.config.annotation.SecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.web.DefaultSecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +@RequiredArgsConstructor +public class JwtSecurityConfig extends SecurityConfigurerAdapter { + + private final TokenProvider tokenProvider; + + @Override + public void configure(HttpSecurity http){ + http.addFilterBefore( + new JwtFilter(tokenProvider), UsernamePasswordAuthenticationFilter.class + ); + } + +} diff --git a/src/main/java/com/example/moreveiw/global/security/jwt/LoginFilter.java b/src/main/java/com/example/moreveiw/global/security/jwt/LoginFilter.java deleted file mode 100644 index ac152e2..0000000 --- a/src/main/java/com/example/moreveiw/global/security/jwt/LoginFilter.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.example.moreveiw.global.security.jwt; - -import com.example.moreveiw.domain.member.model.dto.CustomUserDetails; -import com.example.moreveiw.global.util.JwtUtil; -import jakarta.servlet.FilterChain; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import lombok.RequiredArgsConstructor; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; - -import java.util.Collection; -import java.util.Iterator; - -@RequiredArgsConstructor -public class LoginFilter extends UsernamePasswordAuthenticationFilter { - - private final AuthenticationManager authenticationManager; - private final JwtUtil jwtUtil; - - @Override - public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { - - String memberName = obtainUsername(request); - String password = obtainPassword(request); - - System.out.println(memberName); - - UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(memberName, password, null); - - return authenticationManager.authenticate(authToken); - } - - @Override - protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) { - - CustomUserDetails customUserDetails = (CustomUserDetails) authentication.getPrincipal(); - - String membername = customUserDetails.getUsername(); - - Collection authorities = authentication.getAuthorities(); - Iterator iterator = authorities.iterator(); - GrantedAuthority auth = iterator.next(); - - String role = auth.getAuthority(); - - - String token = jwtUtil.createJwt(membername, role, 60*60*10L); - - response.addHeader("Authorization", "Bearer " + token); - } - - @Override - protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) { - - response.setStatus(401); - } - -} diff --git a/src/main/java/com/example/moreveiw/global/security/jwt/TokenProvider.java b/src/main/java/com/example/moreveiw/global/security/jwt/TokenProvider.java new file mode 100644 index 0000000..9fe78f3 --- /dev/null +++ b/src/main/java/com/example/moreveiw/global/security/jwt/TokenProvider.java @@ -0,0 +1,94 @@ +package com.example.moreveiw.global.security.jwt; + +import io.jsonwebtoken.*; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.stereotype.Component; + +import java.security.Key; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.stream.Collectors; + +@Component +public class TokenProvider implements InitializingBean { + + private final Logger logger = LoggerFactory.getLogger(TokenProvider.class); + private static final String AUTHORITIES_KEY = "auth"; + private final String secret; + private final long tokenValidityInMilliseconds; + private Key key; + + public TokenProvider( + @Value("${jwt.secret}") String secret, + @Value("${jwt.token-validity-in-seconds}") long tokenValidityInSeconds) { + this.secret = secret; + this.tokenValidityInMilliseconds = tokenValidityInSeconds * 1000; + } + + @Override + public void afterPropertiesSet() { + byte[] keyBytes = Decoders.BASE64.decode(secret); + this.key = Keys.hmacShaKeyFor(keyBytes); + } + + public String createToken(Authentication authentication) { + String authorities = authentication.getAuthorities().stream() + .map(GrantedAuthority::getAuthority) + .collect(Collectors.joining(",")); + + long now = (new Date()).getTime(); + Date validity = new Date(now + this.tokenValidityInMilliseconds); + + return Jwts.builder() + .setSubject(authentication.getName()) + .claim(AUTHORITIES_KEY, authorities) + .signWith(key, SignatureAlgorithm.HS512) + .setExpiration(validity) + .compact(); + } + + public Authentication getAuthentication(String token) { + Claims claims = Jwts + .parserBuilder() + .setSigningKey(key) + .build() + .parseClaimsJws(token) + .getBody(); + + Collection authorities = + Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(",")) + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + + User principal = new User(claims.getSubject(), "", authorities); + + return new UsernamePasswordAuthenticationToken(principal, token, authorities); + } + + public boolean validateToken(String token) { + try { + Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token); + return true; + } catch (io.jsonwebtoken.security.SignatureException | MalformedJwtException e) { + logger.info("잘못된 JWT 서명입니다."); + } catch (ExpiredJwtException e) { + logger.info("만료된 JWT 토큰입니다."); + } catch (UnsupportedJwtException e) { + logger.info("지원되지 않는 JWT 토큰입니다."); + } catch (IllegalArgumentException e) { + logger.info("토큰이 잘못되었습니다."); + } + return false; + } +} diff --git a/src/main/java/com/example/moreveiw/global/util/JwtUtil.java b/src/main/java/com/example/moreveiw/global/util/JwtUtil.java deleted file mode 100644 index 2dcd955..0000000 --- a/src/main/java/com/example/moreveiw/global/util/JwtUtil.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.example.moreveiw.global.util; - -import io.jsonwebtoken.Jwts; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import javax.crypto.SecretKey; -import javax.crypto.spec.SecretKeySpec; -import java.nio.charset.StandardCharsets; -import java.util.Date; - -@Component -public class JwtUtil { - - private SecretKey secretKey; - - public JwtUtil(@Value("${jwt.secret_key}") String secret) { - - this.secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), Jwts.SIG.HS256.key().build().getAlgorithm()); - } - - public String getMemberName(String token) { - - return Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token).getPayload().get("memberName", String.class); - } - - public String getRole(String token) { - - return Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token).getPayload().get("role", String.class); - } - - public Boolean isExpired(String token) { - - return Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token).getPayload().getExpiration().before(new Date()); - } - - public String createJwt(String memberName, String role, Long expiredMs) { - - return Jwts.builder() - .claim("memberName", memberName) - .claim("role", role) - .issuedAt(new Date(System.currentTimeMillis())) - .expiration(new Date(System.currentTimeMillis() + expiredMs)) - .signWith(secretKey) - .compact(); - } -} diff --git a/src/main/java/com/example/moreveiw/global/util/SecurityUtil.java b/src/main/java/com/example/moreveiw/global/util/SecurityUtil.java new file mode 100644 index 0000000..c4f9a22 --- /dev/null +++ b/src/main/java/com/example/moreveiw/global/util/SecurityUtil.java @@ -0,0 +1,38 @@ +package com.example.moreveiw.global.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component +public class SecurityUtil { + + private static final Logger logger = LoggerFactory.getLogger(SecurityUtil.class); + + private SecurityUtil(){} + + public static Optional getCurrentUsername() { + final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + + if (authentication == null || !authentication.isAuthenticated()) { + logger.debug("Security Context에 인증 정보가 없습니다."); + return Optional.empty(); + } + + String email = null; + if (authentication.getPrincipal() instanceof UserDetails) { + UserDetails springSecurity = (UserDetails) authentication.getPrincipal(); + email = springSecurity.getUsername(); + } else if (authentication.getPrincipal() instanceof String) { + email = (String) authentication.getPrincipal(); + } + + String username = authentication.getName(); + return Optional.ofNullable(email); + } +} From 917e47b44e1702e40bbad04a5f4fc22d16c15493 Mon Sep 17 00:00:00 2001 From: jgmoon <6813821@tukorea.ac.kr> Date: Thu, 13 Jun 2024 00:54:18 +0900 Subject: [PATCH 7/7] =?UTF-8?q?fix:=20Bean=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0=20(#10)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../moreveiw/domain/websocket/handler/WebSocketHandler.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/example/moreveiw/domain/websocket/handler/WebSocketHandler.java b/src/main/java/com/example/moreveiw/domain/websocket/handler/WebSocketHandler.java index 1ac0a3e..37dbf24 100644 --- a/src/main/java/com/example/moreveiw/domain/websocket/handler/WebSocketHandler.java +++ b/src/main/java/com/example/moreveiw/domain/websocket/handler/WebSocketHandler.java @@ -15,7 +15,6 @@ @Component @RequiredArgsConstructor @Slf4j -@Primary public class WebSocketHandler extends TextWebSocketHandler { private final ProjectService chatService;