Spring Boot 3 & Spring Framework 6 - Section 19 : Spring Security JWT 관련 설정

이정수·2025년 3월 22일

Spring Security에서 Authentication Header에 자격증명을 담아서 로그인하는 방법
formLogin() 등의 인증방식과 다르게 Session이 필요없는 STATELESS 방식이므로, CSRF Protection을 설정 가능.

  • HTTP Basic Authentication : Basic Base64인코딩한ID:PW
    REST API의 보안에서 사용되는 가장 간단한 Authentication 방식.
    session을 사용하지 않는 stateless 특징으로 HTTP Request마다 Authentication 정보를 포함해야한다.
    ID:PWBase64로 인코딩하여 앞에 Basic을 명시한 Base64코드 ( Basic Base64코드 )을 HTTP RequestAuthorization Header로 포함하여 Authentication을 수행.

    Javascript에서는 window.btoa(id + ":" + pw)ID : PWBase64로 인코딩한 Base64코드를 생성한다.

    Basic Authenticationexpire date이 없으며, 사용자 정보도 포함하지않아 권한을 확인할 수 없다.
    Base64 Encoding을 사용하여 Decoding이 가능하며 암호화가 되지않아서 보안에 매우 취약.
    ▶ 현재는 REST API보안 시 주로 JWT 사용



  • Custom Token
    。사용자가 임의로 Token System을 구축.
    。 보안결함이 존재할 수 있는 위험성과 서비스 제공자와 소비자가 이해해야하는 단점이 존재.
    JWT 활용
  • JWT사용 시 Spring에서 정의해야할 Dependency
    • spring-boot-configuration-processor
      Spring Boot에서 @ConfigurationProperties가 선언된 Class를 자동으로 문서화를 수행하고 IDE에서 자동완성기능을 제공하는 Library.
      META-INF/spring-configuration-metadata.json 파일을 생성하여 문서를 자동화.
    <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
    </dependency>
    • spring-boot-starter-oauth2-resource-server
      Spring Boot ApplicationSpring Security와 통합하여 OAuth 2.0 Resource Server로 설정하는 Library.
      Maven
    <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
    </dependency>

    Gradle

    implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'

    OAuth 2.0 Resource Server :
    OAuth2.0 Authentication을 기반으로 Authenticated된 사용자에 대해서만 접근할 수 있도록 보호된 API를 제공하는 Server.
    ▶ 기존 ApplicationREST API가 노출되어있으므로, ApplicationOAuth 2.0 Resource Server로 설정하여 보호된 REST API를 제공하도록 설정됨.

    。 Client의 HTTP RequestAuthentication Header에 포함된 Access Token을 전달받아서 검증 후 Authentication을 수행하여 API에 접근.
    ▶ Dependency를 추가 시 Access Token ( = JWT , Opaque Token 등 )을 검증하여 AuthenticatedHTTP Request만 허용하도록 설정됨.

    • Resource Server : Access Token을 검증하여 HTTP Request를 허용 또는 거부.

    • Authorization Server : Access Token을 발급 및 관리


  • JWK ( JSON Web Key )
    Public Key 정보를 JSON Format으로 표현한 데이터구조.
    JWT Signature의 검증을 수행하기 위해서 Public Key가 필요하므로 주로 RSA방식의 JWTSignature를 검증 시 활용.

    JWK Set : 여러개의 Public Key를 포함하는 Public Key 목록
    JWK Set URI : JWK Set을 제공하는 URI
    JWT의 발행자와 검증자가 Public Key를 안전하게 공유하고 사용하는 용도로 이용됨.
    • JWK 사용 용도
      • JWK Set URI를 통한 JWK Set 제공
        Authentication ServerURI 접속 시 JWK Set를 제공하여 ClientJWK Signature를 검증할 수 있도록 함.
        ex ) https://example.com/oauth2/jwks :
        OAuth 2.0 Authentication Server가 제공하는 Public Key 목록.

      • JWT Signature 검증
        JWT를 사용하는경우, 서명검증을 수행하기 위해 Public Key가 필요하므로, JWK를 사용하여 안전하게 Public Key를 참조.

      • 자동화 Key 관리
        Public KeyJWK로 제공 시 여러 서버간 Public Key를 쉽게 공유 및 갱신이 가능.


    • JWK 구조
    {
      "kty": "RSA",
      "kid": "1234abcd",
      "use": "sig",
      "alg": "RS256",
      "n": "modulus_in_base64url",
      "e": "exponent_in_base64url"
    }
    • kty ( Key Type ) :
      Public Key의 Type을 지정 ( ex. RSA, EC )
      Public Key의 알고리즘 식별 시 필요

    • kid ( Key ID ) :
      Public Key의 고유 식별자
      JWK Set으로 여러 개의 Public Key를 제공하는 경우 식별용도로 활용됨.

    • use ( Key Use ) :
      Public Key의 용도를 지시.
      "use" : "sig" : 서명용 , "use" : "enc" : 암호화용 등.
      JWT는 주로 Signature의 검증으로 사용하므로 sig가 활용됨.

    • alg ( Algorithm ) :
      Public Key를 사용할 알고리즘을 지정 ( ex. RS256, RS512, ES256 )
      JWT Signature를 검증 시 사용할 알고리즘을 지정.

    • n ( Modulus ) :
      RSA Public Key에서 사용되는 Modulus값을 base64로 인코딩하여 설정.
      RSA에서 Public Key의 유효성을 결정하는 핵심요소.

    • e ( Exponent ) :
      RSA Public Key에서 사용되는 지수값을 base64로 인코딩하여 설정.

Spring Boot에서 JWT 실습 수행하기

  • OAuth2.0 Dependency 추가
    Gradle의 경우 build.gradle에 다음 구문을 정의 후 Reload 수행.
    implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'

  • JWT를 기반으로 Spring Security Configuration 을 수행하는 Class 생성
    。이전의 Spring SecurityConfiguration Class ( ex. HTTP Basic Authentication을 수행 )는 모두 삭제하거나 @Configuration을 삭제하여 비활성화.

    JWTSession을 사용하지않는 STATELESS이므로, Session 정책Session을 사용하지 않도록 설정 및 CSRF 비활성화.

    HTTPSecurity객체.oauth2ResourceServer(람다식)를 활용하여 OAuth2.0 Resorce Server를 이용하여 HTTP RequestAuthentication Header에 포함된 Access Token ( ex. JWT, Opaque Token 등 )을 전달받아 JWT Decoder의 Instance를 통해 Decrypt를 수행 및 유효성 검증을 수행하여 Authentication을 설정하여 API에 접근이 가능하도록 설정.

    JwtDecoder Interface의 구현체( = NimbusJwtDecoder )의 Instance를 생성하는 @Bean Method를 정의하여 EncryptJWT TokenDecrypt 후 유효성을 검증하는 역할을 수행.
    JWTDecryption 및 검증하는 용도로 활용되므로, JWK URI에서 Pulbic Key를 가져와서 Decrypt를 수행하는 JwtDecoder Instance를 생성하여 반환.

    。해당 @Bean jwtDecoder() Method를 통해 JwtDecoder instance를 생성 후 Spring Context에 저장하며 Spring SecurityOAuth2.0 Resource Server로 동작 시 JWT Token을 자동으로 검증하지만, 기본 설정으로 JWT를 검증하는 JWK Set을 알 수 없으므로, auth server에서 제공하는 공개키인 JWK Set를 통해 비대칭키인 JWT의 서명을 검증.
// JwtSecurityConfiguration.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class JwtSecurityConfiguration {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // 모든 HTTP Request에 대해 인증된 사용자만 접근가능하도록 접근권한을 부여.
        return http.authorizeHttpRequests((auth)->{
                    auth.anyRequest().authenticated();
                })
                // HTTP Basic Authentication 활성화
                .httpBasic(Customizer.withDefaults())
                // Session Policy를 Session 비활성화로 설정.
                .sessionManagement((session)->{
                    session.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
                })
                // CSRF 비활성화
                .csrf((csrf)->{
                    csrf.disable();
                })
            	// Oauth2.0 Resource Server를 통해 HTTP Request의 Authentication Header에 포함된
                // JWT Token을 커스텀 JWT Decoder를 통해 Decrypt 및 검증을 수행.
                .oauth2ResourceServer(oauth2 -> oauth2
                        .jwt(jwt -> jwt
            					// 커스텀 Decoder를 통해 생성된 JwtDecoder Instance를 활용.
                                .decoder(jwtDecoder()) 
                        ))
                // HttpSecurity Instance를 생성
         		// → SecurityFilterChain instance로서 return.
                .build();
    }
    @Bean
    public JwtDecoder jwtDecoder() {
        return NimbusJwtDecoder.withJwkSetUri("https://auth-server-url/.well-known/jwks.json").build();
    }
}
  • JWT 검증을 수행하기위한 RSA 기반의 RSA Public Key, RSA Private Key를 생성 및 해당 RSA Public Key를 기반으로 JWTDescrypt하는 JWT Decoder @Bean Method 구축하기
    • RSA 암호화 알고리즘의 Key Pair instance를 생성하는 @Bean Method 정의하기
      RSA 암호화 알고리즘을 통해 Public Key , Private Key로 구성된 Key Pair 객체 생성.
      oepnssl 또는 java.security.KeyPairGenerator 활용.

      @Configuration이 선언된 Configuration ClassKey Pair instance를 생성하여 반환하는 @Bean Method 정의.
      @Bean를 선언하여 Spring에 의해 KeyPair을 필요로하는 Method의 매개변수로 자동으로 Auto Wiring.
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.NoSuchAlgorithmException;
    	@Bean
        public KeyPair generateKeyPair() throws NoSuchAlgorithmException {
        	// RSA 알고리즘을 사용한 KeyPairGenerator instance 생성
            KeyPairGenerator keyPairGenerator =  KeyPairGenerator.getInstance("RSA");
        	// 2048 bit의 키 크기 설정
            keyPairGenerator.initialize(2048);
        	// KeyPair instance 생성
            return keyPairGenerator.generateKeyPair();
        }

    RSA 암호화 알고리즘으로 생성된 2048 bit 크기의 Public Key, Private Key를 포함한 KeyPair instance가 생성되어 Spring Bean으로 return.

    • RSA 암호화 알고리즘으로 생성된 KeyPair instance를 이용하여 RSAKey instance 생성
      Nimbus JOSE+JWT 라이브러리를 활용하여 RSAKey instance 생성.
      RSAKey instance에 RSA 암호화 알고리즘의 Private Key, Public Key, Key ID를 정의 및 생성하여 return하는 @Bean Method를 생성.
      UUID.randomUUID().toString() : 중복되지않는 랜덤한 UUID를 문자열로서 생성.
    import java.security.interfaces.RSAPublicKey;
    import java.util.UUID;
    // KeyPair을 return하는 @Bean Method로부터 Auto Wiring되어 전달됨.
        @Bean
        public RSAKey generateRSAKey(KeyPair keyPair){
            return new RSAKey
      				// RSAKey KeyPair객체의 Public Key instance를 RSAPublicKey로 casting하여 설정.
                    .Builder((RSAPublicKey)keyPair.getPublic())
      				// RSAKey KeyPair객체의 Private Key instance를 RSAPrivateKey로 casting하여 설정.
                    .privateKey((RSAPrivateKey)keyPair.getPrivate())
      				// 중복되지않는 UUID를 통한 kid를 지정.
                    .keyID(UUID.randomUUID().toString())
                    .build();
        }

    RSA 암호화 알고리즘으로 생성한 KeyPair 객체의 PublicKeyPrivateKeyRSAKey instance를 새로 생성 및 casting 후 적용한 RSAKey instance 생성.
    JWKSet instance에 여러개의 Public Key를 정의하고자 keyID 지정.

    • RSAKey instance를 이용하여 JWKSource ( JSON Web Key Source )을 생성하는 @Bean Method 정의
      RSAKey instance를 통해 JWKSet instance 생성 후 JWKSource instance를 생성하는 @Bean Method 생성
      RSAKey를 return하는 @Bean Method로부터 AutoWiring하여 공급.

      JWKSet instance로 JWKSource instance 생성 시 JWKSource Interface의 instance를 생성 및 Abstract Method get()를 상속하여 JWKSelector.select(JWKSet객체)를 return하도록 구현.
      Abstract Method get()JWKSet으로부터 JWKSelector를 통해 특정조건에 부합하는 JWK를 선택하여 List<JWK>로 반환.
    	// RSAKey를 return하는 @Bean Method로부터 매개변수로 AutoWiring.
    	@Bean
        public JWKSource generateJWKSource(RSAKey rsaKey){
            // RSAKey instance를 활용하여 JWKSet instance 생성
            JWKSet jwkSet = new JWKSet(rsaKey);
            // JWKSource Interface의 instance 생성
            JWKSource jwkSource = new JWKSource(){
                // 생성자에서 JWKSource의 Abstract Method를 상속 및 구현
                @Override // 원본 Interface에서 상속의 명시적 표현
                public List<JWK> get(JWKSelector jwkSelector, SecurityContext securityContext) throws KeySourceException {
                    // JWKSet instance로부터 JWKSelector를 통해 특정조건에 부합하는 JWK를 List<JWK>로 반환.
                    return jwkSelector.select(jwkSet);
                }
            };
            return jwkSource;
        }
      • 람다식을 활용한 간단한 표현
      // RSAKey를 return하는 @Bean Method로부터 매개변수로 AutoWiring.
          @Bean
          public JWKSource<SecurityContext> generateJWKSource(RSAKey rsaKey){
              // RSAKey instance를 활용하여 JWKSet instance 생성
              JWKSet jwkSet = new JWKSet(rsaKey);
              // JWKSet의 특정조건에 부합하는 List<JWK>를 반환하는 get() Abstract Method가
              // 상속되어 구현된 JWKSource Interface의 instance 생성.
              return ((jwkSelector, securityContext) -> jwkSelector.select(jwkSet));
          }
      • Interfaceabstract method만을 포함하며 Interface를 상속 시 Interface 내부의 메소드를 모두 구현해야한다.


    • JWTDecryption을 수행하는 JwtDecoder의 instance를 반환하는 @Bean Method 정의
      JwtDecoder instance의 경우 구현 Class인 NumbusJwtDecoderNumbusJwtDecoder.withPublicKey(RSAPublicKey객체) Method를 통해 생성하여 반환.

      NimbusJwtDecoder.withPublicKey(RSAPublicKey객체) :
      RSA 암호화 알고리즘을 사용하는 JWTDecryptSignature의 유효성 검증을 수행하는 NimbusJwtDecoder instance를 특정 RSAPublicKey instance를 활용하여 생성하는 Method.
    // RSAKey instance를 return하는 @Bean Method로부터 매개변수로 AutoWiring. 
        @Bean
        public JwtDecoder jwtDecoder(RSAKey rsaKey) throws JOSEException {
            return NimbusJwtDecoder.withPublicKey(rsaKey.toRSAPublicKey()).build();
        }

    NimbusJwtDecoder.build()를 통해 NimbusJwtDecoder instance를 JwtDecoder의 instance로서 생성하여 반환.

OpenSSL :
。암호화 및 보안통신을 위한 Opensource Library
SSL/TLS protocol을 지원하고 다양한 암호화 알고리즘( 대칭키 : AES, DES / 비대칭키 : RSA , ECC )를 제공.

  • JWT 생성을 위한 JWT Resource 구현
    。특정 사용자가 JWT를 활용해 Application에서 OAuth2.0으로 보호된 REST API를 호출하기 위해서는 사용자ID & PW를 포함한 HTTP Basic AuthenticationHTTP Request에 포함하여 @RestController로 선언된 Class에 Controller Method에 Mapping된 URL에 전달하여 Spring Security에 의해 유효한 Signature를 포함한 JWT를 생성HTTP Response로 반환하여 차후 자원을 요청할 HTTP RequestAuthentication Header"Bearer JWT토큰코드"로서 포함하여 전송.
    Client는 해당 Controller Method의 API를 호출하여 HTTP Basic Authentication를 포함한 HTTP Request를 전송하고 Controller MethodHTTP Basic Authentication의 정보를 기반으로 JWT Token을 생성하여 반환
    • HTTP Basic Authentication을 통한 HTTP Request가 전달하는 Authentication 정보 확인하기
      Controller Method의 매개변수에 Authentication interface의 instance를 정의하여 Client에서 전송된 HTTP RequestHTTP Basic Authentication 정보를 확인.
      ▶ 사전에 AuthenticationManager객체.authenticate(Authentication객체)에 의해 사용자인증정보의 검증이 완료되어 principal, authorities, credentials 정보를 포함한 Authentication instance가 매개변수로 전달됨.
    import org.springframework.security.core.Authentication;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RestController;
    @RestController
    public class JwtAuthenticationResource {
        @PostMapping("/authenticate")
        public Authentication authenticate(Authentication authentication){
            return authentication;
        }
    }

    • Authentication interface의 instance를 통해 HTTP Basic Authentication를 포함하여 HTTP Request로서 전송한 Client의 권한( "authority" ) , 인증여부 ( "authenticated" ) , Client의 ID ( "username" )를 알 수 있다.
      • Authentication interface :
        org.springframework.security.core.Authentication
        Spring Security에서 Authentication 정보를 지시하는 Interface
        ▶ 사용자의 인증상태 , 권한 , 인증된 사용자정보 등을 포함.

        HTTP RequestAuthentication Header에 포함된 사용자 인증정보를 Controller Method의 매개변수로 사전에 AuthenticationManager객체.authenticate(Authentication객체)에 의해 사용자인증정보가 검증되어 principal, authorities, credentials 정보를 포함한 Authentication instance로서 mapping되어 전달됨.
        • SecurityContextHolder , SecurityContext , Authentication 관계
        SecurityContextHolder
           └── SecurityContext (보안 컨텍스트)
                 └── Authentication (인증 정보)
                       ├── Principal (사용자 정보)
                       ├── Credentials (비밀번호, JWT 등)
                       └── Authorities (권한 정보)

        Spring Authentication instance 구성

        ▶ Client에서 전송된 HTTP RequestHTTP Basic Authentication 인증정보가 포함된 Authentication instance

        • principal :
          。인증된 사용자의 세부정보를 의미.
          ▶ 보통 UserDetails instance를 포함.

        • credentials
          。사용자가 인증 시 입력한 정보 ( ex. username, password )
          ▶ 인증이 완료된 경우, 보안을 위해 null로 설정됨.

        • authorities
          principal에 정의된 사용자가 보유한 역할, 권한 목록을 지시.
          ▶ 주로 "ROLE_USER" , "ROLE_ADMIN" 등의 권한정보를 포함.

          。검증전의 credentials 정보만 포함된 Authentication instance를 AuthenticationManager객체.authenticate(Authentication객체)로 전달 시 사용자인증정보를 검증 후 인증성공 시 principal, authorities 정보를 추가로 포함한 완전한 Authentication instance를 return.


    • JWT를 생성하여 반환하는 Controller Class 구현
      Java Record 기능을 활용하여 JWT Token을 포함하는 Template 역할의 Record( = JwtResponse )의 token field에 생성자에 JWT의 문자열을 전달하여 Record instance를 생성하여 반환하는 Controller Method 구현.

      JwtEncoder Interface의 field를 생성 후 Constructor-based Dependency Injection을 구현하여 JwtEncoder instance를 생성하여 return하는 @Bean Method로 부터 Dependency Injection을 수행.

      。매개변수의 Authentication instance를 받아서 JwtClaimsSet객체를 생성 후 JwtEncoder instance를 활용해 Jwt객체를 생성하여 서명된 JWT의 문자열을 반환하는 Method를 정의.
      JwtEncoderParameters.from(JwtClaimsSet객체)로 전달하여 JwtEncoderParameters instance 생성 및 JwtEncoder객체.encode(JwtEncoderParameters객체)Jwt instance 생성 및 getter Method ( Jwt객체.getTokenValue() )를 통해 서명된 Jwt 문자열 획득.

      。권한목적의 커스텀 Claim의 값 설정 시 HTTP Basic Authentication을 통한 Authentication instance에 포함된 authorities 배열을 가져와서 Stream객체로 변환 후 Stream객체.map(람다식)을 통해 순회하면서 authority를 추출하여 Stream객체.collect(Collectors.joining(" "))를 통해 구분자를 " "로 설정하여 하나로 합친 문자열을 반환하여 커스텀 Claim 값으로 설정.
      ▶ 해당 커스텀 Claim 생성 시 JWTPayload에서 "scope" : "ROLE_ADMIN ROLE_DEVELOPER"로 생성.
    import org.springframework.security.core.Authentication;
    import org.springframework.security.oauth2.jwt.JwtClaimsSet;
    import org.springframework.security.oauth2.jwt.JwtEncoder;
    import org.springframework.security.oauth2.jwt.JwtEncoderParameters;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RestController;
    import java.time.Instant;
    import java.util.stream.Collectors;
    @RestController
    public class JwtAuthenticationResource {
        // JwtEncoder instance를 생성하여 return하는 @Bean Method로 부터 Dependency Injection.
        private JwtEncoder jwtEncoder;
        public JwtAuthenticationResource(JwtEncoder jwtEncoder) {
            this.jwtEncoder = jwtEncoder;
        }
        // API 호출 시 HTTP Request의 HTTP Basic Authentication 정보를 활용해
        // JWT Token을 생성 후 Record instance에 포함하여 HTTP Response로 반환.
        @PostMapping("/authenticate")
        public JwtResponse authenticate(Authentication authentication) {
            return new JwtResponse(createToken(authentication));
        }
        // JWT Token을 생성하는 Method
        private String createToken(Authentication authentication){
            var claims = JwtClaimsSet.builder()
                    // 발급자 이름 정의
                    .issuer("self")
                    // 발급시간 현재시점으로 설정
                    .issuedAt(Instant.now())
                    // 만료시간 30분 설정
                    .expiresAt(Instant.now().plusSeconds(60*30))
                    // 사용자 ID
                    .subject(authentication.getName())
                    // HTTP Basic Authentication에 포함된 authority 정보를 하나의 문자열로 합쳐서 반환 시
                    // 커스텀 Claim의 값으로 설정하여 권한 목적의 Claim 생성
                    .claim("scope",createScope(authentication))
                    .build();
            // Dependency Injection된 JwtEncoder instance를 활용해
            // JwtClaimSet instance를 포함하여 JWT를 생성하여 반환.
            return jwtEncoder.encode(JwtEncoderParameters.from(claims)).getTokenValue();
        }
        // HTTP Basic Authentication에 포함된 authority 정보를 하나의 문자열로 합쳐서 반환하는 Method.
        private String createScope(Authentication authentication) {
            return authentication.getAuthorities().stream()
                    .map(a->a.getAuthority())
                    // Stream 요소를 " "의 구분자로 하나의 문자열로 합쳐서 반환.
                    .collect(Collectors.joining(" "));
        }
    }
    // JWT Token을 포함하는 Template 역할의 Record
    record JwtResponse(String token){};


    。 해당 Controller MethodAPIHTTP Basic Authentication을 포함한 HTTP Request를 전달하여 호출 시 HTTP Basic Authentication를 기반으로 생성된 JWTRecord ( = JwtResponse )의 token field에 포함하여 HTTP Response로 반환.

    。 생성된 JWT는 다음과 같은 유효한 signature를 가진 header.payload.signature를 포함한다.
    JWT는 발급시점 ( iat )로부터 1742627427-1742625627 = 1800초만큼 유효.

    。생성된 JWTBearer JWT토큰 양식으로 HTTP RequestAuthetication Header에 포함하여 전송 시 성공적으로 ApplicationResource를 반환함을 확인 가능.
    HTTP RequestJWT는 위에서 정의된 JwtDecoder에 의해 Decrypt 및 유효성검증이 수행된 후 Resource의 접근권한여부를 검증.

  • JoseHeader
    JWT Header를 설정하는 역할의 Class
    • JWT headerheader 요소 종류
      alg : ( algorithm ) : 서명 알고리즘( Signature Algorithm )
      Signature Algorithm은 주로 Hashing AlgorithmHS512 , HS256 등을 사용.

      typ : ( Type ) : Token Type
      kid : ( Key ID ) : key의 식별자 ( 제외 가능. )

    • JoseHeader Method
      JoseHeader.withAlgorithm(SignatureAlgorithm.RS256)
            .type("JWT") // JWT 타입 지정
            .keyId("my-key-id") // 키 ID 설정 (옵션)
            .build();

    JoseHeader.withAlgorithm(Signature알고리즘 객체) : 특정 Signature Algorithm (alg) instance를 지정한 JoseHeader instance 생성.

    JoseHeader객체.type("토큰형식") : JoseHeader instance에 특정 Token Type (tkp)을 지정.

    JoseHeader객체.keyId("키ID") : JoseHeader instance에 특정 Key ID (kid)를 지정.
    ▶ 정의안해도된다.

    JoseHeader객체.build() : Configuration이 정의된 JoseHeader instance 생성.

OAuth를 활용하여 Spring Application에서 Google Drive의 파일에 Access하여 전달받는 기능 구현
OAuth Protocol 활용 시 타사의 Application에 사용자 계정정보를 직접 제공하지않아도 타사의 Application의 Resource에 안전하게 접근이 가능.
Google Drive에 계정정보를 직접 노출하지 않고도 안전하게 연동하여 Resource를 가져올 수 있다.

OAuth를 통해 Google에서 제공하는 로그인 서비스를 추가.
。해당 Spring ApplicationClientGoogle Drive에 저장된 파일에 Access를 수행하는 Client Application.

  • OAuth( Open Authorization ) :
    。사용자의 ID와 PW를 직접 제공하지 않아도, 타 Application의 Resource에 안전하게 접근할 수 있도록 하는 프로토콜.
    ▶ 사용자가 자신의 계정정보를 노출하지 않고도 다른 서비스와 안전하게 연동이 가능.

    OAuth 주요 개념

    • Resource Owner :
      API를 통해 보호된 Resource를 소유한 주체.
      ex) Google Drive의 파일을 소유하고 있는 Client

    • Client Application :
      Resource Owner 대신 API를 호출하는 Application
      ex) Google Drive 파일에 접근하고자 하는 Spring Application
      ex) Google 로그인 서비스를 이용하는 웹사이트

    • Resource Server :
      API를 제공하고, 인증된 Access Token을 포함한 HTTP Request만 허용하는 Server
      ex) 접근하려는 Google Drive 파일을 보관하는 Server( = Google Drive )

    • Authorization Server :
      。Client의 인증을 담당 및 인증된 Client에 대해 Access Token을 발급하는 Server
      ex) Google OAuth Server


  • OAuth 관련 의존성 추가
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' 

OAuth2 Client , Spring Web 추가.

  • Application의 Test를 위한 Google 개발자 자격증명 생성
    Google Firebase 활용사례
    • Google API Console에 접속하여 Google Cloud Project 생성

      。프로젝트 구성에서 앱정보와 대상 ( 외부 ) 등을 설정 후 생성완료.

      。이후 데이터 액세스에서 범위 추가 또는 삭제 ( ADD OR REMOVE SCOPE )로 접속하여 이메일정보와 프로필정보에 대한 액세스를 허용하도록 SCOPE를 설정.


    • OAuth 클라이언트 ID 생성

      클라이언트 - 클라이언트만들기 순으로 접속.

      어플리케이션 유형을 웹 애플리케이션으로 지정 후 승인된 리디렉션 URI에서 로컬서버의 URI( http://localhost:8080/login/oauth2/code/google )를 입력.
      ApplicationLocal환경에서 실행 시 지정해야한다.

      。다음처럼 OAuth Client ID가 성공적으로 생성되어 IDSecret이 제공됨.


  • Spring Application에 생성한 OAuth Client 계정 등록하기
    application.properties에서 다음 구문을 기입하여 위 과정에서 생성한 OAuth Client를 등록.
spring.security.oauth2.client.registration.google.client-id=OAuth클라이언트ID
spring.security.oauth2.client.registration.google.client-secret=OAuth클라이언트Secret
  • Spring Application에서 로그인이 수행 될 경우 접근될 기본 Resource 생성
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class BasicResource {
    @GetMapping("/")
    public Authentication home(Authentication authentication) {
        return authentication;
    }
}

localhost:8080/ 접속 시 HTTP RequestAuthentication HeaderAuthentication instance가 AuthenticationManager을 통해 인증을 거친 후 principal, authorities, credentials 정보를 return.
Spring Security 인증원리

  • Spring Application에서 Google을 이용한 로그인 기능 구현하기
    @Configuration Class에서 HttpSecurity instance의 Configuration을 수행 후 SecurityFilterChain instance를 return하는 @Bean Method를 생성.
    ▶ 해당 HttpSecurity객체.oauth2Login(Customizer.withDefaults())를 설정하여 Spring Security에서 Oauth 2.0 로그인 기능을 활성화.
    ▶ 다음 설정을 끝낸 후 localhost:8080/login 접속 시 해당 API를 보호하기위해 등록된 OAuth2 Provider ( ex. Google )에 의해 로그인옵션이 자동으로 표시됨.
@Configuration
public class JwtSecurityConfiguration {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http.oauth2Login(Customizer.withDefaults()).build();
    }   
}





Google을 이용한 로그인을 통해 OAuthOAuth2 Provider에 의해 Spring Application의 보호된 API에 접근 가능.
▶ 다음은 localhost:8080/에 mapping된 Controller Method에 의해 HTTP Response로 return된 Authentication instance

  • 로그아웃 수행
    localhost:8080/logout 입력 시 로그아웃을 수행하게 된다.
profile
공부기록 블로그

0개의 댓글