Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[Refactor/#164] Member, Security 개편 #176

Merged
merged 64 commits into from
Nov 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
03b89b4
[refactor/#164] DB 재설계로 인한 member 관련 Entity, VO 매핑 수정
whitem4rk Aug 29, 2023
b5f56ec
[refactor/#164] member VO, entity 코드 형식 개선
whitem4rk Aug 29, 2023
2075659
[refactor/#164] 네이밍 변경으로 인한 호출 코드 변경
whitem4rk Aug 29, 2023
4850970
[refactor/#164] 일부 attribute 네이밍 변경 롤백
whitem4rk Aug 31, 2023
5282222
[refactor/#164] Role 이름 수정
whitem4rk Aug 31, 2023
d0f6376
[refactor/#164] o -> obj로 변경한것 롤백
whitem4rk Sep 4, 2023
3ff43e8
[refactor/#164] Team 관련 코드 삭제
whitem4rk Sep 4, 2023
35c21d0
[refactor/#164] Team 관련 코드 추가 삭제
whitem4rk Sep 4, 2023
8e68eee
[refactor/#164] VO, Entity, Dto 네이밍 변경 및 롤백
whitem4rk Sep 4, 2023
6fbd654
[refactor/#164] Exception 변수이름 수정
whitem4rk Sep 4, 2023
b734bfb
[refactor/#164] Dto 유효성 검증 어노테이션 추가
whitem4rk Sep 4, 2023
f8c274c
[refactor/#164] Role 이름, TestMember 객체 추가 및 수정
whitem4rk Sep 4, 2023
ff2f165
[refactor/#164] Grade 삭제
whitem4rk Sep 4, 2023
8ea2ff8
[refactor/#164] Hierarchy 총무 추가
whitem4rk Sep 5, 2023
4396f04
[refactor/#164] majorInfo VO, entity, DTO 테이블 매핑
whitem4rk Sep 8, 2023
f0f386d
[refactor/#164] social account 부분 매핑 수정
whitem4rk Sep 11, 2023
1bb7351
[refactor/#164] 회원관리 엔드포인트 재설계로 인한 코드 삭제
whitem4rk Sep 14, 2023
f84b192
[refactor/#164] Page 객체로 반환하는 서비스
whitem4rk Sep 19, 2023
4ab59f5
[refactor/#164] Page를 위한 Dto 생성
whitem4rk Sep 20, 2023
3068fd6
[refactor/#164] Page를 위한 Dto 생성
whitem4rk Sep 22, 2023
8ed5578
[refactor/#164] Directory 구조 변경
whitem4rk Sep 24, 2023
4cc5b60
[refactor/#164] Repository 변경
whitem4rk Sep 25, 2023
8b9513c
[refactor/#164] Role 수정
whitem4rk Oct 2, 2023
ccdfac8
[refactor/#164] WebSecurityConfigurerAdapter 수정
whitem4rk Oct 22, 2023
0c0abec
[refactor/#164] swagger config 수정
whitem4rk Oct 23, 2023
093b436
[refactor/#164] swagger config 수정 & JWT 인증기능 추가
whitem4rk Oct 24, 2023
c3c683e
[refactor/#164] jwt token 관련 수정
whitem4rk Oct 26, 2023
49baf9d
[refactor/#164] oauth 인증 관련 수정
whitem4rk Oct 27, 2023
c9e820b
[refactor/#164] oauth 인증 관련 수정
whitem4rk Oct 28, 2023
77d28ce
[refactor/#164] HttpSessionOAuth2AuthorizedClientRepository -> JdbcOA…
whitem4rk Oct 30, 2023
fa6c201
[refactor/#164] WebSecurityConfig 개편
whitem4rk Nov 1, 2023
965479b
[refactor/#164] JWT OncePerRequestFilter -> AbstractAuthenticationPro…
whitem4rk Nov 2, 2023
7967ab5
[refactor/#164] fixed redirect frontend url config
whitem4rk Nov 5, 2023
c2db6eb
[refactor/#164] Token refactor
whitem4rk Nov 7, 2023
a080a59
[refactor/#164] socialaccount deleted
whitem4rk Nov 8, 2023
5606d5e
[refactor/#164] token include memberId
whitem4rk Nov 9, 2023
25c3e8e
[refactor/#164] fix Jwt filter error
whitem4rk Nov 10, 2023
eb13254
[refactor/#164] WebSecurityConfigurerAdapter hasRole이 하나만 동작하는 문제 해결
whitem4rk Nov 11, 2023
7ae7938
[refactor/#164] Security trivial settings
whitem4rk Nov 11, 2023
62c9d67
[refactor/#164] Separate singUp from member
whitem4rk Nov 11, 2023
91fedc3
[refactor/#164] MemberId -> StudentId로 인한 연관 코드 수정. 이후에 id, StudentId…
whitem4rk Nov 12, 2023
d501688
[refactor/#164] Refresh Token 발급 및 security 설정
whitem4rk Nov 13, 2023
f368c0e
[refactor/#164] Refresh Token 발급 및 security 설정
whitem4rk Nov 13, 2023
aeda084
[refactor/#164] Jwt exception handling 수정
whitem4rk Nov 14, 2023
69fc19e
[refactor/#164] Delete trash file
whitem4rk Nov 14, 2023
81d0206
[refactor/#164] Security Test code refactor
whitem4rk Nov 14, 2023
c9707d6
[refactor/#164] MajorInfo Test code refactor
whitem4rk Nov 14, 2023
a6b0878
[refactor/#164] Member VO Test code refactor
whitem4rk Nov 15, 2023
8717f25
[refactor/#164] Data Masking ObjectMapper
whitem4rk Nov 16, 2023
fdc4899
[refactor/#164] Member VO refactor
whitem4rk Nov 17, 2023
bf00617
[refactor/#164] Role 관련 추가사항
whitem4rk Nov 17, 2023
ec90bdb
[refactor/#164] Member Service refactor
whitem4rk Nov 18, 2023
efcd60c
[refactor/#164] Member repository refactor
whitem4rk Nov 18, 2023
8bfa324
[refactor/#164] Member Dto refactor
whitem4rk Nov 18, 2023
d097ebb
[refactor/#164] Member Controller refactor
whitem4rk Nov 20, 2023
cb7438f
[refactor/#164] 전반적인 Member Test code refactor
whitem4rk Nov 21, 2023
e795ce2
[refactor/#164] studentId(PK) -> memberId(인조키), studentId로 인한 연관 test…
whitem4rk Nov 21, 2023
a039c82
[refactor/#164] auth 관련 trivial 수정
whitem4rk Nov 21, 2023
109a71e
[refactor/#164] 기존코드 변경으로 인한 Test code 임시 주석 처리
whitem4rk Nov 22, 2023
8c22cc6
[refactor/#164] Member table에 grade column추가 및 수정
whitem4rk Nov 22, 2023
a2fcfa9
[refactor/#164] CAMELCASE 통일
whitem4rk Nov 24, 2023
585f0c8
[refactor/#164] config 파일 에러로 인한 수정
whitem4rk Nov 24, 2023
a759dc2
[refactor/#164] Merge 이전 코드충돌 해결
whitem4rk Nov 25, 2023
820327b
[refactor/#164] gradle 코드 오류 수정
whitem4rk Nov 25, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
**/application.pid
HELP.md
.gradle
build/
Expand Down
7 changes: 5 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ subprojects {
'org.springframework.boot:spring-boot-starter-web',
'org.springframework.boot:spring-boot-starter-validation',
'org.springdoc:springdoc-openapi-ui:1.6.0',
'com.google.code.findbugs:jsr305:3.0.2',

// cloud config
'org.springframework.cloud:spring-cloud-starter-config:3.1.0',
Expand All @@ -54,6 +55,7 @@ subprojects {
)
testImplementation 'org.springframework.boot:spring-boot-starter-test'

developmentOnly "org.springframework.boot:spring-boot-devtools"
compileOnly 'org.projectlombok:lombok'


Expand All @@ -78,7 +80,8 @@ project(':module-jpa') {
'org.springframework.boot:spring-boot-starter-data-jpa',
'com.querydsl:querydsl-jpa', // query dsl
'com.jcraft:jsch:0.1.55', // 로컬 개발용 db ssh tunneling, https://mavenlibs.com/maven/dependency/com.jcraft/jsch
'org.mariadb.jdbc:mariadb-java-client',
// 'org.mariadb.jdbc:mariadb-java-client',
'mysql:mysql-connector-java',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기존 사용 db인 mariadb로 변경 필요

'com.h2database:h2'
)
}
Expand All @@ -90,7 +93,6 @@ project(':module-auth') {

dependencies {
api project(':module-jpa')

// jwt
api 'io.jsonwebtoken:jjwt-api:0.11.2'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.2',
Expand All @@ -101,6 +103,7 @@ project(':module-auth') {
// security
api 'org.springframework.boot:spring-boot-starter-security'
api 'org.springframework.boot:spring-boot-starter-oauth2-client'
api 'org.springframework.security:spring-security-core:5.1.6.RELEASE'
api 'javax.xml.bind:jaxb-api'
testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'org.mockito:mockito-inline:2.13.0'
Expand Down
49 changes: 18 additions & 31 deletions module-auth/src/main/java/com/inhabas/api/auth/AuthBeansConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,45 +5,45 @@
import com.inhabas.api.auth.domain.oauth2.handler.Oauth2AuthenticationSuccessHandler;
import com.inhabas.api.auth.domain.oauth2.userAuthorityProvider.DefaultUserAuthorityProvider;
import com.inhabas.api.auth.domain.oauth2.userAuthorityProvider.UserAuthorityProvider;
import com.inhabas.api.auth.domain.token.TokenProvider;
import com.inhabas.api.auth.domain.token.TokenUtil;
import com.inhabas.api.auth.domain.token.TokenReIssuer;
import com.inhabas.api.auth.domain.token.TokenResolver;
import com.inhabas.api.auth.domain.token.jwtUtils.JwtTokenProvider;
import com.inhabas.api.auth.domain.token.jwtUtils.JwtTokenUtil;
import com.inhabas.api.auth.domain.token.jwtUtils.JwtTokenReIssuer;
import com.inhabas.api.auth.domain.token.jwtUtils.JwtTokenResolver;
import com.inhabas.api.auth.domain.token.jwtUtils.refreshToken.RefreshTokenRepository;
import com.inhabas.api.auth.domain.token.securityFilter.DefaultUserPrincipalService;
import com.inhabas.api.auth.domain.token.securityFilter.InvalidJwtTokenHandler;
import com.inhabas.api.auth.domain.token.securityFilter.TokenAuthenticationFailureHandler;
import com.inhabas.api.auth.domain.token.securityFilter.TokenAuthenticationProcessingFilter;
import com.inhabas.api.auth.domain.token.securityFilter.UserPrincipalService;
import io.jsonwebtoken.Jwt;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.web.HttpSessionOAuth2AuthorizedClientRepository;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.oauth2.client.JdbcOAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;

import javax.sql.DataSource;

@Configuration
@RequiredArgsConstructor
public class AuthBeansConfig {

private final JwtTokenUtil jwtTokenUtil;
private final AuthProperties authProperties;
private final RefreshTokenRepository refreshTokenRepository;

@Bean
public HttpCookieOAuth2AuthorizationRequestRepository httpCookieOAuth2AuthorizationRequestRepository() {
return new HttpCookieOAuth2AuthorizationRequestRepository();
}

@Bean
public TokenProvider tokenProvider(RefreshTokenRepository refreshTokenRepository) {
return new JwtTokenProvider(refreshTokenRepository);
}

@Bean
public Oauth2AuthenticationSuccessHandler oauth2AuthenticationSuccessHandler(RefreshTokenRepository refreshTokenRepository) {
return new Oauth2AuthenticationSuccessHandler(
this.tokenProvider(refreshTokenRepository), this.authProperties, this.httpCookieOAuth2AuthorizationRequestRepository());
jwtTokenUtil, this.authProperties, this.httpCookieOAuth2AuthorizationRequestRepository());
}

@Bean
Expand All @@ -58,40 +58,27 @@ public UserAuthorityProvider userAuthorityService() {
}

@Bean
public OAuth2AuthorizedClientRepository oAuth2AuthorizedClientRepository() {
return new HttpSessionOAuth2AuthorizedClientRepository();
public OAuth2AuthorizedClientService authorizedClientService(
DataSource dataSource, ClientRegistrationRepository clientRegistrationRepository) {
return new JdbcOAuth2AuthorizedClientService(new JdbcTemplate(dataSource), clientRegistrationRepository);
}

@ConditionalOnMissingBean
public UserPrincipalService userPrincipalService() {
return new DefaultUserPrincipalService();
}

@Bean
public TokenAuthenticationFailureHandler tokenAuthenticationFailureHandler() {
return new InvalidJwtTokenHandler();
}

@Bean
public TokenResolver tokenResolver() {
return new JwtTokenResolver();
}

@Bean
public TokenAuthenticationProcessingFilter tokenAuthenticationProcessingFilter(
TokenProvider tokenProvider,
TokenResolver tokenResolver,
TokenAuthenticationFailureHandler failureHandler,
UserPrincipalService userPrincipalService
) {
return new TokenAuthenticationProcessingFilter(tokenProvider, tokenResolver, failureHandler,
userPrincipalService);
}

@Bean
public TokenReIssuer tokenReIssuer(TokenProvider tokenProvider, TokenResolver tokenResolver,
RefreshTokenRepository refreshTokenRepository) {
return new JwtTokenReIssuer(tokenProvider, tokenResolver, refreshTokenRepository);
public TokenReIssuer tokenReIssuer(TokenUtil tokenUtil, TokenResolver tokenResolver,
RefreshTokenRepository refreshTokenRepository) {
return new JwtTokenReIssuer(tokenUtil, tokenResolver, refreshTokenRepository);
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.inhabas.api.auth;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.web.cors.CorsUtils;

@Order(0) // 인증 관련 security filter chain 은 우선순위가 가장 높아야 함.
Expand All @@ -20,6 +21,7 @@
public class AuthSecurityConfig extends WebSecurityConfigurerAdapter {

private final CustomOAuth2UserService customOAuth2UserService;
private final OAuth2AuthorizedClientService authorizedClientService;
private final Oauth2AuthenticationSuccessHandler oauth2AuthenticationSuccessHandler;
private final Oauth2AuthenticationFailureHandler oauth2AuthenticationFailureHandler;
private final HttpCookieOAuth2AuthorizationRequestRepository httpCookieOAuth2AuthorizationRequestRepository;
Expand Down Expand Up @@ -51,29 +53,35 @@ public class AuthSecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {

http
.antMatcher("/login/**")
.requestMatchers().antMatchers("/login/**")
.and()
// 세션 생성 금지
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.cors().and()
.and()
.cors()
.and()
.authorizeRequests()
.antMatchers("/login/refresh").permitAll()
.and()
.csrf().and()
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.anyRequest().permitAll()
.and()
.csrf().disable()

// Oauth 로그인 설정
.oauth2Login()
.authorizedClientService(authorizedClientService)
.authorizationEndpoint()
.baseUri("/login/oauth2/authorization")
.authorizationRequestRepository(httpCookieOAuth2AuthorizationRequestRepository)
.and()
.userInfoEndpoint()
.userService(customOAuth2UserService)
.and()
.failureHandler(oauth2AuthenticationFailureHandler)
.successHandler(oauth2AuthenticationSuccessHandler)
.and()
.authorizeRequests()
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.anyRequest().permitAll();
.and()

// 사용자 정보를 가져오는 엔드포인트에 대한 설정
.userInfoEndpoint()
.userService(customOAuth2UserService)
.and()
.failureHandler(oauth2AuthenticationFailureHandler)
.successHandler(oauth2AuthenticationSuccessHandler);

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public interface AuthExceptionCodes {
/**
* {@code user_not_found} - request 에 담긴 토큰정보를 사용해 기존 사용자 정보를 조회하였으나, 존재하지 않는 경우 발생.
* 또는 최초 소셜로그인 시도하였으나 가입한 회원이 아니라면 해당 오류 발생
* @see com.inhabas.api.auth.domain.token.securityFilter.TokenAuthenticationProcessingFilter
* @see com.inhabas.api.auth.domain.token.securityFilter;
*/
String USER_NOT_FOUND = "user_not_found";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.inhabas.api.auth.domain.oauth2;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;

import java.util.Collection;
import java.util.Map;

public class CustomOAuth2User extends DefaultOAuth2User {

private Long memberId;

public CustomOAuth2User(Collection<? extends GrantedAuthority> authorities,
Map<String, Object> attributes,
String nameAttributeKey,
Long memberId) {
super(authorities, attributes, nameAttributeKey);
this.memberId = memberId;
}

public Long getMemberId() {
return memberId;
}

public void setMemberId(Long memberId) {
this.memberId = memberId;
}

}
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
package com.inhabas.api.auth.domain.oauth2;

import com.inhabas.api.auth.domain.exception.InvalidUserInfoException;
import com.inhabas.api.auth.domain.oauth2.userAuthorityProvider.UserAuthorityProvider;
import com.inhabas.api.auth.domain.oauth2.member.domain.entity.Member;
import com.inhabas.api.auth.domain.oauth2.socialAccount.SocialAccountService;
import com.inhabas.api.auth.domain.oauth2.socialAccount.type.UID;
import com.inhabas.api.auth.domain.oauth2.userAuthorityProvider.UserAuthorityProvider;
import com.inhabas.api.auth.domain.oauth2.userInfo.OAuth2UserInfo;
import com.inhabas.api.auth.domain.oauth2.userInfo.OAuth2UserInfoFactory;
import com.inhabas.api.auth.domain.oauth2.member.domain.service.MemberService;
import com.inhabas.api.auth.domain.oauth2.member.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.OAuth2Error;
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Component;
Expand All @@ -22,6 +27,8 @@ public class CustomOAuth2UserService extends DefaultOAuth2UserService {

private final SocialAccountService socialAccountService;
private final UserAuthorityProvider userAuthorityProvider;
private final MemberService memberService;
private final MemberRepository memberRepository;

@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
Expand All @@ -35,14 +42,17 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic
throw new InvalidUserInfoException();
}
// db 에 소셜 계정 정보 update
socialAccountService.updateSocialAccountInfo(oAuth2UserInfo);
memberService.updateSocialAccountInfo(oAuth2UserInfo);
Member member = memberRepository.findByProviderAndUid(
oAuth2UserInfo.getProvider(), new UID(oAuth2UserInfo.getId()))
.orElseThrow(() -> new OAuth2AuthenticationException(new OAuth2Error("user_not_found")));


// 현재 로그인하려는 유저에 맞는 권한을 들고옴.
Collection<SimpleGrantedAuthority> authorities = userAuthorityProvider.determineAuthorities(oAuth2UserInfo);

String nameAttributeKey = userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint()
.getUserNameAttributeName();

return new DefaultOAuth2User(authorities, oAuth2UserInfo.getAttributes(), nameAttributeKey);
return new CustomOAuth2User(authorities, oAuth2UserInfo.getAttributes(), nameAttributeKey, member.getId());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
Expand All @@ -27,7 +28,7 @@ public void onAuthenticationFailure(HttpServletRequest request, HttpServletRespo

String redirectUri = CookieUtils.resolveCookie(request, REDIRECT_URL_PARAM_COOKIE_NAME)
.map(Cookie::getValue)
.orElse(null);
.orElse("");

String targetUrl = getAuthorizedTargetUrl(exception, redirectUri);

Expand All @@ -39,7 +40,7 @@ public void onAuthenticationFailure(HttpServletRequest request, HttpServletRespo
private String getAuthorizedTargetUrl(AuthenticationException exception, String redirectUri) {

StringBuilder targetUrl = new StringBuilder();
if (exception instanceof UnauthorizedRedirectUrlException || redirectUri.isBlank() || notAuthorized(redirectUri)) {
if (exception instanceof UnauthorizedRedirectUrlException || StringUtils.isBlank(redirectUri) || notAuthorized(redirectUri)) {
targetUrl.append(authProperties.getOauth2().getDefaultRedirectUri());
}
else {
Expand Down
Loading
Loading