Skip to content

Commit

Permalink
Merge pull request #137 from JNU-econovation/fix_social_login
Browse files Browse the repository at this point in the history
[FIX] spring security 관련 로직 수정
  • Loading branch information
inferior3x authored Jan 5, 2025
2 parents b7605d6 + 513eeb8 commit 58dc4d9
Show file tree
Hide file tree
Showing 24 changed files with 134 additions and 196 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package com.whoz_in.main_api.config.security.oauth2;
package com.whoz_in.main_api.config.security;

import com.whoz_in.domain.member.model.MemberId;
import java.util.Collection;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;

//SecurityContextHolder에 저장할 인증 객체로, jwt(AccessToken)로 만들어진다.
@RequiredArgsConstructor
public class JwtAuthentication implements Authentication {
private final MemberId memberId;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.whoz_in.main_api.config.security.oauth2;
package com.whoz_in.main_api.config.security;


import static com.whoz_in.main_api.config.security.consts.JwtConst.AUTHORIZATION;
import static com.whoz_in.main_api.shared.jwt.JwtConst.AUTHORIZATION;

import com.whoz_in.main_api.shared.jwt.tokens.AccessToken;
import com.whoz_in.main_api.shared.jwt.tokens.AccessTokenSerializer;
Expand All @@ -14,8 +14,11 @@
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

//요청에서 jwt를 꺼내어 인증정보를 만들고 SecurityContextHolder에 넣는 필터
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final AccessTokenSerializer accessTokenSerializer;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,37 @@
package com.whoz_in.main_api.config.security;

import com.whoz_in.main_api.config.security.oauth2.ClientRegistrationRepositoryFactory;
import com.whoz_in.main_api.config.security.oauth2.CustomOAuth2UserService;
import com.whoz_in.main_api.config.security.oauth2.LoginFailureHandler;
import com.whoz_in.main_api.config.security.oauth2.LoginSuccessHandler;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.LogoutFilter;

@Configuration
@RequiredArgsConstructor
public class SecurityConfig {

private final CustomOAuth2UserService customOAuth2UserService;
private final ClientRegistrationRepositoryFactory clientRegistrationRepositoryFactory;
private final ClientRegistrationRepository clientRegistrationRepository;
private final LoginSuccessHandler loginSuccessHandler;
private final LoginFailureHandler loginFailureHandler;
private final JwtAuthenticationFilter jwtAuthenticationFilter;

@Bean
@Order(0)
@Order(1)
public SecurityFilterChain oauth2FilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity.securityMatcher(
"/login", //TODO: 운용에선 제거
"/oauth2/authorization/*",
"/login/oauth2/code/*"
"/login", //시큐리티 기본 로그인 페이지
"/oauth2/authorization/*", //소셜 로그인 페이지 (OAuth2LoginConfigurer에서 자동 생성)
"/login/oauth2/code/*" //redirect uri
);

commonConfigurations(httpSecurity);
Expand All @@ -38,8 +40,7 @@ public SecurityFilterChain oauth2FilterChain(HttpSecurity httpSecurity) throws E
httpSecurity.logout(AbstractHttpConfigurer::disable);
httpSecurity.oauth2Login(oauth2->
oauth2
//.loginPage(null) //TODO: 운영에선 추가
.clientRegistrationRepository(clientRegistrationRepositoryFactory.create())
.clientRegistrationRepository(clientRegistrationRepository)
.userInfoEndpoint(config -> config.userService(customOAuth2UserService))
.successHandler(loginSuccessHandler)
.failureHandler(loginFailureHandler)
Expand All @@ -48,6 +49,34 @@ public SecurityFilterChain oauth2FilterChain(HttpSecurity httpSecurity) throws E
return httpSecurity.build();
}

//인증이 필요하거나 인증 여부에 따라 다른 동작을 하는 메서드
//로그아웃, 게시글 작성 등
@Bean
@Order(3)
public SecurityFilterChain authenticationFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity.securityMatcher(
"/**"
);
httpSecurity.authorizeHttpRequests(auth-> {
//인증 필요
auth.requestMatchers(HttpMethod.POST,
"/api/v1/device"
).authenticated();
//인증 여부에 따라 다른 동작
// auth.requestMatchers(
// ).permitAll();
auth.anyRequest().denyAll();
});

commonConfigurations(httpSecurity);

httpSecurity.csrf(AbstractHttpConfigurer::disable);
httpSecurity.addFilterAt(jwtAuthenticationFilter, LogoutFilter.class);
//TODO: 로그아웃 추가

return httpSecurity.build();
}

private void commonConfigurations(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf(AbstractHttpConfigurer::disable);
httpSecurity.httpBasic(AbstractHttpConfigurer::disable);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.whoz_in.main_api.config.security;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SecurityFilterConfig {

// Filter를 구현한 클래스가 빈으로 등록되면 전역 필터로 동작하기 때문에 모든 요청에 대해 jwt 검증을 수행하게 됩니다.
// 따라서 필요한 경우에만 jwt 필터를 사용할 수 있도록 FilterRegistrationBean을 사용하여 전역 필터에서 제외합니다.
@Bean
public FilterRegistrationBean<JwtAuthenticationFilter> jwtAuthenticationFilterRegistration(
JwtAuthenticationFilter jwtAuthenticationFilter) {
FilterRegistrationBean<JwtAuthenticationFilter> registrationBean = new FilterRegistrationBean<>(jwtAuthenticationFilter);
registrationBean.setEnabled(false);
return registrationBean;
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
package com.whoz_in.main_api.config.security.oauth2;

import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
import org.springframework.stereotype.Component;

@Component
@Configuration
@RequiredArgsConstructor
public class ClientRegistrationRepositoryFactory {

public class ClientRegistrationRepositoryConfig {
private final ClientRegistrations clientRegistrations;

public ClientRegistrationRepository create(){
@Bean
public ClientRegistrationRepository clientRegistrationRepository(){
return new InMemoryClientRegistrationRepository(
clientRegistrations.kakaoClientRegistration()
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
public class ClientRegistrations {

@Value("${oauth.kakao.secret}")
private String KAKAO_SECRET;
private String kakaoSecret;

@Value("${oauth.kakao.clientId}")
private String KAKAO_CLIENT_ID;
private String kakaoClientId;

@Value("${oauth.redirectUri}")
private String redirectUri;
Expand All @@ -23,11 +23,11 @@ public ClientRegistration kakaoClientRegistration() {
String providerName = SocialProvider.KAKAO.getProviderName();

return ClientRegistration.withRegistrationId(providerName)
.clientId(KAKAO_CLIENT_ID)
.clientSecret(KAKAO_SECRET)
.clientId(kakaoClientId)
.clientSecret(kakaoSecret)
.redirectUri(redirectUri)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.scope("account_email", "profile_nickname", "profile_image")
.scope("profile_image")
.authorizationUri("https://kauth.kakao.com/oauth/authorize")
.tokenUri("https://kauth.kakao.com/oauth/token")
.userInfoUri("https://kapi.kakao.com/v2/user/me")
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.whoz_in.domain.member.MemberRepository;
import com.whoz_in.domain.member.model.SocialProvider;
import com.whoz_in.domain.shared.event.EventBus;
import com.whoz_in.main_api.config.security.oauth2.response.ProviderResponse;
import com.whoz_in.main_api.config.security.oauth2.response.ProviderResponseFactory;
import lombok.RequiredArgsConstructor;
Expand All @@ -11,30 +12,26 @@
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@RequiredArgsConstructor
@Component
public class CustomOAuth2UserService extends DefaultOAuth2UserService {

// TODO: QueryHandler 나 다른 객체로 변경
private final MemberRepository memberRepository;
private final ApplicationEventPublisher eventPublisher;

@Transactional(readOnly = true)
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
//소셜 프로바이더로부터 받은 액세스 토큰을 이용하여 사용자 정보를 가져오도록 구현되어있다.
OAuth2User oAuth2User = super.loadUser(userRequest);

//우리 프로젝트에서 필요한 정보로 재구성하여 반환하도록 한다.
String providerName = userRequest.getClientRegistration().getRegistrationId();
SocialProvider socialProvider = SocialProvider.findSocialProvider(providerName);
ProviderResponse providerResponse = ProviderResponseFactory.create(socialProvider, oAuth2User.getAttributes());
String socialId = providerResponse.getSocialId();
String email = providerResponse.getEmail(); // TODO: email 받아오지 않기
String name = providerResponse.getName();
boolean registered = memberRepository.existsBySocialProviderAndSocialId(socialProvider, socialId);
// TODO: 일반 회원가입으로 등록이 되었을 경우에, 카카오 로그인을 시도하면 socialProvider 정보와 socialId 값을 저장해야 함
// 카카오톡으로부터 사용자의 실명을 가져오면?

return new OAuth2UserInfo(registered, socialProvider, socialId, name);
return new OAuth2UserInfo(registered, socialProvider, socialId);
}

}
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
package com.whoz_in.main_api.config.security.oauth2;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.stereotype.Component;

//사용자가 소셜 로그인에 실패했을 경우 처리하는 핸들러
@Component
public class LoginFailureHandler extends SimpleUrlAuthenticationFailureHandler {

@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
AuthenticationException exception) throws IOException {

exception.printStackTrace();
response.sendRedirect("/login"); //TODO: Static
Expand Down
Loading

0 comments on commit 58dc4d9

Please sign in to comment.