on
[ Spring Boot ] JWT를 이용한 OAuth2 설정
[ Spring Boot ] JWT를 이용한 OAuth2 설정
OAuth2 구성요소
Authorization Server ( 권한 서버 )
Client를 등록하고, 권한을 관리해주는 서버
인증과정 (Authorized Grant Types) , 토큰 방식을 정의
Access Token, Refresh Token 을 발급/재발급
Resource Server
OAuth2 서비스를 제공하고 자원을 관리하는 서버
들어오는 OAuth2 토큰 ( Access Token ) 을 통해 자원 ( URL 경로 및 Resource ID ) 요청을 필터링
Client
API 서비스 ( Resoruce Server가 제공 )를 이용하는 어플리케이션 또는 서비스
Access Token
Authorization Server로 부터 발급 받은 인증 토큰
Resource Server에 전달하여 서비스를 제공받을 수 있도록 함
JWT ( JSON Web Tokens ) 로 이용가능
Resource Owner
Resoruce Server의 계정을 가지고 있는 사용자
소유한 Role에 따라 자원 접근 권한이 다름
OAuth2 플로우
Access Token 발급
User ( Resource Owner ) - Regular Web App ( Client ) - Auth0 Tenant ( Authorization Server )
API 서비스 요청 ( with Access Token )
User ( Resource Owner ) - Regular Web App ( Client ) - Your API ( Resource Server )
Authorization Server 구성
config/AuthorizationServerConfig.java
@Configuration @EnableAuthorizationServer public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
승인된 client 설정 / 권한 승인 방식 ( Authorized Grant Type) 설정
@Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("cello") // client 이름 .secret("{noop}secret") // client 시크릿 .authorizedGrantTypes("refresh_token", "password", "client_credentials") // 권한 승인 방식 설정 .scopes("webclient"); }
토큰 인증 방식 설정
@Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain(); tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtTokenEnhancer, jwtAccessTokenConverter)); endpoints.tokenStore(tokenStore) .accessTokenConverter(jwtAccessTokenConverter) .tokenEnhancer(tokenEnhancerChain) .authenticationManager(authenticationManager) .userDetailsService(userDetailsService); }
Resource Server 구성
config/ResourceServerConfig.java
마이크로 서비스에서는 자원을 가지는 각 서비스마다 설정
@Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
각 자원에 대한 필터링 설정
@Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers(HttpMethod.GET, "/test/rs") // /test/rs 에 대한 GET 요청은 .hasRole("ADMIN_001") // "ADMIN_001" 가진 사용자만 가능하다. .anyRequest() // 모든 요청은 .authenticated(); // 모든 요청은 인증이 필요하다. }
/test/rs 에 대한 GET 요청은 "ADMIN_001" 가진 사용자만 가능하다.
모든 요청은 인증이 필요하다.
WebSecurity 구성
config/AuthorizationServerConfig.java
@Configuration public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
사용자 ( Resource Owner ) 및 Role 구성
일반사용자 - "USER_001" role 만 소유
관리자 - "USER_001" 과 "ADMIN_001" role 소유
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder(); auth.inMemoryAuthentication() .withUser("yskim") .password("{noop}1234") .roles("USER_001") .and() .withUser("cello") .password("{noop}1234") .roles("USER_001", "ADMIN_001"); }
JWT 토큰 구성
@Configuration public class JWTTokenStoreConfig {
토큰 서비스의 구현체 설정
스프링 시큐리티에 있는 기본 토큰 서비스의 구현체 사용
@Bean @Primary public DefaultTokenServices tokenServices () { DefaultTokenServices defaultTokenServices = new DefaultTokenServices(); defaultTokenServices.setTokenStore(tokenStore()); defaultTokenServices.setSupportRefreshToken(true); return defaultTokenServices; }
토큰 변환 방법 정의
중요한 점은 토큰을 서명하는 서명 키 설정한다는 점
@Bean public JwtAccessTokenConverter jwtAccessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey("jwt-secret-key-123"); // 서명키 설정, TO-DO: 비대칭키로 전환 必 return converter; }
토큰의 확장
@Bean public TokenEnhancer jwtTokenEnhancer() { return new JWTTokenEnhancer(); }
config/JWTTokenEnhancer.java
public class JWTTokenEnhancer implements TokenEnhancer { @Override public OAuth2AccessToken enhance(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication) { Map additionalInfo = new HashMap<>(); String celloUid = "cello-uid-123-" + oAuth2Authentication.getName(); additionalInfo.put("cello-uid", celloUid); // JWT 토큰에 추가 될 내용. ((DefaultOAuth2AccessToken)oAuth2AccessToken).setAdditionalInformation(additionalInfo); return oAuth2AccessToken; } }
참고 사이트
from http://arthur.tistory.com/33 by ccl(A) rewrite - 2021-12-21 16:01:01