[React + SpringBoot] JWT 인증 구현 ① - 개념 및 설치

SihoonCho·2023년 4월 18일
0
post-thumbnail

※ 읽기에 앞서


본 시리즈는 작성자의 이해와 경험을 바탕으로 실습 위주의 설명을 기반으로 작성되었습니다.
실습 위주의 이해를 목표로 하기 때문에 다소 과장이 많고 생략된 부분이 많을 수 있습니다.
따라서, 이론적으로 미흡한 부분이 있을 수 있는 점에 대해 유의하시기 바랍니다.

또한, 본 시리즈는 ChatGPT의 도움을 받아 작성되었습니다.
수 차례의 질문을 통해 도출된 여러가지 다양한 방식의 코드를 종합하여
작성자의 이해와 경험을 바탕으로 가장 정석으로 생각되는 코드를 재정립하였습니다.


📌 JWT(Jason Web Token)


What is JSON Web Token?

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.

Although JWTs can be encrypted to also provide secrecy between parties, we will focus on signed tokens. Signed tokens can verify the integrity of the claims contained within it, while encrypted tokens hide those claims from other parties. When tokens are signed using public/private key pairs, the signature also certifies that only the party holding the private key is the one that signed it.

[Reference] https://jwt.io/introduction

JSON 웹 토큰이란 무엇입니까?

JWT(JSON Web Token)는 당사자 간에 정보를 JSON 개체로 안전하게 전송하기 위한 간결하고 독립적인 방법을 정의하는 개방형 표준(RFC 7519)입니다. 이 정보는 디지털 서명되어 있으므로 확인하고 신뢰할 수 있습니다. JWT는 비밀(HMAC 알고리즘 포함) 또는 RSA 또는 ECDSA를 사용하는 공개/개인 키 쌍을 사용하여 서명할 수 있습니다.

JWT를 암호화하여 당사자 간에 비밀성을 제공할 수도 있지만 여기서는 서명된 토큰에 중점을 둘 것입니다. 서명된 토큰은 그 안에 포함된 클레임의 무결성을 확인할 수 있는 반면 암호화된 토큰은 다른 당사자로부터 해당 클레임을 숨깁니다. 공개/개인 키 쌍을 사용하여 토큰에 서명할 때 서명은 개인 키를 보유한 당사자만이 서명한 당사자임을 인증합니다.

[출처] https://jwt.io/introduction

JWT(JSON Web Token)는 개방형 웹 표준 RFC 7519로 지정된
JSON 객체 형태의 Web Token으로 Token 자체에 정보를 저장하는 인증 방식입니다.

OAuth, SAML(Security Assertion Markup Language), OpenID Connect 등과 함께
대표적으로 사용되는 인증 방식으로 다른 인증 방식에 비해 가볍고 간편하다는 장점이 있습니다.

📖 JWT 구조


JWT는 Header, Payload, Signature로 구성됩니다.

  • Header: Signature를 해싱하기 위한 알고리즘 정보
  • Payload: 서버와 클라이언트가 서로 주고받을 실질적인 정보
  • Signature: Token의 유효성 검증을 위한 문자열

예를 들어 다음과 같이 Base64 URL Safe Encoding을 사용하여
Token을 암호화하고 Token 속에 정보를 포함하여 전송하는 것입니다.

JWT Base64 URL Decode 결과

{
	"header": {
    	"alg":"HS512"
	}
	"payload": {
		"sub": "test2"
		"userId": 3
		"userName": "test2"
		"userEmail": "test2@test.com"
		"iat": 1681801541
		"exp": 1681887941
    }
    "signature": 1BwC=ͼq4�TY<5WWK/\Qd\_ٙ4rfRfoo
}

📖 JWT 장단점


장점

  • 중앙 인증서버 방식, 데이터 스토어에 대한 의존성 없음, 시스템 수평 확장에 용이
  • Base64 URL Safe Encoding을 사용하기 때문에 URL, Cookie, Header 모두 사용 가능

단점

  • Payload의 정보가 많아지면 네트워크 사용량 증가
  • Token이 클라이언트에 저장되기 때문에, 서버에서 클라이언트의 Token을 조작할 수 없음

📌 JWT 기본세팅


실습을 위해 대략적인 프로젝트의 구조와
build.gradledependency를 확인합니다.


📖 프로젝트 구조


com.example
├── config
│   ├── JwtTokenFilter.java
│   ├── JwtTokenProvider.java
│   └── WebSecurityConfig.java
│   └── CustomUserDetails.java
│   └── CustomUserDetailsService.java
├── domain
│   ├── Auth.java
│   └── User.java
├── dto
│   ├── AuthRequestDTO.java
│   ├── AuthResponseDTO.java
│   ├── UserRequestDTO.java
│   └── UserResponseDTO.java
├── repository
│   ├── AuthRepository.java
│   └── UserRepository.java
├── service
│   ├── AuthService.java
│   └── UserService.java
└── controller
    ├── AuthController.java
    └── UserController.java

위 프로젝트 구조는 MVC 패턴에 기반한 프로젝트 구조입니다.
기본적인 구조는 위와 같고, 필요에 따라 package 구조를 변경하셔도 좋습니다.

CustomUserDetails, CustomUserDetailsService
원래는 domain, service에 위치해야 하지만,
편의상 config에 위치시켰습니다.


📖 Dependencies


build.gradle

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-security'	// 추가
	implementation 'org.springframework.boot:spring-boot-starter-websocket'

	implementation 'io.jsonwebtoken:jjwt:0.9.1'	//추가
	implementation 'mysql:mysql-connector-java'
	implementation 'org.projectlombok:lombok:1.18.26'

	annotationProcessor 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testImplementation 'org.springframework.security:spring-security-test'	//추가
}

dependencies를 추가한 후에는 refresh 하는 것을 잊지 않도록 합니다.
IntelliJ에서는 Reload All Gradle Projects 에 해당합니다.

profile
꾸준히 노력하는 개발자

0개의 댓글