OAuth / / 2024. 12. 17. 23:57

OAuth 2.0 액세스 토큰 발급 방법

1. OAuth2 인증 서버 설정 (SecurityConfig)

SecurityConfig 클래스는 OAuth2 인증 서버와 클라이언트를 설정하는 코드입니다.

코드 설명

@Configuration
public class SecurityConfig {

  // 1. 인증 서버 필터 체인 설정
  @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();
  }

  // 2. 기본 시큐리티 필터 체인 설정
  @Bean
  @Order(2)
  public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
    http.formLogin(Customizer.withDefaults());
    http.authorizeHttpRequests(c -> c.anyRequest().authenticated());
    return http.build();
  }

  // 3. 사용자 정보 설정 (InMemoryUserDetailsManager)
  @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();
  }

  // 4. OAuth2 클라이언트 설정
  @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);
  }

  // 5. JWT 키 설정
  @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();
    return new ImmutableJWKSet<>(new JWKSet(rsaKey));
  }

  // 6. 인증 서버 세팅
  @Bean
  public AuthorizationServerSettings authorizationServerSettings() {
    return AuthorizationServerSettings.builder().build();
  }

  // 7. JWT 토큰 커스터마이징
  @Bean
  public OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer() {
    return context -> {
      JwtClaimsSet.Builder claims = context.getClaims();
      claims.claim("priority", "HIGH");
    };
  }
}

2. Code Verifier 생성 (PKCE)

SecureRandom을 사용하여 Code Verifier를 생성합니다.

코드

package main;

import java.security.SecureRandom;
import java.util.Base64;

public class GenerateVerifier {

  public static void main(String[] args) {
    System.out.println(generateVerifier());
  }

  public static String generateVerifier() {
    SecureRandom secureRandom = new SecureRandom();
    byte[] code = new byte[32];
    secureRandom.nextBytes(code);
    return Base64.getUrlEncoder().withoutPadding().encodeToString(code);
  }
}

결과 예시:


3. Code Challenge 생성

SHA-256을 사용하여 Code Verifier를 기반으로 Code Challenge를 생성합니다.

코드

package main;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class GenerateChallenge {

  public static void main(String[] args) {
    String verifier = "Oz85Ph-hZO88HAfqoSm0mix0on7pjQGMLoDVmqMBVhE";
    System.out.println(generateChallenge(verifier));
  }

  public static String generateChallenge(String verifier) {
    try {
      MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
      byte[] digested = messageDigest.digest(verifier.getBytes());
      return Base64.getUrlEncoder().withoutPadding().encodeToString(digested);
    } catch (NoSuchAlgorithmException e) {
      throw new RuntimeException(e);
    }
  }
}

결과 예시:


4. 인증 요청

브라우저에서 다음 URL에 접속하여 로그인 페이지를 띄웁니다.

  • ID : bill
  • Password : password
http://localhost:8080/oauth2/authorize?response_type=code&client_id=client&scope=openid&redirect_uri=https://www.manning.com/authorized&code_challenge=위에서 생성한 Challenge Code&code_challenge_method=S256

결과 예시:

결과 예시:


5. POST 요청으로 토큰 발급

Postman에서 다음과 같이 설정합니다.

  1. URL: http://localhost:8080/oauth2/token
  2. Method: POST
  3. Authorization:
    • Auth Type: Basic Auth
    • Username: client
    • Password: secret
  4. Headers:
    • Authorization: Basic Y2xpZW50OnNlY3JldA== (Base64로 인코딩된 client:secret)
    • Content-Type: application/x-www-form-urlencoded
  5. Body:
    • grant_type: authorization_code
    • code: URL에서 발급받은 인증 코드
    • redirect_uri: https://www.manning.com/authorized
    • client_id: client
    • code_verifier: 위에서 생성한 Code Verifier

6. 응답 예시


요약

  1. Code Verifier 생성
  2. Code Challenge 생성
  3. 브라우저 URL로 로그인
  4. Postman에서 토큰 요청 및 응답 확인

'OAuth' 카테고리의 다른 글

인가 코드 그랜트 타입과 클라이언트 크레덴셜 그랜트 타입  (0) 2024.12.18
Client Credentials Grant Type  (0) 2024.12.18
Spring Authorization Server 구성  (0) 2024.12.17
Authorization Code  (0) 2024.12.17
Proof Key(PKCE)  (0) 2024.12.17
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유