๐Ÿ”™๋’ค๋กœ๊ฐ€๊ธฐ

JWT๋Š” ์„ธ ๊ฐ€์ง€ ๋ถ€๋ถ„์œผ๋กœ ์ด๋ฃจ์–ด์ ธ์žˆ๋‹ค.

  1. Header : ํ† ํฐ ํƒ€์ž…๊ณผ ํ•ด์‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.
  2. Payload : ํ•„์š”ํ•œ ํด๋ ˆ์ž„ ์ •๋ณด๋ฅผ ๊ฐ–๊ณ  ์žˆ๋‹ค.
  3. Signature : ํ† ํฐ์˜ ๋ฌด๊ฒฐ์„ฑ์„ ๋ณด์žฅํ•œ๋‹ค.

JWT ํ† ํฐ์˜ ๋ฐœ๊ธ‰ ๊ณผ์ •

  1. ์‚ฌ์šฉ์ž ์ธ์ฆ

์‚ฌ์šฉ์ž๋Š” ์ž์‹ ์˜ ์ž๊ฒฉ ์ฆ๋ช…(์˜ˆ: ์‚ฌ์šฉ์ž๋ช…๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ)์„ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ๊ทธ์ธ ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค.

// HTTP POST ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฉ”์†Œ๋“œ
// "/login" ์—”๋“œํฌ์ธํŠธ์— ๋กœ๊ทธ์ธ ์š”์ฒญ์ด ์˜ค๋ฉด ์ด ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋จ
@PostMapping("/login")
public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {

    // ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ username๊ณผ password๋กœ Authentication ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ
    // ์ด ๊ฐ์ฒด๋Š” Spring Security์—์„œ ์ œ๊ณตํ•˜๋Š” ์ธ์ฆ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ์‚ฌ์šฉํ•จ
    Authentication authentication = authenticationManager.authenticate(
            new UsernamePasswordAuthenticationToken(
                    loginRequest.getUsernameOrEmail(),  // ์‚ฌ์šฉ์ž ์ž…๋ ฅ username
                    loginRequest.getPassword()  // ์‚ฌ์šฉ์ž ์ž…๋ ฅ password
            )
    );

    // ์ธ์ฆ๋œ Authentication ๊ฐ์ฒด๋ฅผ SecurityContextHolder์— ์„ค์ •
    // SecurityContextHolder๋Š” ํ˜„์žฌ ์‚ฌ์šฉ์ž์˜ ๋ณด์•ˆ ์ปจํ…์ŠคํŠธ๋ฅผ ๋ณด๊ด€ํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋จ
    SecurityContextHolder.getContext().setAuthentication(authentication);

    // JWT ํ† ํฐ ์ƒ์„ฑ์„ ์œ„ํ•ด tokenProvider์˜ generateToken ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœ,
    // ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž์— ๋Œ€ํ•œ JWT๋ฅผ ์ƒ์„ฑ
    String jwt = tokenProvider.generateToken(authentication);

    // ์ƒ์„ฑ๋œ JWT๋ฅผ ์‘๋‹ต์œผ๋กœ ๋ฐ˜ํ™˜
    return ResponseEntity.ok(new JwtAuthenticationResponse(jwt));
}
  1. JWT ์ƒ์„ฑ

์„œ๋ฒ„๋Š” ์‚ฌ์šฉ์ž์˜ ์ž๊ฒฉ ์ฆ๋ช…์„ ํ™•์ธํ•˜๊ณ , ์ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ JWT๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. JWT ์ƒ์„ฑ์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์„œ๋ฒ„์˜ ๋น„๋ฐ€ ํ‚ค(secret key)๋ฅผ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฃจ์–ด์ง„๋‹ค.

// JWT ํ† ํฐ์„ ์ƒ์„ฑํ•˜๋Š” ๋ฉ”์†Œ๋“œ
public String generateToken(Authentication authentication) {

    // Authentication ๊ฐ์ฒด์—์„œ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ด
    UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal();

    // ํ˜„์žฌ ์‹œ๊ฐ„์„ ๊ฐ€์ ธ์˜ค๊ณ ,
    Date now = new Date();

    // ํ† ํฐ์˜ ์œ ํšจ๊ธฐ๊ฐ„์„ ์„ค์ •
    Date expiryDate = new Date(now.getTime() + jwtExpirationInMs);

    // JWT ๋นŒ๋”๋ฅผ ์‚ฌ์šฉํ•ด JWT ํ† ํฐ์„ ์ƒ์„ฑ
    // Subject์—๋Š” ์‚ฌ์šฉ์ž ID๋ฅผ, ๋ฐœํ–‰์‹œ๊ฐ„๊ณผ ๋งŒ๋ฃŒ์‹œ๊ฐ„์„ ์„ค์ •
    // ์ดํ›„ ์„œ๋ฒ„์˜ ๋น„๋ฐ€ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•ด ์„œ๋ช…ํ•จ
    return Jwts.builder()
            .setSubject(Long.toString(userPrincipal.getId()))  // ์‚ฌ์šฉ์ž ID
            .setIssuedAt(new Date())  // ๋ฐœํ–‰ ์‹œ๊ฐ„
            .setExpiration(expiryDate)  // ๋งŒ๋ฃŒ ์‹œ๊ฐ„
            .signWith(SignatureAlgorithm.HS512, jwtSecret)  // ์„œ๋ช…
            .compact();
}
  1. JWT ๋ฐ˜ํ™˜
// ์ƒ์„ฑ๋œ JWT๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ณผ์ •
public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {
    // ... ์ƒ๋žต ...

    // ์ƒ์„ฑ๋œ JWT๋ฅผ HTTP ์‘๋‹ต ๋ฐ”๋””์— ๋‹ด์•„ ๋ฐ˜ํ™˜
    // JwtAuthenticationResponse๋Š” JWT๋ฅผ ๋‹ด๋Š” ํด๋ž˜์Šค
    return ResponseEntity.ok(new JwtAuthenticationResponse(jwt));
}

์ƒ์„ฑ๋œ JWT๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฐ˜ํ™˜๋œ๋‹ค. ์ด ํ† ํฐ์€ ์ผ๋ฐ˜์ ์œผ๋กœ HTTP ์‘๋‹ต ํ—ค๋” ํ˜น์€ ๋ฐ”๋””์— ํฌํ•จ๋˜์–ด ์ „๋‹ฌ๋œ๋‹ค. ์ด ๊ฒฝ์šฐ ์„œ๋ฒ„์˜ ์‘๋‹ต์€ application/json ํ˜•์‹์œผ๋กœ, ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

{
    "accessToken": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
    "tokenType": "Bearer"
}
//"accessToken"์€ ๋ฐœ๊ธ‰๋œ JWT, "tokenType"์€ ์ด ํ† ํฐ์ด Bearer ํƒ€์ž…์ž„์„ ๋œปํ•จ

์‚ฌ์šฉ์ž๋Š” ์ด๋ ‡๊ฒŒ ๋ฐ˜ํ™˜๋œ JWT๋ฅผ ๊ฐ€์ง€๊ณ  ์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ๋งˆ๋‹ค ์ด ํ† ํฐ์„ Authorization ํ—ค๋”์— ํฌํ•จ์‹œํ‚จ๋‹ค. ์„œ๋ฒ„๋Š” ์ด ํ† ํฐ์„ ํ•ด๋…ํ•˜์—ฌ ์‚ฌ์šฉ์ž๋ฅผ ์ธ์ฆํ•  ์ˆ˜ ์žˆ๋‹ค.

JWT์˜ ๋ณด์•ˆ ์ทจ์•ฝ์ 

JWT๋Š” ์ •๋ณด๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ „์†กํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜์ง€๋งŒ, ์—ฌ์ „ํžˆ ๋ช‡ ๊ฐ€์ง€ ์ฃผ์˜ ์‚ฌํ•ญ์ด ์žˆ๋‹ค.

  1. ํ† ํฐ ๋…ธ์ถœ : JWT๋Š” ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ์—์„œ ์ €์žฅ๋˜๊ณ  ๊ด€๋ฆฌ๋˜๋ฏ€๋กœ, XSS(ํฌ๋กœ์Šค ์‚ฌ์ดํŠธ ์Šคํฌ๋ฆฝํŒ…)๋‚˜ ๋‹ค๋ฅธ ์œ ํ˜•์˜ ๊ณต๊ฒฉ์— ๋…ธ์ถœ๋  ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ์—์„œ๋Š” JWT๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ๋ณด๊ด€ํ•ด์•ผ ํ•œ๋‹ค. ๋˜ํ•œ, JWT๋Š” ํด๋ผ์ด์–ธํŠธ์—์„œ ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ํ˜•ํƒœ๋กœ ์ €์žฅ๋˜๋ฏ€๋กœ, ๋ฏผ๊ฐํ•œ ์ •๋ณด๋Š” ํ† ํฐ์— ํฌํ•จ๋˜์ง€ ์•Š๋„๋ก ์ฃผ์˜ํ•ด์•ผ ํ•œ๋‹ค. (์‹ ์ƒ์ •๋ณด, ์‹ค์ œ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋“ฑ)