월 24,200원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결스프링 시큐리티 OAuth2
OAuth2 클라이언트를 어디에 구성하는 것이 좋은지 고민이 되어 질문드립니다
안녕하세요 정수원님~!현재 front가 react로 되어있다보니 OAuth2 클라이언트 서버를 node 서버냐(프론트에서 처리) spring boot 서버(백엔드에서 처리)냐에서 고민이 되는데 보통 이럴경우 OAuth2 클라이언트 서버를 어디에 구성하는게 좋을지 궁금합니다~!
- 미해결스프링 시큐리티 OAuth2
고도의 신뢰성을 가지고있는 클라이언트
안녕하세요 클라이언트가 고도의 신뢰성을 가지고있는가? 에 대해 No인경우 Authorization Code 방식을, Yes인경우에는 Resource Owner 방식을 선택한다는 내용이있었는데 여기서 말하는 고도의 신뢰성을 가진 클라이언트는 구글,네이버,페이스북 이런 곳들이 해당되는걸까요?흔히 생각했을때 인프런 로그인을할때 구글로 로그인하는경우에는 Authorization code 방식이지만, 구글자체에 로그인한다고하면 Resource Owner 방식으로 하고있는건가? 라는 생각이 들어서요
- 미해결스프링 시큐리티 OAuth2
OAuth 2.0 Authorization Grant Code 네이버 로그인 구현
안녕하세요 정수원님 강의 내용과 조금 다른 부분이긴한데 질문드리고자 합니다.Vue와 Spring Boot(Spring Security OAuth Client로 활용)로 네이버 로그인을 구현해보고 있습니다.웹, 안드로이드, iOS 등에 대한 소셜로그인을 Authorization Grant Code방식으로 구현하려고 하고 있으며 REST API 방식으로 동작하도록 하고싶습니다.하지만 Spring Security의 org.springframework.boot:spring-boot-starter-oauth2-client 의존성을 추가하여 OAuth2UserService를 구현하게되면 백엔드에 your-server-host/ oauth2/authorization/naver로 요청을 보내면 사용자에게 로그인을 받고 Authorization Grant Code를 받아와 AccessToken을 반환받고 이를 통해 UserInfo를 Resource Server로부터 받아오는 과정을 처리해줍니다.이 과정속에서 프론트에게 로그인 성공시 실행되는 AuthenticationSuccessHandler 구현 과정에서 sendRedirect를 통해 accessToken과 refreshToken을 전달하려고 했으나 이런 방식은 REST API에 적합하지 않은것 같다고 느껴집니다.심지어 front에서 버튼을 클릭하면 GET 요청으로 /oauth2/authorization/naver를 호출하도록 해보려고 했으나 이 경우에 네이버 로그인 호출하는 과정에서 CORS에러가 발견되어 하이퍼링크로 호출하도록 구현하였습니다. 위의 배경으로 궁금한 점은 다음과 같습니다.프론트엔드와 Authorization Grant Code를 REST API 방식으로 구현하기 위해서는 어떻게 해야할까요? 제가 생각한 방식과 굉장히 유사한 블로그 포스팅을 발견했는데 Spring Security는 사용하지 않는 것 같습니다.(https://blog.naver.com/PostView.naver?blogId=varkiry05&logNo=222295764870) Spring Security를 활용하는 방안이 있다면 추천 부탁드립니다.. 혹은 굳이 Spring Security를 사용하지 않고 구현해도 된다고 생각하시는경우에도 의견주시면 감사하겠습니다.위의 경우에는 client-id를 프론트에서 관리하며 강좌에서 이런 경우에는 보안상의 이슈가 발생할 수 있다고 하셨는데 어떻게 대안점이 있을까요? (https://www.rfc-editor.org/rfc/rfc6749#section-2.3.1) rfc6749에서는 client-id는 secret이 아니라고 하는것 같습니다. 제가 처음 구현하려던 방식과 유사한 tech blog를 찾았습니다. 내부적인 커스터마이징을 통해 redirection을 구현한 것 같습니다.(https://tech.kakao.com/2023/01/19/social-login/) 이때 accessToken과 refreshToken을 redirect시킬 때 param으로 넘긴다면 url주소로 토근값들이 보일것인데 보안상으로 괜찮을까요? ps.실제로 https://olive.kakao.com/login (카카오 테크 블로그에 소개된 redirection이 구현된 페이지)의 js 코드를 까보니 <a> 태그 형식의 하이퍼링크로 호출함을 확인했으며, redirect되는 callback url에서 token값을 확인할 수 있음을 크롬 개발자도구 네트워크탭에서 확인했습니다. 감사합니다.
- 미해결스프링 시큐리티 OAuth2
subject type을 pairwise 변경 문의
subject_type을 pairwise로 변경 하려고 Spring Authorization Server 공식 문서(현재 1.0.1)와 소스(1.0.1과 강의에 사용된 0.31) 소스를 봐도 subject_type 를 변경하는 API는 찿지 못했는데 Spring Authorization Server 에서는 지원하지 않는 걸까요?https://docs.spring.io/spring-authorization-server/docs/current/reference/html/core-model-components.html#oauth2-token-customizer문서를 참조하여 acesss token 과 id token 의 cliams 정보를 커스터마이징한 소스에서 pairwise 유형으로 설정하고 providerConfigurationEndpoint을 커스텀 하여 openid-configuration discovery metadata 의 정보를 변경하면 될까요?@Bean public OAuth2TokenGenerator<?> tokenGenerator(JWKSource<SecurityContext> jwkSource) { JwtEncoder jwtEncoder = new NimbusJwtEncoder(jwkSource); JwtGenerator jwtGenerator = new JwtGenerator(jwtEncoder); jwtGenerator.setJwtCustomizer(jwtCustomizer()); OAuth2AccessTokenGenerator accessTokenGenerator = new OAuth2AccessTokenGenerator(); OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator(); return new DelegatingOAuth2TokenGenerator( jwtGenerator, accessTokenGenerator, refreshTokenGenerator); } @Bean public OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer() { return context -> {; JwtClaimsSet.Builder claims = context.getClaims(); OidcUserResponseDto user = (OidcUserResponseDto)context.getPrincipal().getPrincipal(); claims.subject(user.getEmpId()); claims.claim("dept_id", user.getDeptId()); claims.claim("locale", user.getLocale()); }; } ......... authorizationServerConfigurer.tokenGenerator(tokenGenerator); 참고 현재 설정된 openid-configuration의 subject_types_supported 정보
- 해결됨스프링 시큐리티 OAuth2
Authentication를 받아오는 차이가 뭔가요?
파라미터로 Authentication 객체를 받아오면 Null이고 직접 SecurityContextHolder에서 꺼내오면 anonymousUser가 들어있는 이유가 뭔가요?Authentication 파라미터도 관련 ArgumentResolver에서 SpringSecurityContextHolder.getContext().getAuthentication()으로 꺼내오는 것이 아닌가요?
- 미해결스프링 시큐리티 OAuth2
Resource Owner Password grant 방식 문의
안녕하세요.oauth 를 사용하여 마이크로서비스 인증/인가를 구현하는 경우가 꽤 많은 것으로 알고 있습니다.구글링을 해보면 사용자가 최초 로그인 시, 인증서버에서 jwt 토큰을 발행해주고 사용자는 jwt 토큰을 사용하여 각 마이크로서비스의 api 를 요청하는 컨셉으로 확인됩니다.이때 각각의 마이크로서비스는 oauth 에서 리소스 서버의 역할로 볼 수 있고요.그래서 최초 토큰을 발행하는 인증 방식은 단순히 id/password 를 넘겨서 토큰을 발행받는 Resource Owner Password grant 방식을 사용했던 것 같은데요.하지만 강의에서 설명해 주신대로 최근 스프링 시큐리티의 Authorization 서버에서는 Resoure Owner Password grant 방식을 더 이상 사용할 수 없다고 하셨어요.그렇다면 마이크로서비스를 위해 Authorization 서버를 구현할 때, 토큰 발행을 어떤 방식으로 구현하는 것이 바람직할까요? 제3의 앱에서 로그인을 하는 것도 아닌데 Authorization code 방식을 적용할 필요가 있는 것인지 모르겠네요.
- 해결됨스프링 시큐리티 OAuth2
Ajax 인증시 인가코드가 발급 되지 않는 원인 문의
Spring Authorization 1.0,1 기반으로 개발을 하고 있습니다. 인가코드를 발급 할떄 FormLogin 기본 설정을 사용하면 인가코드가 발급이 되는데 Ajax 로 로그인을 하면 인가코드가 발급되지 않고 있습니다. 디버깅을 해보면 로그인인 후 OAuth2AuthorizationEndpointFilter 는 실행되는데 @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (!this.authorizationEndpointMatcher.matches(request)) { filterChain.doFilter(request, response); return; } try { Authentication authentication = this.authenticationConverter.convert(request); if (authentication instanceof AbstractAuthenticationToken) { ((AbstractAuthenticationToken) authentication) .setDetails(this.authenticationDetailsSource.buildDetails(request)); } Authentication authenticationResult = this.authenticationManager.authenticate(authentication); if (!authenticationResult.isAuthenticated()) { // If the Principal (Resource Owner) is not authenticated then // pass through the chain with the expectation that the authentication process // will commence via AuthenticationEntryPoint filterChain.doFilter(request, response); return; } if (authenticationResult instanceof OAuth2AuthorizationConsentAuthenticationToken) { if (this.logger.isTraceEnabled()) { this.logger.trace("Authorization consent is required"); } sendAuthorizationConsent(request, response, (OAuth2AuthorizationCodeRequestAuthenticationToken) authentication, (OAuth2AuthorizationConsentAuthenticationToken) authenticationResult); return; } this.authenticationSuccessHandler.onAuthenticationSuccess( request, response, authenticationResult); } catch (OAuth2AuthenticationException ex) { if (this.logger.isTraceEnabled()) { this.logger.trace(LogMessage.format("Authorization request failed: %s", ex.getError()), ex); } this.authenticationFailureHandler.onAuthenticationFailure(request, response, ex); } } FormLogin 적용시에는 authenticationResult의 principal 에 UsernamePasswordAuthenticationToken이 설정되어 인가 코드가 정상적으로 발급되는데 AjaxLogin 적용시에는 authenticationResult의 principal 에 AnonymousAuthenticationToken이 설정되어 인가 코드가 정상적으로 발급되지 않고 403 예외가 발생합니다.AuthenticationProvider 구현체에서는 정상적으로 토큰을 저장하고 있습니다. AuthenticationProvider 구현체 소스@Component @RequiredArgsConstructor public class CustomAuthenticationProvider implements AuthenticationProvider { private final CustomUserDetailsService customUserDetailsService; private final PasswordEncoder passwordEncoder; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { if(authentication == null){ throw new InternalAuthenticationServiceException("Authentication is null"); } LoginRequestDto loginRequestDto = (LoginRequestDto)authentication.getPrincipal(); String password = loginRequestDto.getLoginPassword(); UserAdapter userAdapter = (UserAdapter) customUserDetailsService.loadUserByLoinRequestDto(loginRequestDto); if (!passwordEncoder.matches(password, userAdapter.getCurrentUser().getLoginPwd())) { throw new BadCredentialsException("BadCredentialsException"); } CustomAuthenticationToken result = CustomAuthenticationToken.authenticated(userAdapter.getCurrentUser(), authentication.getCredentials(), userAdapter.getAuthorities()); result.setDetails(authentication.getDetails()); return result; } @Override public boolean supports(Class<?> authentication) { return CustomAuthenticationToken.class.isAssignableFrom(authentication); } } 이외 Custom 소스Spring Security 설정@EnableWebSecurity @RequiredArgsConstructor @Configuration public class DefaultSecurityConfig { private final CustomAuthenticationProvider customAuthenticationProvider; // private final CustomUserDetailsService customUserDetailsService; @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { return authenticationConfiguration.getAuthenticationManager(); } @Bean public CustomAuthenticationProcessingFilter customAuthenticationProcessingFilter() throws Exception { CustomAuthenticationProcessingFilter filter = new CustomAuthenticationProcessingFilter(); // filter.setAuthenticationManager(authenticationManager(null)); filter.setAuthenticationManager(new ProviderManager(customAuthenticationProvider)); // filter.setAuthenticationSuccessHandler(customAuthenticationSuccessHandler()); // filter.setAuthenticationFailureHandler(customAuthenticationFailureHandler()); return filter; } // @formatter:off @Bean SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(authorizeRequests ->authorizeRequests .requestMatchers(CorsUtils::isPreFlightRequest).permitAll() .requestMatchers(new AntPathRequestMatcher("/")).permitAll() .requestMatchers(new AntPathRequestMatcher("/login/**")).permitAll() .requestMatchers("/api/login/**").permitAll() .requestMatchers("/api/registered-client/**").permitAll() .anyRequest().authenticated() ); http.addFilterBefore(customAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class); http.exceptionHandling(httpSecurityExceptionHandlingConfigurer -> httpSecurityExceptionHandlingConfigurer .authenticationEntryPoint(new CustomLoginAuthenticationEntryPoint()) .accessDeniedHandler(customAccessDeniedHandler()) ); // http.userDetailsService(customUserDetailsService); // http.formLogin(); http.csrf().disable(); return http.build(); } // @formatter:on @Bean public AccessDeniedHandler customAccessDeniedHandler() { return new CustomAccessDeniedHandler(); } @Bean public AuthenticationSuccessHandler customAuthenticationSuccessHandler() { return new CustomAuthenticationSuccessHandler(); } @Bean public AuthenticationFailureHandler customAuthenticationFailureHandler() { return new CustomAuthenticationFailureHandler(); } } Ajax 로그인 처리 필터 소스public class CustomAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter { private final ObjectMapper objectMapper = new ObjectMapper(); private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER = new AntPathRequestMatcher("/api/login", HttpMethod.POST.name()); public CustomAuthenticationProcessingFilter() { super(DEFAULT_ANT_PATH_REQUEST_MATCHER); } public CustomAuthenticationProcessingFilter(AuthenticationManager authenticationManager) { super(DEFAULT_ANT_PATH_REQUEST_MATCHER, authenticationManager); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { if (!request.getMethod().equals("POST")) { throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); } LoginRequestDto loginRequestDto = objectMapper.readValue(request.getReader(), LoginRequestDto.class); if(StringUtils.isEmpty(loginRequestDto.getLoginId())||StringUtils.isEmpty(loginRequestDto.getLoginPassword())) { throw new IllegalStateException("Username or Password is empty"); } CustomAuthenticationToken authRequest = CustomAuthenticationToken.unauthenticated(loginRequestDto, loginRequestDto.getLoginPassword()); authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request)); return getAuthenticationManager().authenticate(authRequest); } } CustomAuthenticationToken 소스public class CustomAuthenticationToken extends AbstractAuthenticationToken { private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; private final Object principal; private Object credentials; public CustomAuthenticationToken(Object principal, Object credentials) { super(null); this.principal = principal; this.credentials = credentials; setAuthenticated(false); } public CustomAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) { super(authorities); this.principal = principal; this.credentials = credentials; super.setAuthenticated(true); // must use super, as we override } public static CustomAuthenticationToken unauthenticated(Object principal, Object credentials) { return new CustomAuthenticationToken(principal, credentials); } public static CustomAuthenticationToken authenticated(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) { return new CustomAuthenticationToken(principal, credentials, authorities); } @Override public Object getCredentials() { return this.credentials; } @Override public Object getPrincipal() { return this.principal; } }
- 해결됨스프링 시큐리티 OAuth2
AuthorizedClient 질문
OAuth2AuthorizedClient 의 클라이언트가클라이언트 서버를 의미하는 지리소스 오너의 정보를 의미하는 지 헷갈립니다.ㅠㅠ 클라이언트 서버에서 인증 받은 클라이언트라고 하면이걸 서버 입장에서의 사용자를 이야기 하는 건지무엇을 얘기하는 지 헷갈리네요..
- 미해결스프링 시큐리티 OAuth2
AbstractOAuth2UserService의 @Autowired
안녕하세요 정수원님. 덕분에 스프링 시큐리티를 알아가고 있습니다. 수강 중 문의드리고 싶은 점이 생겨 질문 드립니다.customUserDetailService에서는 @RequiredArgsConstructor로 생성자 초기화를 하고 AbstractOAuth2UserService에서는 @Autowired로 생성자 초기화를 하는데 이와 같은 방식으로 생성자 초기화를 설정하신 이유를 알고 싶습니다. 답변해주시면 정말 감사드리겠습니다!
- 해결됨스프링 시큐리티 OAuth2
Ajax 인증시 AuthenticationManager 등록 문의
Spring Authorization 1.0 을 사용하여 FormLogin 이 아닌 Ajax로 로그인을 하려고 합니다.Spring Security 강의를 참조하여AbstractAuthenticationProcessingFilter를 상속하여 CustomUserDetailsService, CustomAuthenticationProvider, CustomAuthenticationProcessingFilter, CustomAuthenticationToken 구현체를 만들었습니다.CustomAuthenticationProcessingFilter는 AbstractAuthenticationProcessingFilter 상속하여 개발하였는데 Filter를 등록 하려면 강의에서 내용처럼 AuthenticationManager를 등록 해줘여 하는데 강의는 WebSecurityConfigurerAdapter 상속하여 설정 하는것으로 설명되어 있는데 Spring Securitty 6.0 에서는 삭제되었습니다.Spring Security 의 강의를 보면 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(ajaxAuthenticationProvider()); }configure(AuthenticationManagerBuilder auth)를 구현하고 @Bean public AjaxLoginProcessingFilter ajaxLoginProcessingFilter() throws Exception { AjaxLoginProcessingFilter filter = new AjaxLoginProcessingFilter(); filter.setAuthenticationManager(authenticationManagerBean()); return filter; } 질문)AjaxLoginProcessingFilter Bean 에서 설정하는데 SecurityFilterChain 를 등록하는 방식에서는 어떻게 등록해야 할지 문의 합니다.제가 구현한 소스 일부Authorization Server 설정을 다른 클래스에서 설정하였고 디버깅을 해보니 Authorization Server 용 FilterChain 과 로그인 처리용 FilterChain 이 따로 등록되어 로그인 프로세스는 Spring Security FilterChain Class 에서 진행하였습니다@Configuration는 Spring Security 6에서는 @EnableWebSecurity에 포함되지 않아 추가 하였습니다.@EnableWebSecurity @RequiredArgsConstructor @Configuration public class DefaultSecurityConfig { private final PasswordEncoder passwordEncoder; private final CustomAuthenticationProvider customAuthenticationProvider; // @Bean public CustomAuthenticationProcessingFilter customAuthenticationProcessingFilter() throws Exception { CustomAuthenticationProcessingFilter filter = new CustomAuthenticationProcessingFilter(); return filter; } // @formatter:off @Bean SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(authorizeRequests ->authorizeRequests .requestMatchers(CorsUtils::isPreFlightRequest).permitAll() .requestMatchers("/login/**").permitAll() .requestMatchers("/api/registered-client/**").permitAll() .anyRequest().authenticated() ) .csrf(csrf -> csrf .ignoringRequestMatchers(new AntPathRequestMatcher("/api/registered-client/**")) ) .formLogin().disable(); http.authenticationProvider(customAuthenticationProvider); http.addFilterBefore(customAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class); return http.build(); } // @formatter:on }AuthenticationManager를 등록하지 않아 예와가 발생함Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'customAuthenticationProcessingFilter' defined in class path resource [com/naon/oidc/security/config/DefaultSecurityConfig.class]: authenticationManager must be specified그리고 @Bean으로 만들어 등록하면 순환참조가 됩니다.
- 미해결스프링 시큐리티 OAuth2
Authorization Code Grant Type 문의
강사님 안녕하세요.신규 Authorization 서버를 구축해보고자 사전 지식 쌓을겸 강의를 현재 듣고 있습니다.Authorization code grant 방식으로 고려중인데 User Credentials을 사용안하고(openId X) 단순히 code 발급, token 발급, token 인증 형태의 기능만 사용하고 싶은 경우에 FilterChain에서 설정이 가능한지 궁금합니다. 브라우저를 통해 로그인 없이 단순 API 형태로써 말이죠.왜냐하면 다른 형태의 SSO Token을 내부적으로 활용해야 하는 방향으로 접근해야 해서, 리소스 획득을 위한 인증 방식으로 Authorization Code Grant Type을 적용해볼까 했습니다.항상 로그인을 통한 User Detail Repository 참조의 형태를 가져가는것이 기본인지 해당 기능을 off 할 수 있는지 궁금합니다.감사합니다.
- 미해결스프링 시큐리티 OAuth2
RSA 검증 기능 구현 - JwtAuthorizationRsaFilter
강의를 보다 의문이 생겨서 질문 드립니다.http.addFilterBefore(jwtAuthorizationRsaFilter(null), UsernamePasswordAuthenticationFilter.class);필터를 등록하실 때 jwtAuthorizationRsaFIlter에 null을 주셨습니다.@Bean public JwtAuthorizationRsaFilter jwtAuthorizationRsaFilter(RSAKey rsaKey) throws JOSEException { return new JwtAuthorizationRsaFilter(new RSASSAVerifier(rsaKey.toRSAPublicKey())); // 검증은 공개키 }그러나 jwtAuthorizationRsaFIlter는 파라미터에 넘어온 rsaKey를 이용하여 공개키를 찾는데 이 rsaKey는 어디서 주입 받는 것인가요??설정 클래스에 @Autowired는 모두 삭제한 것으로 알고 있습니다.jwtAuthenticationFilter를 등록할 때 역시 같은 이유로 어디서 주입 받는지 잘 모르겠습니다.
- 해결됨스프링 시큐리티 OAuth2
추가 질문 드립니다.
https://www.inflearn.com/questions/770325 안녕하세요.OAuth2 를 Toggle 버튼 등으로 계정 하나에 여러 SNS 계정을 연동하는 방법에 질문 드렸었는데, 상세 내용 전달 드립니다. 이와 같이, 보여드린 사진처럼 이미 로그인을 한 상태에서 네이버, 카카오 등을 연동하는 것입니다 제가 생각해보았었던 구현 방법을 한번 말씀 드리겠습니다.사용자 로그인 (JWT)회원 상세 정보 화면 이동상세 화면에서 위에서 첨부 드린 사진과 같이, sns 설정을 통해 네이버 연동 시작네이버 선택시 oauth2/authorization/naver redirect사용자 네이버 로그인 과정네이버 로그인이 완료되면 OAuth2UserService 에서 네이버 계정의 정보를 얻어 오고, 기존 계정과 연동을 하고자 하는데 기존 계정의 정보를 알 수 있는 방법이 도저히 떠오르지 않아서 질문을 드렸었습니다.한 가지 생각한 것은, 4번의 과정에서 기존 계정을 Cookie 에 저장하고, 추후에 naver 로그인이 완료 되고 AuthenticationSuccessHandler 에서 request 안에 있는 cookie 로 판별하는 것이었습니다.하지만 이 방법은 (1) 기존 계정에 SNS 연동을 하려고 하는 건지(지금 말씀드리고 있는 방법) (2)계정 로그인이 안된 상태에서 SNS 로그인 과정을 걸치는 건지 2가지 케이스가 있을 것 같은데, 이런 부분을 쿠키를 통해서 분기 처리를 한다는 것이 데이터 정합성에 문제가 생기지 않을까 염려되었습니다. (AuthenticationSuccessHandler 에서 쿠키만으로 기존 password 계정에 SNS 연동을 하는 것인지, 신규 SNS 회원 가입인지 판별하는 것은 위험해보였습니다. )쿠키 방식 말고, (1) 기존 계정에 SNS 연동을 하려고 하는 건지(지금 말씀드리고 있는 방법) (2)계정 로그인이 안된 상태에서 SNS 로그인 과정을 걸치는 건지 2가지 케이스 를 구분할 수 있는 방법에 대해 조언 해주시면 감사하겠습니다!
- 미해결스프링 시큐리티 OAuth2
git hub 들어가니 소스가 비어있습니다 강사님
git hub 들어가니 소스가 비어있습니다 강사님https://github.com/onjsdnjs/spring-security-oauth2/tree/master/src/main/java/io/security/oauth2
- 해결됨스프링 시큐리티 OAuth2
Authorization Code 궁금증이 있습니다.
안녕하세요 선생님 강의 잘 듣고 있습니다 Authorization Code 요청하기 강의를 듣고 궁금한점이 생겨서 질문 올립니다 이번 강의의 핵심은 임시코드 발급하기 였습니다 클라이언트가 keyCloak 와 연동해서 어떻게 redirect uri 를 만들고 어떻게 요청을 하고 인증이 완료 되는것도 같이 해보았습니다 다만 저는 좀 궁금한게 선생님이 총 2개의 로그인 방식을 보여주셨다고 생각합니다 이 링크를 클릭했을때의 방식 다른 방식은 세션을 완전히 제거한 이 화면에서 로그인 하는 방식을 보여주셨습니다 여기선 궁금한건 이번강의 주제는 임시코드를 발급받는 Filter 에 대해서 공부중인데첫번째 스크린샷에서는 선생님이 말씀하신 대로 OAuth2AuthorizationRequestRedirectFilter 에서 잘 요청이 들어옵니다requset 가 "/oauth2/authorization"; 들어오기 떄문인데 두번쨰 스크린샷에서는 전혀 이 필터를 태우지 않습니다 저는 임시코드 발급이라고 하길래 지금 할려는 스크린샷 1 , 2 두 행동 모두가 임시코드를 발급받기 위한 행동으로 알고 있습니다 그런데 첫번째 스크린샷은 OAuth2AuthorizationRequestRedirectFilter 필터를 태우고 두번째 스크린샷은 OAuth2LoginAuthenticationFilter 이 필터를 태우고 있습니다 이 앞의 configure 강의에서도 요청 순서 말씀하시면서 OAuth2AuthorizationRequestRedirectFilter 가 먼저 요청을 받아서 임시코드를 받아오고 그 다음 OAuth2LoginAuthenticationFilter 가 진행된다 라고 하셔서 제가 지금 혼동이 오는거 같습니다. 앞의 부분에서 제가 놓친 부분이 있을까요 선생님?
- 미해결스프링 시큐리티 OAuth2
OAuth 2.0 Token Endpoinr Flow - 클라이언트 인증하기
강의 영상이 로딩이 안돼고 있습니다P
- 해결됨스프링 시큐리티 OAuth2
JdbcOAuth2AuthorizationService에서 DB에 저장시 오류 원인
OAuth2AuthorizationService 구현체를 JdbcOAuth2AuthorizationService로 변경하였습니다.Spring Authorization Server 버전은 1.0 입니다.@Bean public OAuth2AuthorizationService authorizationService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository) { return new JdbcOAuth2AuthorizationService(jdbcTemplate, registeredClientRepository); }DB Schema : Spring Authorization Server 에서 제공/* IMPORTANT: If using PostgreSQL, update ALL columns defined with 'blob' to 'text', as PostgreSQL does not support the 'blob' data type. */ CREATE TABLE oauth2_authorization ( id varchar(100) NOT NULL, registered_client_id varchar(100) NOT NULL, principal_name varchar(200) NOT NULL, authorization_grant_type varchar(100) NOT NULL, authorized_scopes varchar(1000) DEFAULT NULL, attributes blob DEFAULT NULL, state varchar(500) DEFAULT NULL, authorization_code_value blob DEFAULT NULL, authorization_code_issued_at timestamp DEFAULT NULL, authorization_code_expires_at timestamp DEFAULT NULL, authorization_code_metadata blob DEFAULT NULL, access_token_value blob DEFAULT NULL, access_token_issued_at timestamp DEFAULT NULL, access_token_expires_at timestamp DEFAULT NULL, access_token_metadata blob DEFAULT NULL, access_token_type varchar(100) DEFAULT NULL, access_token_scopes varchar(1000) DEFAULT NULL, oidc_id_token_value blob DEFAULT NULL, oidc_id_token_issued_at timestamp DEFAULT NULL, oidc_id_token_expires_at timestamp DEFAULT NULL, oidc_id_token_metadata blob DEFAULT NULL, refresh_token_value blob DEFAULT NULL, refresh_token_issued_at timestamp DEFAULT NULL, refresh_token_expires_at timestamp DEFAULT NULL, refresh_token_metadata blob DEFAULT NULL, PRIMARY KEY (id) ); authorization code 발급시 로그인 화면 계정 정보 입력 후 MariaDB에 저장할떄 .BadSqlGrammarException 예외가 발생합니다, 질문1)에러 로그를 보면 insertAuthorization 메소드에서 attribute 컬럼에 Principal Class 자체를 저장하는 과정에서 발생하고 있습니다,다만,퀴리를 DB에서 직접 실행하면 저장이 되는것 으로 보아 Spring JDBCTemplate에서 변환시 오루가 발생하는거 같은데 원인이 궁급합니다. private void insertAuthorization(OAuth2Authorization authorization) { List<SqlParameterValue> parameters = this.authorizationParametersMapper.apply(authorization); try (LobCreator lobCreator = this.lobHandler.getLobCreator()) { PreparedStatementSetter pss = new LobCreatorArgumentPreparedStatementSetter(lobCreator, parameters.toArray()); this.jdbcOperations.update(SAVE_AUTHORIZATION_SQL, pss); } } Caused by: java.sql.SQLSyntaxErrorException: (conn=952251) Could not convert [{"@class":"java.util.Collections$UnmodifiableMap","java.security.Principal":{"@class":"org.springframework.security.authentication.UsernamePasswordAuthenticationToken","authorities":["java.util.Collections$UnmodifiableRandomAccessList",[{"@class":"org.springframework.security.core.authority.SimpleGrantedAuthority","authority":"ROLE_USER"}]],"details":{"@class":"org.springframework.security.web.authentication.WebAuthenticationDetails","remoteAddress":"0:0:0:0:0:0:0:1","sessionId":"B8C2C171954B719820D6592F6102AF9B"},"authenticated":true,"principal":{"@class":"org.springframework.security.core.userdetails.User","password":null,"username":"user1","authorities":["java.util.Collections$UnmodifiableSet",[{"@class":"org.springframework.security.core.authority.SimpleGrantedAuthority","authority":"ROLE_USER"}]],"accountNonExpired":true,"accountNonLocked":true,"credentialsNonExpired":true,"enabled":true},"credentials":null},"org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest":{"@class":"org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest","authorizationUri":"http://localhost:9000/oauth2/authorize","authorizationGrantType":{"value":"authorization_code"},"responseType":{"value":"code"},"clientId":"messaging-client","redirectUri":"http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc","scopes":["java.util.Collections$UnmodifiableSet",["openid"]],"state":null,"additionalParameters":{"@class":"java.util.Collections$UnmodifiableMap","grant_type":"authorization_code"},"authorizationRequestUri":"http://localhost:9000/oauth2/authorize?response_type=code&client_id=messaging-client&scope=openid&redirect_uri=http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc&grant_type=authorization_code","attributes":{"@class":"java.util.Collections$UnmodifiableMap"}}}] to -4 RegisteredClientRepository는 구현체를 JdbcRegisteredClientRepository 로 변경해도 이상없이 동작 하고 있고 JdbcAuthorizationConsentService는 JdbcOAuth2AuthorizationService 오류로 동의 단게가 진행되지 않아서 확인해보지 않았습니다. 질문2)이외에도Authorization Server에서 blob 컴럼에 Class 자체를 저장하는 사례가 많이 있는데 커스참 구현체를 만들어서 Class 를 저장하지 않고 Authorization Server 필요한 항목만 JSON 으로 저장 하거나 테이블을 정규화 하여 Map 에 담아 주는것이 좋은 방법일까요? 참고로 Attribe는 JwtGenerator에서 보면 nonce 을 가지고 오고 있습니다.if (AuthorizationGrantType.AUTHORIZATION_CODE.equals(context.getAuthorizationGrantType())) { OAuth2AuthorizationRequest authorizationRequest = context.getAuthorization().getAttribute( OAuth2AuthorizationRequest.class.getName()); String nonce = (String) authorizationRequest.getAdditionalParameters().get(OidcParameterNames.NONCE); if (StringUtils.hasText(nonce)) { claimsBuilder.claim(IdTokenClaimNames.NONCE, nonce); } } 에러로그 전문org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [INSERT INTO oauth2_authorization (id, registered_client_id, principal_name, authorization_grant_type, authorized_scopes, attributes, state, authorization_code_value, authorization_code_issued_at, authorization_code_expires_at,authorization_code_metadata,access_token_value,access_token_issued_at,access_token_expires_at,access_token_metadata,access_token_type,access_token_scopes,oidc_id_token_value,oidc_id_token_issued_at,oidc_id_token_expires_at,oidc_id_token_metadata,refresh_token_value,refresh_token_issued_at,refresh_token_expires_at,refresh_token_metadata) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)]at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:101) ~[spring-jdbc-6.0.4.jar:6.0.4]at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70) ~[spring-jdbc-6.0.4.jar:6.0.4]at org.springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1538) ~[spring-jdbc-6.0.4.jar:6.0.4]at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:667) ~[spring-jdbc-6.0.4.jar:6.0.4]at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:960) ~[spring-jdbc-6.0.4.jar:6.0.4]at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:1015) ~[spring-jdbc-6.0.4.jar:6.0.4]at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService.insertAuthorization(JdbcOAuth2AuthorizationService.java:211) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0]at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService.save(JdbcOAuth2AuthorizationService.java:189) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0]at org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeRequestAuthenticationProvider.authenticate(OAuth2AuthorizationCodeRequestAuthenticationProvider.java:209) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0]at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:182) ~[spring-security-core-6.0.1.jar:6.0.1]at org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationEndpointFilter.doFilterInternal(OAuth2AuthorizationEndpointFilter.java:166) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.4.jar:6.0.4]at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.0.1.jar:6.0.1]at org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationServerMetadataEndpointFilter.doFilterInternal(OAuth2AuthorizationServerMetadataEndpointFilter.java:84) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.4.jar:6.0.4]at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.0.1.jar:6.0.1]at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) ~[spring-security-web-6.0.1.jar:6.0.1]at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) ~[spring-security-web-6.0.1.jar:6.0.1]at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.0.1.jar:6.0.1]at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:116) ~[spring-security-web-6.0.1.jar:6.0.1]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.4.jar:6.0.4]at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.0.1.jar:6.0.1]at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) ~[spring-security-web-6.0.1.jar:6.0.1]at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) ~[spring-security-web-6.0.1.jar:6.0.1]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.4.jar:6.0.4]at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.0.1.jar:6.0.1]at org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.AuthorizationServerContextFilter.doFilterInternal(AuthorizationServerContextFilter.java:61) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.4.jar:6.0.4]at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.0.1.jar:6.0.1]at org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:82) ~[spring-security-web-6.0.1.jar:6.0.1]at org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:69) ~[spring-security-web-6.0.1.jar:6.0.1]at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.0.1.jar:6.0.1]at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) ~[spring-security-web-6.0.1.jar:6.0.1]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.4.jar:6.0.4]at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.0.1.jar:6.0.1]at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) ~[spring-security-web-6.0.1.jar:6.0.1]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.4.jar:6.0.4]at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.0.1.jar:6.0.1]at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) ~[spring-security-web-6.0.1.jar:6.0.1]at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) ~[spring-security-web-6.0.1.jar:6.0.1]at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:351) ~[spring-web-6.0.4.jar:6.0.4]at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) ~[spring-web-6.0.4.jar:6.0.4]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-6.0.4.jar:6.0.4]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.4.jar:6.0.4]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-6.0.4.jar:6.0.4]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.4.jar:6.0.4]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-6.0.4.jar:6.0.4]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.4.jar:6.0.4]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:177) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:859) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1734) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-10.1.5.jar:10.1.5]at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]Caused by: java.sql.SQLSyntaxErrorException: (conn=952251) Could not convert [{"@class":"java.util.Collections$UnmodifiableMap","java.security.Principal":{"@class":"org.springframework.security.authentication.UsernamePasswordAuthenticationToken","authorities":["java.util.Collections$UnmodifiableRandomAccessList",[{"@class":"org.springframework.security.core.authority.SimpleGrantedAuthority","authority":"ROLE_USER"}]],"details":{"@class":"org.springframework.security.web.authentication.WebAuthenticationDetails","remoteAddress":"0:0:0:0:0:0:0:1","sessionId":"B8C2C171954B719820D6592F6102AF9B"},"authenticated":true,"principal":{"@class":"org.springframework.security.core.userdetails.User","password":null,"username":"user1","authorities":["java.util.Collections$UnmodifiableSet",[{"@class":"org.springframework.security.core.authority.SimpleGrantedAuthority","authority":"ROLE_USER"}]],"accountNonExpired":true,"accountNonLocked":true,"credentialsNonExpired":true,"enabled":true},"credentials":null},"org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest":{"@class":"org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest","authorizationUri":"http://localhost:9000/oauth2/authorize","authorizationGrantType":{"value":"authorization_code"},"responseType":{"value":"code"},"clientId":"messaging-client","redirectUri":"http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc","scopes":["java.util.Collections$UnmodifiableSet",["openid"]],"state":null,"additionalParameters":{"@class":"java.util.Collections$UnmodifiableMap","grant_type":"authorization_code"},"authorizationRequestUri":"http://localhost:9000/oauth2/authorize?response_type=code&client_id=messaging-client&scope=openid&redirect_uri=http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc&grant_type=authorization_code","attributes":{"@class":"java.util.Collections$UnmodifiableMap"}}}] to -4at org.mariadb.jdbc.export.ExceptionFactory.createException(ExceptionFactory.java:282) ~[mariadb-java-client-3.0.10.jar:na]at org.mariadb.jdbc.export.ExceptionFactory.create(ExceptionFactory.java:336) ~[mariadb-java-client-3.0.10.jar:na]at org.mariadb.jdbc.BasePreparedStatement.setInternalObject(BasePreparedStatement.java:1172) ~[mariadb-java-client-3.0.10.jar:na]at org.mariadb.jdbc.BasePreparedStatement.setObject(BasePreparedStatement.java:608) ~[mariadb-java-client-3.0.10.jar:na]at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.setObject(HikariProxyPreparedStatement.java) ~[HikariCP-5.0.1.jar:na]at org.springframework.jdbc.core.StatementCreatorUtils.setValue(StatementCreatorUtils.java:415) ~[spring-jdbc-6.0.4.jar:6.0.4]at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValueInternal(StatementCreatorUtils.java:236) ~[spring-jdbc-6.0.4.jar:6.0.4]at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValue(StatementCreatorUtils.java:152) ~[spring-jdbc-6.0.4.jar:6.0.4]at org.springframework.jdbc.core.ArgumentPreparedStatementSetter.doSetValue(ArgumentPreparedStatementSetter.java:65) ~[spring-jdbc-6.0.4.jar:6.0.4]at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService$LobCreatorArgumentPreparedStatementSetter.doSetValue(JdbcOAuth2AuthorizationService.java:621) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0]at org.springframework.jdbc.core.ArgumentPreparedStatementSetter.setValues(ArgumentPreparedStatementSetter.java:50) ~[spring-jdbc-6.0.4.jar:6.0.4]at org.springframework.jdbc.core.JdbcTemplate.lambda$update$2(JdbcTemplate.java:963) ~[spring-jdbc-6.0.4.jar:6.0.4]at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:651) ~[spring-jdbc-6.0.4.jar:6.0.4]... 68 common frames omitted
- 해결됨스프링 시큐리티 OAuth2
OAuth2 Login에 대해 궁금한 점
안녕하세요해당 강의를 통해서 OAuth2 로그인을 따라해보면서, 궁금한 점이 생겨서 질문 드립니다.만약에 기존 유저에 OAuth2 로그인을 적용시키려면 어떻게 하는 지 궁금하네요..요즘 여러 서비스에서, OAuth2를 도입하고 기존 계정에 Toggle 버튼 같이 네이버, 카카오 등을 On, Off 할 수 있는 기능들을 제공합니다하지만 Spring Security OAuth2 Login 기능으로 기존 계정에 on,off 처럼 연결이 가능할까 의문도 들고 생각도 해봤지만 도저히 떠오르지 않더라구여더군다나 기존 계정에 JWT 로 인증을 하고 있었다면 불가능하지 않나 생각이 들었습니다.너무 막연하게 질문을 드렸는데, 정확하게 알고 싶은 것은 유저 상세 페이지에서 토글 버튼 같은 것으로 네이버 연동을 시도하여 네이버 로그인을 시도했을 때,OAuth2UserService 에서 기존 유저에 대한 정보를 알 수 있는 방법이 있는 지 궁금합니다
- 해결됨스프링 시큐리티 OAuth2
OAuth2 로그인 이후 통신 방법
안녕하세요.OAuth2 로그인 이후에 검증 방식에 대해 궁금한 점이 있어서 질문 드려봅니다.현재 프로젝트에서 OAuth2 를 이용하여 로그인 하는 기능을 사용하고자 하여, 강사님의 강의를 통해 OAuth2 Login을 적용시켰습니다.OAuth2 를 이용하여 회원가입을 하고, 회원가입이 완료되어 OAuth2로 로그인하면, 자체적으로 생성한 JWT Token 을 이용하여 Client 와 통신을 하는 방식으로 구현하였습니다.API 호출 마다 JWT 토큰만으로 인증을 하고 있었는데, JWT 토큰 이후 이 유저가 OAuth2(예를들어 네이버 같은 서버)에서도 유효한 회원인 지 검증이 필요하지 않을까 생각이 들었고,유저가 OAuth2 서버에서 유효한 회원인 지 검증 하는 부분을 만들고자 하는데, 내부적으로 이용할 수 있는 기능이 있는지 문의 드립니다.ClientRegistration 에 user-info-uri 를 통해 유저 정보를 가져오기 때문에, 예를 들어 oauth2_authorized_client의 accessToken을 이용하여 Naver(OAuth2)에서 회원을 간단하게 조회하고 검증 작업을 진행하면 되지 않을까 해서 내부적으로 이용할 수 있는 기능이 있을 것 같아서요..아니면 OAuth2 로그인 이후에 검증 방식에 대해서 제가 잘못 이해한 부분이 있다면 말씀 부탁 드리겠습니다감사합니다.
- 미해결스프링 시큐리티 OAuth2
무한리디렉션 궁금증
안녕하세요 선생님 강의 잘듣고 있습니다 오늘 처음으로 spring 시큐리티와 keycloak 와 사용해서 간단한 RestController 을 만들어서 keycloak 로 로그인하는 강의를 들었는데 궁금점이 생겼습니다 applition.yml redirect 구성하실때 http://localhost:8081/login/oauth2/code/keycloak이 주소가 시큐리티 ouath2 로그인 고유 주소인가요? 제가 테스트한다고 oauth2 에 다른 문자열을 넣고 돌리면 리디렉션이 너무 많다고 크롬 , 엣지에서 오류가 발생합니다 ex1) clientId - OAuth2-client-appredirectUri=http://localhost:8081/login/oauth2/code/keycloakex2)clientId - OAuth2-client-appredirectUri=http://localhost:8081/login/OAuth2-client-app/code/keycloak 이렇게 비교를 해보았는데 1번은 로그인이 잘되고 2번은 계속 무한 리디렉션이 나옵니다 그래서 ex1) 번을 크롬 개발자 도구로 쫒아 가보니 1) http://localhost:8081/oauth2/authorization/keycloak status :302 Location: http://localhost:8080/realms/spring-security-OAuth2/protocol/openid-connect/auth?response_type=code&client_id=OAuth2-client-app&scope=openid%20email%20profile&state=wNz-VZFRvu_Nr8KUFYjRshELNLOFbUZVO9vWdcEQrs4%3D&redirect_uri=http://localhost:8081/login/oauth2/code/keycloak&nonce=ehS4VAjQJBrDf7APtHtUbWuzwdOnCJAOd8BhRhSohoU 2) http://localhost:8080/realms/spring-security-OAuth2/protocol/openid-connect/auth?response_type=code&client_id=OAuth2-client-app&scope=openid%20email%20profile&state=wNz-VZFRvu_Nr8KUFYjRshELNLOFbUZVO9vWdcEQrs4%3D&redirect_uri=http://localhost:8081/login/oauth2/code/keycloak&nonce=ehS4VAjQJBrDf7APtHtUbWuzwdOnCJAOd8BhRhSohoUstatus : 302 Location: http://localhost:8081/login/oauth2/code/keycloak?state=wNz-VZFRvu_Nr8KUFYjRshELNLOFbUZVO9vWdcEQrs4%3D&session_state=0e8d5564-fa24-4521-9bd9-bd931d42beb7&code=58d084f3-272e-4e31-ad4d-edc808fde122.0e8d5564-fa24-4521-9bd9-bd931d42beb7.e3344d0f-ca0d-44fd-8993-08b7b90ca190 3) http://localhost:8081/login/oauth2/code/keycloak?state=wNz-VZFRvu_Nr8KUFYjRshELNLOFbUZVO9vWdcEQrs4%3D&session_state=0e8d5564-fa24-4521-9bd9-bd931d42beb7&code=58d084f3-272e-4e31-ad4d-edc808fde122.0e8d5564-fa24-4521-9bd9-bd931d42beb7.e3344d0f-ca0d-44fd-8993-08b7b90ca190status : 302 Location: http://localhost:8081/ 스프링 시큐리티 안에서 oauth2 가 가지는 고유의 엔드포인트 라고 생각을 해야 하는게 맞는거겠죠? 무한리디렉션이 생기는 이유는 솔직히 모르겠습니다 아마 로그인 권한은 획득했는데.. 그 이후는 잘 모르겠습니다.