✔ Spring Boot의 자동 구성을 이용한 OAuth2 인증 설정
- Spring Boot의 자동 구성을 이용한 방법
- SecurityConfiguration(V1)
- (1) 인증된 request에 대해서만 접근하도록 추가
- (2) OAuth2 로그인 인증 활성화
✔ OAuth2 클라이언트 등록 정보 추가
- application.yml
- (1) OAuth2 클라이언트 생성 시, 클라이언트 ID
- (2) 클라이언트 보안 비밀번호, 클라이언트 Secret
- 실무에서는 시스템 환경 변수에 설정
✔ 실행 후 접속
✔ Configuration을 통한 OAuth2 인증 설정
- 자동 구성을 통한 설정 뿐만 아니라, Configuration을 통해 Bean을 등록함으로써 OAuth2의 인증을 설정할 수 있다.
- SecurityConfiguration(V2)
- (1), (2) application.yml 파일에 설정되어 있는 구글의 ID와 Secret을 로드
- (3)
ClientRegistrationRepository
를 Bean으로 등록
- Spring Boot 자동 구성 기능을 이용할 경우, 내부적으로 Bean이 생성되지만, 지금은 Configuration을 통해 직접 등록
- (3-1) private 메서드인
clientRegistration()
을 호출하여 인스턴스를 리턴 받는다.- (3-2) 구현 클래스인 InMemoryClientRegistrationRepository의 인스턴스를 생성
- (4) ClientRegistration 인스턴스를 생성하는 private 메서드
- (4-1) Spring Security에서는
CommonOAuth2Provider
enum 제공. 내부적으로 빌더 패턴을 이용해 ClientRegistration 인스턴스를 제공하는 역할을 한다.- ClientRegistration은 OAuth2 Client에 대한 등록 정보를 표현하는 객체
구글의 API 콘솔에서 등록했던 정보가 포함
1. SecurityContext를 이용하는 방법
- HomeController(V2)
- (1) 인증된 Authentication 객체를 통해 Principal 객체를 얻는다.
OAuth2로 로그인 인증을 수행했으므로 Principal은OAuth2User
객체로 캐스팅 가능- (2)
OAuth2User
객체에 저장되어 있는 사용자 정보 중 사용자의 이메일 정보를 얻고 있다.- 인증 후, 정상적으로 이메일 주소가 출력된다면 인증 성공
2. Authentication 객체를 핸들러 메서드 파라미터로 전달 받는 방법
- HomeController(V3)
3. OAuth2User를 파라미터로 전달 받는 방법
- HomeController(V4)
1. OAuth2AuthorizedClientSevice를 DI 받는 방법
- HomeController(V5)
OAuth2AuthorizedClientService
는 권한을 부여받은 Client 를 관리하는 역할
이것을 이용하여OAuth2AuthorizedClient
가 보유하고 있는 Access Token에 접근할 수 있기 때문에 (1) 같이 DI 받는다.- (2)
OAuth2AuthorizedClient
객체를 로드 . loadAuthorizedClient() 를 호출하면 내부적으로 Repository에서OAuth2AuthorizedClient
를 조회한다.- (3) AccessToken 객체를 얻는다
- (3-1) Access Token의 문자열 출력
- (3-2) Token의 타입 출력
- (3-3) 토큰으로 접근할 수 있는 리소스의 범위 목록 출력
- (3-4) 토큰의 발행일시
- (3-5) 토큰의 만료일시
2. OAuth2AuthorizedClient를 핸들러 메서드의 파라미터로 전달 받는 방법
- (1)
OAuth2AuthorizedClientRepository
에 저장되어 있는OAuth2AuthorizedClient
를 파라미터로 전달 받음.
- 하나 이상의 핸들러 메서드에서
OAuth2AuthorizedClient
사용해야 한다면OAuth2AuthorizedClientService
를 DI 받아서 사용하는 것이 바람직함.
http://localhost:8080/oauth2/authorization/google
로 request를 전송,OAuth2LoginAuthenticationFilter
가 처리http://localhost:8080/login/oauth2/code/google
) 를 쿼리 파라미터로 전달http://localhost?access_token={jwt-access-token}&refresh_token={jwt-refresh-token}
) 으로 리다이렉트 한다.1. 아파치 웹서버 설치
Apache24
디렉토리를 C:\ 디렉토리로 이동ServerName localhost:80
2. Frontend 샘플 애플리케이션을 아파치 웹 서버에 배포
C:\Apache24\htdocs
디렉토리로 위치
- index.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>OAuth2 + JWT Frontend</title> </head> <body> <h2>Welcome to OAuth 2.0 + JWT Spring Security</h2> <a href="http://localhost:8080/oauth2/authorization/google">Google로 로그인</a> </body> </html>
- Google로 로그인 버튼을 클릭하면 백엔드 애플리케이션으로 request가 전송되고 로그인 화면 오픈
- receive-token.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>OAuth2 + JWT My page</title> </head> <body> <script type="text/javascript"> let accessToken = (new URL(location.href)).searchParams.get('access_token'); let refreshToken = (new URL(location.href)).searchParams.get('refresh_token'); localStorage.setItem("accessToken", accessToken) localStorage.setItem("refreshToken", refreshToken) location.href = 'my-page.html' </script> </body> </html>
- 백엔드 애플리케이션에서 전달 받은 jWT Access Token과 Refresh Token을 웹 브라우저의 LocalStorage에 저장한 후 , my-page.html로 이동
- my-page.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>OAuth2 + JWT My page</title> </head> <body> <h2>My Page</h2> <h3>아래의 토큰을 이용해서 Backend 애플리케이션의 리소스를 요청할 수 있습니다.</h3> <p> <span>Access Token: </span><span id="accessToken" style="color: blue"></span> </p> <p> <span>Refresh Token: </span><span id="refreshToken" style="color: blue"></span> </p> <script type="text/javascript"> let accessToken = localStorage.getItem('accessToken') let refreshToken = localStorage.getItem('refreshToken'); document.getElementById("accessToken").textContent = accessToken; document.getElementById("refreshToken").textContent = refreshToken; </script> </body> </html>
- LocalStorage에 저장된 JWT Access Token과 Refresh Token을 로드해서 웹 브라우저에 표시
1. JwtTokenizer 추가
- JWT 유닛 코드
2. application.yml 설정
- (1), (2) scope 값 직접 지정하면 해당 범위만큼의 리소스를 Client(백엔드) 에게 제공
3. JwtVerificationFilter 추가
- JWT 유닛 코드
4. AuthenricationSuccessHandler 구현
OAuth2 인증에 성공하면 호출되는 핸들러
JWT 생성하고, Frontend쪽으로 JWT를 전송하기 위해 리다이렉트 하는 로직 구현
(1)
SimpleUrlAuthenticationSuccessHandler
상속하면 리다이렉트를 손쉽게 할 수 있는getRedirectStrategy().sendRedirect()
와 같은 API 사용 가능(2) 필요한 객체 DI 받기
(3) Authentication 객체로부터 얻어낸 OAuth2User 객체로부터 Resource Owner의 이메일 주소 얻기
(4) CustomAuthorityUtils 이용해 권한 정보 생성
(5) Resource Owner의 이메일 주소를 DB에 저장
백엔드 애플리케이션의 리소스(커피정보, 주문정보) 와 연관 관계를 맺기 위해 최소한의 정보 관리(6) Access Token과 Refresh Token을 생성하여 Frontend 애플리케이션에게 전달하기 위해 Redirect 한다.
- (6-1), (6-2) JWT Access Token과 Refresh Token을 생성.
- (6-3) Frontend 애플리케이션 쪽의 URL 생성, createURI() 메서드에서
UriComponentBuilder
를 이용해 AccessToken과 RefreshToken을 포함한 URL 생성- 포트 설정을 하지 않으면 기본값은 80 포트
- (6-4) sendRedirect() 메서드를 이용해 프론트엔드 애플리케이션쪽으로 리다이렉트 한다.
SecurityConfiguration
(1) OAuth2 로그인 설정에 .successHandler() 를 통해 인증이 성공한 뒤 실행되는 핸들러 추가
OAuth2MemberSuccessHandler
객체를 생성하면서 OAuth2MemberSuccessHandler에서 필요한 의존 객체를 DI 하고 있다.(2) JwtVerificztionFilter를 OAuth2LoginAuthenricationFilter 뒤에 추가
5. 기타 회원 정보 등록 및 수정 로직이 수정됨.
https://github.com/codestates-seb/be-reference-spring-security-oauth2-basic
https://github.com/codestates-seb/be-reference-oauth2-frontend