묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨스프링 시큐리티 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
안녕하세요 MSA 구성을 진행하고 있는 뉴비 신입 개발자입니다.
KeyCloak 을 인가서버로 활용하고Resource 자원 사용하는 Data API 인가 처리를 하는 Auth API (Gateway) 를 구현해서 진행하고 있습니다.그런데 너무 여러가지 방식이 많다보니 혼돈이 와서 선생님이 가르쳐주신 방식으로 인가와 인증을 구현하려고하는데,인가 서버 -> KeyCloak 사용 게이트 웨이에 Oauth2 를 넣으려고 하는데 개념적으로 궁금한 점이 있어 여쭤봅니다.공개 클라이언트 방식과 기밀 클라이언트 가 구현함에 있어 어떤 차이를 가지는지 의문입니다.가령 react -> KeyCloak 요청 시 token 을 바로 가져오려고 하는데, 이 토큰을 받는 것 까진 문제가 없습니다. 하지만 영상에서 보여주신 것과 같이 자원 API 로 접근하는 권한을 획득하기 위해서 기밀 클라이언트 방식으로 구현하면 code 를 리다이렉트 받은 uri 와 token 요청시 리다이렉트 uri 가 같아야하는 문제가 있어서 code 를 auth api 로 받은 뒤 토큰 엔드포인트를 찍어 스프링 프로젝트에서 가져올 때 오류가 발생합니다.react -> keycloak -> code 반환 받은 것 -> spring -> redirect uri 문제로 토큰 발급 불가 가 되는데 어떤 형식으로 처리해야 맞는 것인지 궁금합니다.
-
해결됨스프링 시큐리티 OAuth2
강의에 매칭되는 git branch 찾기가 매우 힘듭니다.
안녕하세요 !git branch 마다 README 파일이 있는건 아니라서강의에 해당하는 git branch 를 찾기가 매우 힘듭니다.혹시 강의와 브렌치의 매핑이 정리된 자료가 있나요 ?
-
미해결스프링 시큐리티 OAuth2
keycloack userinfo 403 forbidden error
https://www.inflearn.com/questions/693312/profile-email-%EA%B6%8C%ED%95%9C%ED%8E%98%EC%9D%B4%EC%A7%80%EA%B0%80-%EB%82%98%EC%98%A4%EC%A7%80-%EC%95%8A%EC%8A%B5%EB%8B%88%EB%8B%A4 해당 페이지에 있는 해결 방법 그대로consent required를 킨 후에access token을 받아오는 것 까지는 잘 되는데,마찬가지로 userinfo 요청시http://localhost:8080/realms/oauth2/protocol/openid-connect/userinfo에 Authorization에 Bearer Token타입 체크 후Token값도 받아온 access_token값으로 잘 넣어줬는데도403 forbidden 에러가 뜨네요무엇이 잘못된걸까요keycloack버전은 20.0.2입니다
-
미해결스프링 시큐리티 OAuth2
Spring Boot 를 이용해 JWT + Social 로그인 처리 질문 있습니다.
안녕하세요. 우선 좋은 강의 제공 해주셔서 감사드립니다 :) 이번에 회사에서 신규 프로젝트로Client Server (Vue, React, Android, IOS)Back Server (Spring Boot)해당 언어로 구성하기로 결정 되었습니다. 신규 프로젝트에 있어서 가장 중요한 부분이 인증 및 인가 시스템인데요.여기서 우리는 JWT + Spring Security 를 사용하기로 결정되었고특히 Social Login 경우 Grant Type 을 "Authorization Code Grant Type" 을 이용하기로 했습니다.아무래도 Authorization Code Grant Type 이 가장 안전하기 때문 입니다. 앞써 말씀드렸지만 Client Server 를 vue, react, Android, ois 를 이용 계획이고Authorization Code Grant Type 을 동시에 이용하면서 인증 처리 할 예정인데요. 인증이 성공적으로 완료된다면 자체적으로 JWT 토큰을 생성해서 Access Token 을 만들고 Client 서버 에게 반환 해서 반환 받은 Client 서버들을 Resouce Server 에서 자원을 요청 하는 시스템입니다. 우선 이미지를 보면서 시나리오를 설명 드리도록 하겠습니다. 일반 로그인A 사용자가 아이디 하고 패스워드를 입력 후 Authorization Server(Spring Boot) 로 전송한다. 인증 처리가 완료 되면 A 사용자 그러니깐 Client 서버에게 자체적으로 JWT Token 을 만들어서 Access Token을 전송한다. Client Server 는 자체적으로 만든 JWT Token (Access Token) 을 쿠키에 저장 하고 Resource Server 에 요청 한다. Social 로그인Client 서버 접속한 사용자는 KaKao 소셜 로그인 버튼을 클릭한다. (요청 파라미터는 카카오로 부터 제공 받은 client_id, redirect_uri + response_type 을 'code' 로 지정한다.) KaKao Authorization Server 는 요청 받은 파라미터로 Client 식별하고 사용자에게 kakao 로그인 페이지를 보여드린다. 생략 되었지만 인가 처리되었다면 임시 코드값을 지정한 redirect uri 통해 client server 로 전송한다. 임시 코드를 받은 Client Server 는 자체적으로 구축한 Authorization Server(Spring Boot) 로 전송한다. 임시 코드를 전송 받은 데이터와 client_id, client_secret, response_type 함께 KaKao Authorization Server 로 요청한다 (Access Token 받기 위해) 인증이 완료되면 KaKao Authorization Server 는 Authorization Server(Spring Boot) 로 인가처리가 완료되었음을 의미하는 Access Token 만들어 전송한다. Access Token 을 발급 받은 Authorization Server(Spring Boot) 서버는 해당 Access Token 을 이용해서 인증 처리하기 위해 KaKao Authorization Server 로 요청한다. 인증 처리 완료되었다면 해당 접속자의 유저 정보를 전송 한다. 해당 유저 정보를 이용해서 회원 가입 프로세스 처리 동시에 자체적으로 JWT Token (Resource Server 접근 하기 위한) 을 생성해서 Client Server에 반환 한다. Client Server 는 자체적으로 만든 JWT Token (Access Token) 을 쿠키에 저장 하고 Resource Server 에 요청 한다. 선생님 강의에서는 Client Server 경우 Spring Boot Security 을 이용했던거와 달리클라이언트 서버 경우 Vue, React, Android, IOS 사용 할려고 합니다.그리고 Grant Type 을 "Authorization Code Grant Type" 사용 하기 때문에 일반 로그인 경우는 문제가 없는데Social 로그인 경우 프로세스를 어떻게 하면 잘 구성 될지 제 나름대로 고민을 해보았습니다. Implicit Grant Type 경우를 사용하면 쉽게 처리 할 수 있을것 같은데Grant Type 을 "Authorization Code Grant Type" 사용 할려다 보니 많이 복잡해지고 이렇게 작동이 될지 의문도 들고 이런 저런 생각이 드네요. 또한 Client Server 경우 절대로 client_secret 을 노출 해서는 안되다는 점 제한으로 이러저런 구성하는데 힘이 좀 들었습니다한번 선생님에게 제가 구상한 프로세스를 피드백 받고 싶어 이렇게 질문 드립니다. 항상 소중한 강의 제공해주셔서 감사드리고 답변 부탁드립니다. 감사합니다 :)
-
해결됨스프링 시큐리티 OAuth2
Spring Authorization Server 1.0 관련
https://spring.io/projects/spring-authorization-serverSpring Authorization Server 1.0이 정식으로 출시되었고 강의는 만들어진 시간으로 보아 0.31 기반인거 같은데 1.0(0.4)에 대한 보강 계획은 있으신지요?
-
미해결스프링 시큐리티 OAuth2
OAuth2 로그인 구현 - Authorization Code 요청하기 - OAuth2AuthorizationRequest 객체 세션 저장 문제
안녕하세요! 좋은 강의 너무 감사드립니다! 한가지 질문 드릴께 있습니다. OAuth2 로그인 구현 - Authorization Code 요청하기26:25분내용을 보면 첫번째 인증 단계! (response type = code)OAuth2AuthorizationRequest 객체 담아서인가 서버 (keyclack 서버) 에 전달 하게 되는데요이것과 동시에 OAuth2AuthorizationRequest 객체를 sesstion 에 저장을 하게 됩니다. 그러면 사용자는 인가 서버 (keyclack 서버) 로그인을 성공적으로 해결된다면 미리 지정된 redirect url 통해Authorization Code 값을 전달해주는데요!그런 후 미리 OAuth2AuthorizationRequest 객체를 sesstion 저장된것을 가져오는데 만약 해당 서버가 1개 라서 다행이지만scale out 경우 그러니깐 서버가 2대 이상이라면 맨처음 OAuth2AuthorizationRequest 객체 저장할때가 1번 서버라면 OAuth2AuthorizationRequest 객체를 가져올때가 2번 서버라면 이때 각각 다른 서버이기 때문에 가져오지 못하는 문제가 발생되지 않나요? 이때는 어떻게 해결해야 할까요??.. OAuth2AuthorizationRequest 객체를 외부 세션 서버로 저장 할수 있도록 다시 로직을 재구현 해야 하는걸까요?
-
미해결스프링 시큐리티 OAuth2
userinfo 요청 시 403에러
http://localhost:8080/realms/oauth2/protocol/openid-connect/userinfo포스트맨 요청 시 403 에러가 납니다 버전은 20.0.1입니다
-
미해결스프링 시큐리티 OAuth2
profile email 권한페이지가 나오지 않습니다.
authorization_code 를 얻어오는 요청 보냄login 페이지가 떠서 로그인함email ,profile 등 이걸 허락하겠는가? (저는 이게 안뜹니다.)8081이 안떠있으니 에러페이지code를 복붙해서 access token 요청 -> accestoken 잘받아옴해당 access token 으로 userinfo 요청시 403 forbidden놓친 설정이 있나 확인을 여러번 하였는데 첫번째 강의에서는 Clients 설정에서 Authentication flow 에 implicit flow를 체크하셨는데 2번째 강의에는 해제 되어있길레 해제 해봤지만 결과는 동일합니다.무엇이 문제인지 알 수 있을까요..? jwt.io에서 토큰 정보를 확인했을떄 다음과 같습니다. 제가 안되길레 여러 RoleMapping을 추가해본것입니다.{ "exp": 1668576888, "iat": 1668576588, "auth_time": 1668576573, "jti": "6775c84b-9f26-4d8c-ab58-a09c136eb782", "iss": "http://localhost:8080/realms/oauth2", "aud": [ "realm-management", "account" ], "sub": "f35e128a-f3a9-48df-a784-5675ade34468", "typ": "Bearer", "azp": "oauth2-client-app", "session_state": "4b46d62b-0dbe-41ba-9901-a2465eed5f41", "acr": "1", "realm_access": { "roles": [ "offline_access", "uma_authorization", "default-roles-oauth2" ] }, "resource_access": { "realm-management": { "roles": [ "manage-users", "view-users", "query-groups", "query-users" ] }, "account": { "roles": [ "manage-account", "manage-account-links", "view-profile" ] } }, "scope": "profile email", "sid": "4b46d62b-0dbe-41ba-9901-a2465eed5f41", "email_verified": false, "name": "kakarot lim", "preferred_username": "user", "given_name": "kakarot", "family_name": "lim", "email": "user@keycloak.com" }구글링 해서 알아본 결과 authorization_code를 요청할때 헤더에 scope=openid 로 하니 잘되었습니다. 이건 버전 차이라고 보면 될까요? 저는 도커로 20 버전을 사용하였습니다.
-
미해결스프링 시큐리티 OAuth2
clientRegistration이 null로 뜹니다.
디버그 모드 상태에서 보면, clientRegistrationRepository에 객체가 존재하고, 관련 설정값들이 확인이 되고있는데, 이것이 변수에 저장되지 못하고null이 되고 있습니다.따라서, clientId 같은 속성들도 확인이 불가능 합니다.컨트롤러에서는 해당 의존성을 사용하지 않으면 일단 기능은 작동되니 사용하고있지 않으나,컨트롤러에서 clientRegistration를 사용할수 없는 상황입니다.
-
미해결스프링 시큐리티 OAuth2
restfual api 개발할때
안녕하세요 선생님. 지금가지 선생님의 강의를 바탕으로 oauth 를 사용하는 프로젝트를 구축하는데 있어 궁금점이 생겨 질문드립니다.소셜로그인 인증 챕터 부분에서는 전형적인 session 인증 방식인데 restful api 서버 개발시에는 어떻게 설정해야할까요? 대안으로 찾아본바 successHandler 를 커스텀하게 설정하여 jwt 로 암호화해서 서버 api로 리다이렉트 시 쿼리파라미터에 jwt를 넣어 프론트에게 jwt 를 전달하는데 이 방식이 맞나요?또한 강의에서 restfual api 에 대해 다루신다면 어느 챕터에서 확인할 수 있을까요?
-
미해결스프링과 JPA 기반 웹 애플리케이션 개발
rest api + 관리자 페이지 제작 및 oauth 관련하여 질문드립니다.
안녕하세요. 현재 모바일 앱 연동을 위해 bearer 인증 기반으로 rest api 서버를 구축하였습니다. 회원가입은 firebase 의 id_token 인증을 통해 진행됩니다. 여기서 관리자페이지 제작을 하려고 하는데 보통 관리자 페이지는 api서버 프로젝트와 따로 프로젝트를 생성하여 만드는지 아니면 한 프로젝트에 모든 기능을 한 번에 구축하는지 일반적으로 현업에서는 어떤 구조로 이루어져있는지 궁금합니다. 프로젝트를 따로 가져가는 경우 공통된는 service 기능이나 domain은 중복해서 생성해야할거같아서 비효율적일거 같아 우선 저의경우 한 프로젝트에 앱 서버와 관리자 서버 모두 구축하는 방법을 진행해 봤는데 rest api 기반 시큐리티 설정과 웹 시큐리티 설정이 동시에 구축되는게 문제가 있는지 웹 로그인이 진행이 안됩니다. 다른 질문으론 oAuth2가 스프링에서 deprecated 된거같은데 선생님께서는 다른 방안을 어떻게 생각하고 계신가요?? 답변 부탁드립니다. 감사합니다!