Java/Spring Boot

[Java] Spring Boot Security 3.x + JWT 이해하기 -1 : 구조 및 Client / Server 처리과정

adjh54 2024. 10. 6. 14:02
반응형
해당 환경에서는 Spring Boot Security 3.x 기준으로 JWT와 함께 이해하고 처리되는 과정에 대해 알아봅니다.

 
 

 💡[참고] Spring Security 관련 글 및 Github Repository 경로입니다. 참고하시면 도움이 됩니다.
분류 상세 분류 주제 링크
Spring Boot 2.x 이론 Spring Boot Security 이해하기 -1 : 2.7.x 버전 구조 및 파일 이해 https://adjh54.tistory.com/91
Spring Boot 2.x 환경 설정 Spring Boot Security 이해하기 -2 : 2.7.x 버전 구현하기 https://adjh54.tistory.com/92
Spring Boot 2.x 이론 Spring Boot Security 이해하기 -3: JWT(JSON Web Token) 이해하기 https://adjh54.tistory.com/93
Spring Boot 2.x 환경 설정 Spring Boot Security 이해하기 -4: JWT 환경 설정 및 구성 하기 https://adjh54.tistory.com/94
Spring Boot 2.x 소스코드 Spring Boot Security 2.x + JWT 기반 구성 Github Repository https://github.com/adjh54ir/blog-codes/tree/main/spring-boot2-security
       
기타 이론 Spring Boot 2.x.x 버전 프로젝트 생성: 지원 종료 및 다운그레이드 https://adjh54.tistory.com/361
       
Spring Boot 3.x 이론 Spring Boot Security 3.x + JWT 이해하기 -1 : 구조 및 Client / Server 처리과정 https://adjh54.tistory.com/576
Spring Boot 3.x 환경 설정 Spring Boot Security 3.x + JWT 이해하기 -2 : 환경 설정 및 구성 https://adjh54.tistory.com/577
Spring Boot 3.x 환경 설정 Spring Boot Security 3.x + JWT 이해하기 -3 : Refresh Token 활용 https://adjh54.tistory.com/583
Spring Boot 3.x 환경 설정 Spring Boot Security 3.x + JWT 이해하기 -4 : 로그아웃 + 블랙리스트 활용 https://adjh54.tistory.com/592
Spring Boot 3.x 소스코드 Spring Boot Security 3.x + JWT 기반 구성 Github Repository https://github.com/adjh54ir/blog-codes/tree/main/spring-boot3-security
React 소스코드 Spring Boot 3.x와 통신하여 로그인을 수행하는 클라이언트 구성 Github Repository https://github.com/adjh54ir/blog-codes/tree/main/react-login


 

1) Spring Boot Security


💡Spring Boot Security

- Spring 기반 애플리케이션 내에서 보안을 담당하는 프레임워크를 의미합니다. 이는 사용자에 대한 ‘인증’과 ‘인가(권한부여)’에 대한 처리를 담당합니다.
분류 설명
인증(Authentication) - 사용자는 자신을 입증할 수 있는 ‘정보’를 시스템에 제공하며, 시스템은 사용자에 대한 정보를 ‘검증’하여 시스템을 이용할 수 있는 사용자 인지에 대해 확인을 하는 과정을 의미합니다.
인가(Authorization) - 애플리케이션에서 보호된 자원(메서드 접근 혹은 요청에 대한 자원)에 대해서 접근을 허가하거나 거부하는 기능을 의미합니다.

 

 

Spring Security

Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications. Spring Security is a framework that focuses on providing both authentication and authoriz

spring.io

 

💡[참고] 상세한 Spring Boot Seucrity에 대해 알고 싶으시면 아래의 글을 참고하시면 도움이 됩니다.
 

[Java] Spring Boot Security 이해하기 -1 : 2.7.x 버전 구조 및 파일 이해

해당 글에서는 Spring Boot 기반의 Spring Security Framework를 적용하여 로그인의 API를 구성하는 방법에 대해서 공유합니다. 1) 개발환경 💡 Spring Security 개발 환경을 구성하기 위해 사용한 개발환경입니

adjh54.tistory.com

 

1. Spring Boot Security 인증과 인가


💡Spring Boot Security 인증과 인가

- 해당 과정에서는 클라이언트에서 로그인 정보를 전달하면, 데이터베이스에서 이를 조회하여 ‘인증’을 수행합니다.
- 그리고 이 인증이 완료된 경우, JWT 토큰을 발급하여 인증이 된 사용자로 ‘인가(권한부여)’를 할 예정입니다.

 

 
 

2. 주요 특징


특징 설명
인증(Authentication) 사용자의 신원을 확인합니다. 폼 로그인, HTTP 기본 인증, JWT 등 다양한 인증 방식을 지원합니다.
인가(Authorization) 인증된 사용자의 리소스 접근 권한을 확인합니다. URL 기반, 메소드 기반 등 다양한 접근 제어를 제공합니다.
보안 위협 방어 CSRF, XSS 등 다양한 웹 보안 위협에 대한 기본적인 보호 기능을 제공합니다.
세션 관리 사용자 세션을 안전하게 관리합니다. 동시 세션 제어, 세션 고정 보호 등의 기능을 제공합니다.
암호화 비밀번호 등 중요 정보를 안전하게 저장하기 위한 암호화 기능을 제공합니다.
통합성 Spring 생태계와 완벽하게 통합됩니다. 다른 Spring 프로젝트들과 쉽게 연동할 수 있습니다.

 
 

2) JWT(JSON Web Token)


 💡JWT(JSON Web Token)

- ‘사용자 인증’을 위해 ‘인증’에 필요한 정보를 토큰에 담아서 암호화를 하여 사용하는 인터넷 표준 인증방식을 의미합니다.
- 가볍고 자가 수용적인(self-contained) 방식으로 정보를 안전성 있게 전달해 줍니다.

 
 

[ 더 알아보기 ]

💡 자가수용적인 (self-contained) 방식
- JWT 내에 필요한 정보를 토큰 내에 자체적으로 지니고 있음을 의미합니다.
- 이는 JWT에서 발급된 토큰은 기본 정보, 전달할 정보, 검증에 대한 모든 Signature도 포함하고 있으며, 웹 서버 환경에서는 HTTP 헤더에 포함을 시키거나 URL의 파라미터로 전달이 가능합니다.

 

1. JWT 이용방법


💡JWT 이용방법

- 사용자의 인증을 통과한 경우에 이에 대한 인가(권한부여)를 위해서 JWT를 발급해 줍니다.
- 이 발급받은 JWT를 클라이언트에서는 HTTP/HTTPS 통신 시 Header에 ‘Authorization’ 키와 ‘Bearer JWT’ 형태의 값 형태로 전달을 하여 유효한 토큰일 경우 JWT를 통해 로그인된 사용자로 ‘인가(권한부여)’를 받을 수 있습니다.

 
 

2. JWT 구조


💡JWT 구조

- Token의 구조는 아래의 이미지와 같이 점(.)을 기반으로 구분되어 세 부분으로 구성이 됩니다.(header.payload.signature) 이 세 부분은 암호화로 Base64Url로 인코딩 되어 있어서 읽기 어려운 형태로 변환이 됩니다.
- 특히 Signature 부분은 비밀 키를 사용하여 생성되므로, 토큰의 위조나 변조를 방지할 수 있습니다.
- 단 Header와 Payload 부분은 단순히 인코딩만 되어 있을 뿐, 암호화되지 않았다는 점입니다. 따라서 중요한 정보는 Payload에 포함시키지 않는 것이 좋습니다.
구성 요소 설명
헤더 (Header) 토큰의 타입과 서명(Signature)에서 사용할 알고리즘을 포함합니다.
페이로드 (Payload) 인증에 필요한 실제 정보들(클레임)을 담고 있습니다.
서명 (Signature) 인코딩된 헤더와 페이로드, 비밀 키, 그리고 헤더에 명시된 알고리즘을 사용하여 생성됩니다.

 
 

💡[참고] Header, Payload, Signature는 아래와 같은 형태로 구성이 되어 있습니다.
// [Header] typ : 토큰의 타입 / alg : 토큰의 서명에서 사용할 암호화 알고리즘 종류
{
  "typ": "JWT",
  "alg": "HS256"
}

// [payload] 등록 클레임, 공개 클레임, 비공개 클레임

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

// [Signature] 서명(Signature) = 인코딩 헤더 + 인코딩 비밀키 + 비밀 키 + 헤더의 알고리즘
HMACSHA256(
    base64UrlEncode(header) + "." +
    base64UrlEncode(payload),
    secret
)

 
 

💡[참고] 상세 구조에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
 

[Java] Spring Boot Security 이해하기 -3: JWT(JSON Web Token) 이해하기

해당 글에서는 Spring Security의 인증을 위한 ‘JWT: JSON Web Token’를 이해하고 적용하기 위해 우선 이해를 목적으로 작성한 글입니다. 추후 적용을 위한 환경 설정 방법에 대해서 공유합니다. 💡 [참

adjh54.tistory.com

 

💡[참고] JWT 실제 값 예시

- 아래와 같은 형태의 JWT 형태의 구조를 가지고 있습니다.
- 또한, 디버깅을 목적으로 공식 사이트에서 인코딩 된 JWT를 디코딩하여서 볼 수도 있습니다.

 

Authorization: Bearer 
eyJyZWdEYXRlIjoxNzI3NzY5NDcwNTU3LCJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.
eyJ1c2VyTm0iOiJsZWUiLCJ1c2VySWQiOiJhZGpoNTQiLCJzdWIiOiIwIiwiZXhwIjoxNzI3Nzk4MjcwfQ.
wdfzdWNQU04aV9b18o23FCtYEtFgd1xSxEhxYVHSFBgBWLd1CfIcF1_cyDbjBS_F0VntE4Lv0kIyKzly8bRiwA

https://jwt.io/

 

[더 알아보기]

💡 공식 사이트에서 JWT만 알면 디코딩을 할 수 있는데 이거 위험한 거 아닌가?

- 네, 맞습니다. JWT의 Header와 Payload 부분은 단순히 Base64Url로 인코딩 되어 있을 뿐이며, 실제로 암호화되지 않았습니다. 이는 보안상의 우려를 일으킬 수 있는 부분입니다.
- 그러나 이것이 반드시 위험하다고 볼 수는 없습니다. JWT의 보안은 주로 Signature 부분에 의존합니다. Signature는 비밀 키를 사용하여 생성되므로, 토큰의 위조나 변조를 방지할 수 있습니다.
- 그럼에도 불구하고, 중요한 정보는 Payload에 포함시키지 않는 것이 좋습니다. 예를 들어, 비밀번호나 민감한 개인정보 등은 JWT의 Payload에 포함해서는 안 됩니다.
- 공식 사이트에서 JWT를 디코딩할 수 있다는 것은 단순히 JWT의 구조를 이해하고 디버깅을 돕기 위한 도구일 뿐입니다. 실제 애플리케이션에서는 서버 측에서 비밀 키를 사용하여 Signature를 검증함으로써 토큰의 무결성을 확인합니다.

 
 

3. 인증 타입 : Bearer Token


💡 인증 타입 : Bearer Token

- 토큰을 소지한 사람(bearer)에게 접근 권한을 부여하는 인증 방식을 의미합니다.
- HTTP 요청의 Authorization 헤더에 "Bearer" 키워드와 함께 토큰을 포함하여 사용이 됩니다.
- 해당 인증 타입은 구현이 간단하고, 서버 측에서 세션 상태를 유지할 필요가 없어서 확장성이 좋습니다.
(즉, API 통신 시마다 Header에 Token을 담아서 전송하기에 서버 측에서 세션 상태를 유지하지 않습니다)

 

 

 

반응형

 

 

3) Spring Security + JWT 처리과정 : Client 관점


💡 Spring Security + JWT 처리과정: Client 관점

1. Client는 로그인을 수행합니다.
- 사용자 아이디, 비밀번호를 기준으로 로그인을 수행합니다.

2. Client는 API Server로 API 호출 시 사용자 정보를 함께 전달하여 ‘인증’을 요청합니다 : 인증(Authentication)
- 사용자 아이디, 비밀번호를 기준으로 API Server로 호출을 하면 데이터베이스를 조회하여 실제 인증이 된 회원인지 여부를 확인합니다.

3. API Server에서 클라이언트에게 인증 결과 값을 반환해 줍니다.
- 데이터베이스 조회 결과를 통해서, 회원 여부에 따라 맞는 응답 결과를 반환해 줍니다.

4. 로그인 성공 시 '인가(권한 부여)'로 JWT를 발급하며, 조회된 사용자 정보를 응답 값으로 전달합니다.
- 로그인 성공 시 JWT와 사용자 정보를 함께 반환해 주고, 실패인 경우에는 에러 코드 및 메시지를 전달하며, 다시 로그인을 요청합니다.

5. 클라이언트는 전달받은 JWT 내부 스토리지에 저장합니다.
- 발급받은 JWT를 유지하며, 이후 API 호출마다 이를 Header에 포함하여 전달하기 위해 저장해 둡니다.

6. 클라이언트가 API Server로 API 통신 시 JWT를 Header에 추가하여 호출합니다.
- 이를 통해 인가받은 사용자만 API 통신을 수행할 수 있음을 확인합니다.

 
 
 
 

1. 로그인


💡로그인

- 클라이언트는 아이디와 비밀번호를 입력하고 ‘로그인’ 버튼을 누르면 입력한 아이디, 비밀번호를 기반을 API 통신을 수행합니다.
- 아래에서는 간단한 코드를 통해서 흐름에 대해서만 확인해 봅니다.

 

💡클라이언트 측 API 통신

- 아래와 같이 http://localhost:8080/api/v1/user/login이라는 엔드포인트로 API를 호출하며 해당 값을 전달합니다.

 
 

💡Spring Boot API 서버 내 코드 : Spring Security 구성 -1

- 추후 Spring Security 내에서 해당 Endpoint를 지정하여서 로그인을 위한 URL로 지정을 하였습니다.

 

💡Spring Boot API 서버 내 코드 : Spring Security 구성 -2

- 해당 로그인의 인증을 위해서 아이디/비밀번호를 확인하는 곳은 authenticationManage() 메서드 내에서 이를 수행합니다.

 
 

2. 로그인 성공여부 : 로그인 실패


💡로그인 성공여부 : 로그인 실패

- 로그인 실패를 하는 경우 resultCode : 9999라는 값을 통해서 오류 메시지와 함께 응답이 되도록 처리하였습니다.

 

💡Spring Boot API 서버 내 코드 : Spring Security 구성 -1

- 해당 로그인 실패에 대한 처리는 customLoginFailureHandler에서 처리가 됩니다.

 

💡Spring Boot API 서버 내 코드 : Spring Security 구성 -2

- 아래의 customLoginFailureHandler 내에서는 실패에 대한 응답 값을 구성해서 반환해 줍니다.

 
 

3. 로그인 성공여부 : 로그인 성공


💡로그인 성공여부 : 로그인 성공

- 해당 값을 기반으로 Spring Security가 처리되어서, 최종적으로는 로그인이 완료되어 클라이언트에게 응답 값으로 사용자 정보와 JWT를 발급해 줍니다.

 
 

💡Spring Boot API 서버 내 코드 : Spring Security 구성 -1

- 해당 로그인 실패에 대한 처리는 customLoginSuccessHandler에서 처리가 됩니다.

 
 

💡Spring Boot API 서버 내 코드 : Spring Security 구성 -2

- 아래의 customLoginSuccessHandler 내에서는 성공에 대한 응답 값(사용자 정보, JWT)을 구성해서 반환해 줍니다.

 
 
 

4) Spring Security + JWT 처리과정 : API Server 관점


💡Spring Security + JWT 처리과정 : API Server

- 클라이언트의 호출 이후 내부적으로 처리되는 API Server의 과정에 대해 확인합니다.

1. 클라이언트의 API 호출 : 엔드포인트(api/v1/user/login)
- 클라이언트는 사용자 아이디, 비밀번호를 기반으로 API 호출을 수행합니다.

2. 서버 내에서 해당 엔드포인트에 대한 감지 하여 이를 처리합니다. : CustomAuthenticationFilter
- CustomAuthenticationFilter 내에서 사전에 지정한 엔드포인트를 통해서 수행처리 합니다.

3. 감지 이후 Filter에서 우선적으로 감지하여 해당 엔드포인트로 호출되는 정보를 조회합니다. : JwtAuthorizationFilter

- 3.1. JWT가 필요가 없는 URL인 경우는 다음 필터를 수행하도록 처리가 됩니다.
- 3.2. JWT가 필요한 경우는 JWT에 대한 존재 및 유효성을 검증합니다.

4. 사용자 아이디/비밀번호를 감지하여 전달합니다.: CustomAuthenticationFilter
- CustomAuthenticationFilter 내에서 사용자 아이디/비밀번호 값을 CustomAuthenticationProvider로 전달을 합니다.

5. 전달받은 값을 통해 데이터베이스 내의 사용자 정보를 조회하여 사용자 여부를 확인합니다. : CustomAuthenticationProvider
- 데이터베이스를 호출하여 사용자를 조회하여 실제 사용자 여부인지 여부를 성공(CustomAuthSuccessHandler)과 실패(CustomAuthFailureHandler)로 전달을 합니다.

6. 이전과정에서 사용자 여부가 비교되어서 상황에 따른 처리를 수행합니다

- 6.1. 성공 시, 조회된 사용자 정보와 토큰을 발급하여 클라이언트에게 전달합니다.
- 6.2. 실패 시, 클라이언트에게 오류 코드와 오류 메시지를 전달합니다.

 
 
 
오늘도 감사합니다. 😀

 

반응형