social login 처리

dev
minuk926 3 years ago
parent 443c77d363
commit ce71941d2f

@ -22,7 +22,7 @@ import javax.annotation.Nonnull;
@Tag(name = "CmmCodeMgtController", description = "코드 관리") @Tag(name = "CmmCodeMgtController", description = "코드 관리")
@RestController @RestController
@RequiredArgsConstructor @RequiredArgsConstructor
@RequestMapping("/api/biz/cmm/code") @RequestMapping("/api/biz/cmm/callback")
public class CmmCodeMgtController { public class CmmCodeMgtController {
private final ICmmCodeService cmmCodeService; private final ICmmCodeService cmmCodeService;

@ -19,8 +19,10 @@ import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds; import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@ -66,6 +68,12 @@ import java.util.Arrays;
* </pre> * </pre>
*/ */
@Configuration @Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
securedEnabled = true,
jsr250Enabled = true,
prePostEnabled = true
)
@RequiredArgsConstructor @RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter { public class SecurityConfig extends WebSecurityConfigurerAdapter {
@ -152,28 +160,43 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override @Override
protected void configure(HttpSecurity http) throws Exception { protected void configure(HttpSecurity http) throws Exception {
http http
// Rest API이므로 기본설정 안함 - 기본 설정은 비인증시 로그인 폼으로 direct .cors()
.httpBasic().disable() .and()
// Rest API 이므로 csrf 보안 불필요
.csrf().disable()
// jwt token 인증 - 세션은 필요 없어 생성 안함 // jwt token 인증 - 세션은 필요 없어 생성 안함
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and() .and()
.cors() // Rest API 이므로 csrf 보안 불필요
.csrf()
.disable()
.formLogin()
.disable()
// Rest API이므로 기본설정 안함 - 기본 설정은 비인증시 로그인 폼으로 direct
.httpBasic()
.disable()
.exceptionHandling()
.authenticationEntryPoint(new RestAuthenticationEntryPoint())
.accessDeniedHandler(tokenAccessDeniedHandler)
.and() .and()
.authorizeRequests() .authorizeRequests()
// GET, POST 요청시 : OPTIONS preflight 요청 - 실제 서버가 살아있는지를 사전에 확인하는 요청 // GET, POST 요청시 : OPTIONS preflight 요청 - 실제 서버가 살아있는지를 사전에 확인하는 요청
// Spring에서 OPTIONS에 대한 요청을 막고 있어 OPTIONS 요청이 왔을 때도 오류를 리턴하지 않도록 설정 // Spring에서 OPTIONS에 대한 요청을 막고 있어 OPTIONS 요청이 왔을 때도 오류를 리턴하지 않도록 설정
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll() .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.antMatchers("/**/signup", "/**/login", "/**/swagger-ui.html").permitAll() .antMatchers(
.antMatchers(HttpMethod.GET, "/**/users/**").permitAll() "/",
.anyRequest().permitAll() //.hasRole(RoleType.USER.getCode()) "/favicon.ico",
"/**/*.png",
"/**/*.gif",
"/**/*.svg",
"/**/*.jpg",
"/**/*.html",
"/**/*.css",
"/**/*.js").permitAll()
.antMatchers("/auth/**", "/oauth2/**", "/**/users/**").permitAll()
.anyRequest().authenticated()
.and() .and()
.exceptionHandling() //.anyRequest().permitAll() //.hasRole(RoleType.USER.getCode())
.authenticationEntryPoint(new RestAuthenticationEntryPoint())
.accessDeniedHandler(tokenAccessDeniedHandler)
// .and() // .and()
// .logout() // .logout()
@ -182,7 +205,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
// .invalidateHttpSession(true) // .invalidateHttpSession(true)
.and()
.oauth2Login() .oauth2Login()
.authorizationEndpoint() .authorizationEndpoint()
.baseUri("/oauth2/authorization") .baseUri("/oauth2/authorization")
@ -191,15 +214,9 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
.and() .and()
.userInfoEndpoint() .userInfoEndpoint()
.userService(customOAuth2UserService) .userService(customOAuth2UserService)
.and()
.redirectionEndpoint()
.baseUri("/*/oauth2/code/*")
.and() .and()
.successHandler(oAuth2AuthenticationSuccessHandler()) .successHandler(oAuth2AuthenticationSuccessHandler())
.failureHandler(oAuth2AuthenticationFailureHandler()) .failureHandler(oAuth2AuthenticationFailureHandler())
.and() .and()
// jwt token filter를 id / password 인증 필터 전에 넣는다 // jwt token filter를 id / password 인증 필터 전에 넣는다
.addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); .addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

@ -25,6 +25,7 @@ import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@ -162,6 +163,23 @@ public class WebCommonConfig extends AsyncConfigurerSupport implements WebMvcCon
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// /**
// * CORS 설정
// * TODO :: SecurityConfig#corsConfigurationSource 설정이 안돼는 경우 적용
// * @param registry CorsRegistry
// *
// * @see SecurityConfig#corsConfigurationSource()
// */
// @Override
// public void addCorsMappings(CorsRegistry registry) {
// registry.addMapping("/**")
// .allowedOrigins("")
// .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")
// .allowedHeaders("*")
// .allowCredentials(true)
// .maxAge(3600);
// }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// yaml type Message loading // yaml type Message loading
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

@ -104,7 +104,7 @@ public class AuthService implements IAuthService {
.orElse(null); .orElse(null);
// 저장된 refresh token not exists // 저장된 refresh token not exists
if (Checks.isNull(savedRefreshToken)) { if (Checks.isNull(savedRefreshToken) || Checks.isNull(savedRefreshToken.getValue())) {
// 없는 경우 새로 등록 // 없는 경우 새로 등록
tokenDto = jwtTokenProvider.generateTokenDto(authentication, infoMap); tokenDto = jwtTokenProvider.generateTokenDto(authentication, infoMap);
refreshTokenRepository.saveAndFlush( refreshTokenRepository.saveAndFlush(

@ -43,10 +43,10 @@ public class OAuth2AuthorizationRequestBasedOnCookieRepository implements Author
return this.loadAuthorizationRequest(request); return this.loadAuthorizationRequest(request);
} }
@Override // @Override
public OAuth2AuthorizationRequest removeAuthorizationRequest(HttpServletRequest request, HttpServletResponse response) { // public OAuth2AuthorizationRequest removeAuthorizationRequest(HttpServletRequest request, HttpServletResponse response) {
return this.loadAuthorizationRequest(request); // return this.loadAuthorizationRequest(request);
} // }
public void removeAuthorizationRequestCookies(HttpServletRequest request, HttpServletResponse response) { public void removeAuthorizationRequestCookies(HttpServletRequest request, HttpServletResponse response) {
CookieUtil.deleteCookie(request, response, OAUTH2_AUTHORIZATION_REQUEST_COOKIE_NAME); CookieUtil.deleteCookie(request, response, OAUTH2_AUTHORIZATION_REQUEST_COOKIE_NAME);

@ -4,23 +4,29 @@ spring:
client: client:
registration: registration:
google: google:
client-id: 259821403087-talgepagvnahurp0bfnk55pujrdaec7q clientId: 259821403087-talgepagvnahurp0bfnk55pujrdaec7q
client-secret: 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 clientSecret: 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
#clientId: 5014057553-8gm9um6vnli3cle5rgigcdjpdrid14m9.apps.googleusercontent.com
#clientSecret: tWZKVLxaD_ARWsriiiUFYoIk
redirectUri: "{baseUrl}/oauth2/callback/{registrationId}"
scope: scope:
- profile - profile
- email - email
facebook: facebook:
clientId: 652436969254286 #clientId: 652436969254286
clientSecret: 822069e9cd00654574d16a88cf3a4be9 #clientSecret: 822069e9cd00654574d16a88cf3a4be9
clientId: 121189305185277
clientSecret: 42ffe5aa7379e8326387e0fe16f34132
redirectUri: "{baseUrl}/oauth2/callback/{registrationId}"
scope: scope:
- email - email
- public_profile - public_profile
kakao: kakao:
clientId: 1d0012ecc1e9d454a69b3a850c546879 clientId: 1d0012ecc1e9d454a69b3a850c546879
clientSecret: bfctm9QldllT81f2UK7L0Cc5QDcDfsYb clientSecret: bfctm9QldllT81f2UK7L0Cc5QDcDfsYb
redirectUri: "{baseUrl}/oauth2/callback/{registrationId}"
clientAuthenticationMethod: post clientAuthenticationMethod: post
authorizationGrantType: authorization_code authorizationGrantType: authorization_code
redirectUri: http://localhost:8090/oauth2/code/kakao
scope: scope:
- profile_nickname - profile_nickname
- profile_image - profile_image
@ -29,14 +35,21 @@ spring:
naver: naver:
clientId: '{네이버 client-id}' clientId: '{네이버 client-id}'
clientSecret: '{네이버 client-secret}' clientSecret: '{네이버 client-secret}'
redirectUri: "{baseUrl}/oauth2/callback/{registrationId}"
clientAuthenticationMethod: post clientAuthenticationMethod: post
authorizationGrantType: authorization_code authorizationGrantType: authorization_code
redirectUri: http://localhost:8090/oauth2/code/naver
scope: scope:
- nickname - nickname
- email - email
- profile_image - profile_image
clientName: Naver clientName: Naver
github:
clientId: d3e47fc2ddd966fa4352
clientSecret: 3bc0f6b8332f93076354c2a5bada2f5a05aea60d
redirectUri: "{baseUrl}/oauth2/callback/{registrationId}"
scope:
- user:email
- read:user
provider: provider:
kakao: kakao:
authorizationUri: https://kauth.kakao.com/oauth/authorize authorizationUri: https://kauth.kakao.com/oauth/authorize
@ -48,10 +61,14 @@ spring:
tokenUri: https://nid.naver.com/oauth2.0/token tokenUri: https://nid.naver.com/oauth2.0/token
userInfoUri: https://openapi.naver.com/v1/nid/me userInfoUri: https://openapi.naver.com/v1/nid/me
userNameAttribute: response userNameAttribute: response
facebook:
authorizationUri: https://www.facebook.com/v3.0/dialog/oauth
tokenUri: https://graph.facebook.com/v3.0/oauth/access_token
userInfoUri: https://graph.facebook.com/v3.0/me?fields=id,first_name,middle_name,last_name,name,email,verified,is_verified,picture.width(250).height(250)
# Spring Security cors 설정 :: CorsConfiguration 설정 값 # Spring Security cors 설정 :: CorsConfiguration 설정 값
cors: cors:
allowed-origins: 'http://localhost:3000' allowed-origins: http://localhost:3000,http://localhost:8090
allowed-methods: GET,POST,PUT,DELETE,OPTIONS allowed-methods: GET,POST,PUT,DELETE,OPTIONS
allowed-headers: '*' allowed-headers: '*'
max-age: 3600 max-age: 3600
@ -89,5 +106,11 @@ xit:
# day # day
refreshTokenExpiry: 7 refreshTokenExpiry: 7
oauth2: oauth2:
# After successfully authenticating with the OAuth2 Provider,
# we'll be generating an auth token for the user and sending the token to the
# redirectUri mentioned by the client in the /oauth2/authorize request.
# We're not using cookies because they won't work well in mobile clients.
authorizedRedirectUris: authorizedRedirectUris:
- http://localhost:3000/oauth/redirect - http://localhost:3000/oauth2/redirect
- myandroidapp://oauth2/redirect
- myiosapp://oauth2/redirect

@ -12,7 +12,7 @@
<!-- <script>--> <!-- <script>-->
<!-- fetch("http://localhost:8301/sample/code?codeGrpId=GrpID", {--> <!-- fetch("http://localhost:8301/sample/callback?codeGrpId=GrpID", {-->
<!-- // method: "GET",--> <!-- // method: "GET",-->
<!-- // headers: {--> <!-- // headers: {-->
<!-- // "Content-Type": "application/json",--> <!-- // "Content-Type": "application/json",-->

Loading…
Cancel
Save