1. OAuth2 Authorization Server란?
OAuth2 Authorization Server는 클라이언트 애플리케이션이 사용자 데이터에 접근할 수 있도록 액세스 토큰을 발급해 주는 서버입니다.
예를 들어, 사용자가 Google 로그인을 통해 특정 애플리케이션에 접근하는 경우, Google의 Authorization Server가 동작합니다.
1.1 핵심 개념
Authorization Grant Type
- 클라이언트가 사용자 데이터를 요청할 때 사용하는 방식입니다.
Authorization Code
: 인증 코드 발급 후 액세스 토큰 발급 (가장 많이 사용)Client Credentials
: 서버 간 통신 시 사용Password Grant
(Deprecated): 사용자 이름과 비밀번호를 직접 전달 (보안 취약)
- 클라이언트가 사용자 데이터를 요청할 때 사용하는 방식입니다.
JWT (JSON Web Token)
- 인증 및 권한 부여 정보를 포함하는 JSON 기반 토큰입니다.
- 클라이언트는 이 토큰을 통해 인증된 사용자임을 증명합니다.
- 서명을 통해 위변조를 방지합니다.
JWK (JSON Web Key)
- JWT 서명에 사용하는 공개 키와 비밀 키를 JSON 형식으로 표현한 키입니다.
OIDC (OpenID Connect)
- OAuth2를 확장한 표준으로, 사용자 ID 정보를 포함합니다.
- 예:
scope=openid
를 통해 사용자 정보를 요청합니다.
2. SecurityConfig 코드 분석
2.1 OAuth2 인증 서버 필터 체인
@Bean
@Order(1)
public SecurityFilterChain asFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(Customizer.withDefaults());
http.exceptionHandling(e ->
e.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
);
return http.build();
}
설명
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http)
- Spring이 제공하는 OAuth2 Authorization Server의 기본 보안 설정을 적용합니다.
- CSRF 보호, 세션 관리, 권한 검사 등의 보안을 설정합니다.
OIDC 지원
.oidc(Customizer.withDefaults())
: OpenID Connect를 활성화합니다.- 클라이언트는
scope=openid
를 통해 사용자 ID 정보를 요청할 수 있습니다.
예외 처리
- 인증되지 않은 요청이 들어오면
/login
페이지로 리디렉션합니다.
- 인증되지 않은 요청이 들어오면
2.2 기본 로그인 필터 체인
@Bean
@Order(2)
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.formLogin(Customizer.withDefaults());
http.authorizeHttpRequests(c -> c.anyRequest().authenticated());
return http.build();
}
설명
- 폼 로그인: 사용자가 기본 로그인 폼을 통해 인증합니다.
- 모든 요청 인증 필수:
anyRequest().authenticated()
를 통해 모든 요청에 대해 인증을 요구합니다.
2.3 사용자 인증 정보 설정
@Bean
public UserDetailsService userDetailsService() {
UserDetails userDetails = User.withUsername("bill")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(userDetails);
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
설명
UserDetailsService
- 인메모리에
bill
이라는 사용자 계정을 생성합니다. - 아이디:
bill
- 비밀번호:
password
- 역할:
USER
- 인메모리에
비밀번호 인코더
- NoOpPasswordEncoder는 암호화 없이 비밀번호를 사용합니다.
- 테스트용이며, 실제 운영에서는 BCrypt와 같은 안전한 방식 사용이 필요합니다.
2.4 클라이언트 등록 설정
@Bean
public RegisteredClientRepository registeredClientRepository() {
RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("client")
.clientSecret("secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.redirectUri("https://www.manning.com/authorized")
.scope(OidcScopes.OPENID)
.build();
return new InMemoryRegisteredClientRepository(registeredClient);
}
설명
RegisteredClient
- OAuth2 클라이언트를 설정합니다.
- Client ID: 클라이언트를 식별하는 값 (
client
) - Client Secret: 클라이언트 인증을 위한 비밀번호 (
secret
) - Grant Type:
AUTHORIZATION_CODE
- Redirect URI: 인증 완료 후 리디렉션할 주소
- Client ID: 클라이언트를 식별하는 값 (
- OAuth2 클라이언트를 설정합니다.
RegisteredClientRepository
InMemoryRegisteredClientRepository
를 사용해 클라이언트 정보를 메모리에 저장합니다.
2.5 RSA 키 쌍 생성 및 JWK 설정
@Bean
public JWKSource<SecurityContext> jwkSource() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
RSAKey rsaKey = new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString())
.build();
JWKSet jwkSet = new JWKSet(rsaKey);
return new ImmutableJWKSet<>(jwkSet);
}
설명
- RSA 키 쌍 생성
KeyPairGenerator
를 사용해 2048비트 RSA 키 쌍을 생성합니다.
- JWK 생성
- RSA 키를 JWK (JSON Web Key) 형식으로 변환합니다.
- ImmutableJWKSet
- JWT 서명에 사용할 키를 JWK 소스로 반환합니다.
2.6 JWT 커스터마이징
@Bean
public OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer() {
return context -> {
JwtClaimsSet.Builder claims = context.getClaims();
claims.claim("priority", "HIGH");
};
}
설명
OAuth2TokenCustomizer
: JWT에 커스텀 클레임을 추가합니다.- 예시로
"priority": "HIGH"
라는 클레임을 추가하여 특정 사용자 정보를 전달할 수 있습니다.
3. 결론 및 요약
이 SecurityConfig
클래스는 Spring Authorization Server를 기반으로 OAuth2 인증 서버를 설정하는 예제입니다.
핵심 기능 요약
OAuth2 Authorization Server
- 인증 및 액세스 토큰 발급을 처리합니다.
OIDC (OpenID Connect)
- 사용자 ID 정보 제공 (
scope=openid
).
- 사용자 ID 정보 제공 (
JWT 커스터마이징
- JWT에 추가적인 클레임 값을 넣습니다.
RSA 키 관리
- JWT 서명 및 검증을 위한 RSA 키 쌍을 생성하고 JWK 형식으로 설정합니다.
이 설정은 OAuth2와 OIDC 기반의 인증 서버를 구현하는 데 기초적인 예제를 제공합니다. 추가적으로 보안 강화를 위해 비밀번호 암호화 및 외부 저장소 사용을 고려할 수 있습니다.
'OAuth' 카테고리의 다른 글
Client Credentials Grant Type (0) | 2024.12.18 |
---|---|
OAuth 2.0 액세스 토큰 발급 방법 (0) | 2024.12.17 |
Authorization Code (0) | 2024.12.17 |
Proof Key(PKCE) (0) | 2024.12.17 |
투명 토큰(Transparent Token)과 불투명 토큰(Opaque Token) (1) | 2024.12.17 |