티스토리 뷰
최근 프로젝트들의 경향을 살펴보면 자체 데이터를 기반으로 인증 로직을 구현하기보다는 대형 플랫폼의 인증 시스템을 기반으로 서비스를 구현한다.
이를 위해 필수적으로 알아햐하는 방식이 OAuth2.0 프로토콜이고 Spring Security에서 해당 방식을 어떤식으로 구현해서 사용할 수 있는지 공식문서를 기반으로 알아보고 구현해보려고 한다.
https://docs.spring.io/spring-security/reference/servlet/oauth2/index.html
OAuth2 :: Spring Security
To get started, add the spring-security-oauth2-client dependency to your project. When using Spring Boot, add the following starter: OAuth2 Client with Spring Boot implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' org.springframew
docs.spring.io
위 공식 문서를 참고하여 포스팅을 시작한다.
초기 설정
Google OAuth 2.0을 사용해서 로그인을 구현하기 위해서는 Google API Console에서 OAuth 2.0 credentials을 얻어야한다.
https://console.cloud.google.com/welcome?organizationId=0
Google 클라우드 플랫폼
로그인 Google 클라우드 플랫폼으로 이동
accounts.google.com
우선 위 링크에 접속해서 새로운 프로젝트를 만든다.
위 화면에서 API 및 서비스 메뉴를 클릭하여 접속한다.
위 화면과 같이 사용자 인증 정보 메뉴에 접속해서 동의 화면 구성 버튼을 클릭한다.
나는 예제 프로젝트에 누구나 Google API를 통해 로그인이 가능하도록 설정할 것이기 때문에 외부를 선택했다.
그리고 이후 화면에서는 앱 이름, 사용자 지원 이메일, 개발자 이메일만 입력하고 넘어가고 범위, 테스트 사용자 설정에서도 아무것도 입력하지 않고 동의 화면 구성을 끝낸다.
그리고 다시 사용자 인증 정보 메뉴로 접속하여 상단의 "+ 사용자 인증 정보 만들기" 메뉴 중 OAuth 클라이언트 ID를 선택한다.
위와 같이 애플리케이션 유형은 웹 애플리케이션으로 선택하고 프로젝트 이름을 입력해준다.
그리고 승인된 JavaScript 원본에는 서버 주소와 포트를 입력해주고 승인된 리디렉션 URI에는 서버 접속 정보에 /auth/google path를 추가해서 설정해준다.
(Redirect URI는 사용자가 구글 인증 및 OAuth Client 동의 페이지에서 권한을 얻은 후 리다이렉팅되는 경로이다)
이렇게 클라이언트 ID와 클라이언트 보안 비밀번호를 생성하게 되는데 이 정보를 가지고 Google과 OAuth2.0 인증을 수행하게 된다.
application.yml 설정
spring:
security:
oauth2:
client:
registration:
google:
client-id: google-client-id
client-secret: google-client-secret
생성된 클라이언트 ID와 보안 비밀번호를 application.yml에 위와 같이 설정한다.
프로젝트를 기동하고 나서 localhost:8080으로 접속하면 위와 같이 자동 생성되는 구글 로그인 페이지를 만날 수 있다.
우선 localhost:8080으로 접속하면 Response Header의 Location 값의 주소로 리다이렉션이 되도록 302 Found Status로 응답한다.
리다이렉션된 요청을 다시 호출하게 되더라도 302 Found Status로 응답되며 이 때 다음 리다이렉션 URI는 구글 API이다.
구글 API를 호출해서 로그인 뷰에 해당하는 HTML을 받게 된다.
CommonOAuth2Provider
CommonOAuth2Provider는 자주 사용되는 provider의 client property들을 미리 정의해둔 것이다.
위의 구현을 보면 authorization-uri, user-info-url 등을 따로 설정하지 않아도 기본 값을 CommonOAuth2Provider에서 제공한다.
그렇기 때문에 applicaion.yml에 client-id와 client-secret만 정의하더라도 정상적으로 동작할 수 있었다.
Spring Boot에서 OAuth2 Client Auto-Configuration
OAuth2ClientAutoConfiguration 클래스는 스프링 부트에서 아래와 같은 방식으로 OAuth Client 자동 설정의 역할을 수행한다.
- OAuth Client property 기반의 ClientRegistration으로 구성된 ClientRegistrationRepository 빈을 등록
- httpSecurity.oauth2Login()을 통해 OAuth 2.0 Login의 활성화하여 SecurityFilterChain 빈을 등록
ClientRegistrationRepository 빈 등록
@Configuration
public class OAuth2LoginConfig {
@Bean
public ClientRegistrationRepository clientRegistrationRepository() {
return new InMemoryClientRegistrationRepository(this.googleClientRegistration());
}
private ClientRegistration googleClientRegistration() {
return ClientRegistration.withRegistrationId("google")
.clientId("google-client-id")
.clientSecret("google-client-secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.redirectUri("{baseUrl}/login/oauth2/code/{registrationId}")
.scope("openid", "profile", "email", "address", "phone")
.authorizationUri("https://accounts.google.com/o/oauth2/v2/auth")
.tokenUri("https://www.googleapis.com/oauth2/v4/token")
.userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo")
.userNameAttributeName(IdTokenClaimNames.SUB)
.jwSetUri("https://www.googleapis.com/oauth2/v3/certs")
.clientName("Google")
.build();
}
}
SecurityFilterChain 빈 등록
@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.anyrequest().authenticated()
)
.oauth2Login(Customizer.withDefaults());
return http.build();
}
}
HttpSecurity.oauth2Login() 메서드는 OAuth 2.0 로그인을 위한 설정들을 제공하며, 각 프로토콜 그룹에 대응하는 엔드포인트들을 설정할 수 있다.
예를 들어 oauth2Login().authorizationEndpoint()는 인가 엔드포인트를 설정하고, oauth2Login().tokenEndpoint()는 토큰 엔드포인트를 설정한다.
@Configuration
@EnableWebSecurity
public class Oauth2LoginSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.oauth2Login(oauth2 -> oauth2
.clientRegistrationRepository(clientRegistrationRepository())
.authorizedClientRepository(authorizedClientRepository())
.authorizedClientService(authorizedClientService())
.loginPage("/login")
.authorizationEndpoint(authorization -> authorization
.baseUri(authorizationRequestBaseUri())
.authorizationRequestRepository(authorizationRequestRepository())
.authorizationRequestResolver(authorizationRequestResolver())
)
.redirectionEndpoint(redirection -> redirection
.baseUri(authorizationResponseBaseUri())
)
.tokenEndpoint(tokenEndpoint -> tokenEndpoint
.accessTokenResponseClient(accessTokenResponseClient())
)
.userInfoEndpoint(userInfo -> userInfo
.userAuthoritiesMapper(userAuthoritiesMapper())
.userService(oauth2UserService())
.oidcUserService(oidcUserService())
)
);
return http.build();
}
}
OAuth 2.0 인증 프레임워크에서는 해당 프로토콜이 동작하기 위한 엔드포인트를 설정하도록 정의한다.
위 코드의 oauth2Loing()의 용도는 이와 같은 엔드포인트를 설정하는 것이다.
다음 글: https://gojs.tistory.com/61
OAuth 2.0 with Spring Security (2) - 추가적인 로그인 설정
https://gojs.tistory.com/60 OAuth 2.0 with Spring Security (1) - 기본 로그인 구현하기최근 프로젝트들의 경향을 살펴보면 자체 데이터를 기반으로 인증 로직을 구현하기보다는 대형 플랫폼의 인증 시스템을
gojs.tistory.com
'공부 > Spring Security' 카테고리의 다른 글
OAuth 2.0 with Spring Security (3) - 클라이언트 어플리케이션 구성하는 방법 (0) | 2024.11.11 |
---|---|
OAuth 2.0 with Spring Security (2) - 추가적인 로그인 설정 (3) | 2024.10.27 |
Spring Security 동작 원리 및 보안 기본 (0) | 2024.06.23 |