-
Spring security 5 OAuth2 공부한거project 2022. 5. 6. 22:46
Spring security 5 OAuth2 workflow 에 대해 다시 정리하고자 한다. (틀린 부분 더 있을거 같다. 점점 고치자.)
Spring security 5 는 인증/인가에 대한 framework 로 OAuth2 기능 중 Client, Resource server 를 제공한다. Authorization server 는 sub-project 로 제공한다.
Client, resource server 기능을 이용하여 사용자 인증과 외부 resource server 로의 client 요청 기능을 구현할 수 있다. 예를 들어 API 서버를 인증된 사람만 쓸 수 있게 하고 싶다. API 중엔 외부 resource server 에서 가져오는 기능이 있다. 이런 경우에 두 기능을 이용해서 구현이 가능하다.
위에 노란 부분의 워크플로우를 적어보면 다음과 같다.
(코드를 아래처럼 짰다.. 분명 나중에 보면 이상한 코드겠지)<Client>
- 사용자를 authorization uri 로 보낸다. (프론트엔드가 보낼 수도 있고 default 는 redirect)
- 사용자는 구글 로그인 페이지에서 로그인하고 구글은 CODE / TOKEN 를 redirect uri 로 보낸다.
- Client 는 token uri 에 CODE / TOKEN 을 access_token 으로 바꿔먹는다.
- Client 에 access_token 을 저장하고 나중에 꺼내 쓸 수 있다. (default 는 in-memory 로 껐다 키면 없어진다. db나 redis로 override 해야 한다. )
- OAuth2UserService 는 access_token 을 가지고 userinfo endpoint 에 request 를 보내 정보를 가져온다. (ID, name, 등등) default(servlet) 는 rest template 으로 가져온다.
- 잘 가져오면 로직을 처리한다. 예를 들어 이걸로 회원가입 기능을 대신하고 싶으면 실제 서버 db에 Entity 를 persist 한다.
- Success handler 로 보내지고 JWT access token 등으로 인증 유지 로직을 한다.
<Resource Server>
- 위의 과정을 거친 사용자는 JWT 를 가지고 서버에 접근한다.
- Servlet 에서 들어가다가 Security filter chain 을 마주칠 것이다. Authentication filter 에서 auth request token 으로 convert 하여 auth manager 에게 요청하면 auth provider 가 Granted Authority 를 부여하고 set authenticated 된 (이는 auth manager 였나 만 가능하다. interface 가 강제하고 있다.) Authentication 객체를 생성해서 리턴하면 security context 에 넣어준다. (thread-local, 쓰고 나중에 context clear 메소드를 불러야 memory leak 가 안난다, -> https://stackoverflow.com/questions/67577715/is-there-any-scenario-where-securitycontext-wont-get-cleared-from-threadlocal-a 프레임워크 코드에서 finally block으로 해제해준다. )
- authenticated 된 사용자만 .authenticated 로 설정된 API 에 접근할 수 있다.
<Client>
- 앞에서 저장했던 Client 를 가져와서 외부 resource server 에 요청을 보낸다. WebClient 와 integrated 되어 있어 OAuth2Client 를 꺼내 resource server에 request 를 보낼 수 있다. 요청하려면 인증과 비슷하게 Manager 가 허락해야 할 수 있고, servlet 요청의 경우 config 를 통해 default OAuth2 client manager 를 Bean 등록하여 쓸 수 있다. cron 으로 스케쥴링하는 등 정상적인 servlet 요청이 아닌 explict 한 경우 AuthorizedClientServiceOAuth2AuthorizedClientManager 를 등록해서 써야 한다.
- 데이터를 받아오고 servlet 일 경우 webclient 를 block 하여 동기처리를 하고 정보가 오면 써먹는다.
cf) 로그아웃? access token 을 보내지 않으면 인증되지 않은 사용자로 표시될 것이다. 서버에서는 간접적으로 access token을 persist 해서 blacklist 하는 방법이 있는데 리소스 낭비이다. 클라이언트에서 안보내면 된다.
위에서 authorization uri, token uri, redirect uri, 등은 application.properties 로 config 할 수 있다. 조금씩 더 알아보자.
Config 는 application.properties 에 registration / provider 로 적는 것으로 시작한다.
Authorization endpoint, Token endpoint, Redirection endpoint, Userinfo endpoint 등을 설정해야 하며, 거기에 적힌 주소대로 가서 request 를 해준다.
설정을 어떻게 해야 할까? OAuth2 제공 사이트 (google, kakao, 등등, 이후 vendor 라고 하자.) google, github, facebook 등은 스프링이 설정을 해줘서 client id 랑 client secret 만 적으면 설정이 된다. 그외에 유명한 vendor 들은 블로그 글이 많다.
그외에는 설정하기가 까다롭다. 이상하게 설정하면 컴파일러가 잡아줄 때도 있고 런타임에 오류메시지도 없이 에러가 난다. (예를들어, 트위터는 Oops! your mistake 이런 메시지가 뜬다) 어떻게 작동하는지 조금 더 알아보고 싶은 마음이 생겼다.
vendor 사이트 에서 보면 token_uri, authorization endpoint, 등등을 적어놓는다. 그걸 보고 올바르게 설정해야 한다. -> OAuth framework 대로 구성된 point 들이다.
Redirect uri, authorization endpoint 들의 Default 값들은 클래스에 적혀있다. 수정하려면 override 나 따로 adapter 클래스가 있다.
DEFAULT_FILTER_PROCESSES_URI = "/login/oauth2/code/*"DEFAULT_AUTHORIZATION_REQUEST_BASE_URI = "/oauth2/authorization";OAuth2LoginConfigurer 에서 config 를 해준다. 무언가 값이 있으면 (if ... not null) 그걸로 config 해주고 아니면 default 로 config 해주는 방식이고
if (AuthorizationGrantType.AUTHORIZATION_CODE.equals(authorizationGrantType)) { this.responseType = OAuth2AuthorizationResponseType.CODE; } else if (AuthorizationGrantType.IMPLICIT.equals(authorizationGrantType)) { this.responseType = OAuth2AuthorizationResponseType.TOKEN; }application.yml 에 authorization-grant-type: authorization_code 로 적으면 oauth2 페이지에서 "CODE" 로 적혀있는 그걸로 설정해 준다. implicit 으로 적으면 TOKEN 으로, client_credentials 는 다른 방식인가보다.
...(계속)
'project' 카테고리의 다른 글
SnsChats - 개발 일기 (0) 2022.05.25 Docker 시작 (0) 2022.05.22 테스트 코드의 중요성, TDD (0) 2022.04.30 Spring security > 5.1 jwt 인증하는 방법 (0) 2022.04.25 spring security oauth2 로그인 구현 (개발 로그) (0) 2022.03.30