์นดํ…Œ๊ณ ๋ฆฌ ์—†์Œ

[๋ฉ‹์Ÿ์ด์‚ฌ์ž์ฒ˜๋Ÿผ ๋ถ€ํŠธ์บ ํ”„ TIL ํšŒ๊ณ ] BE 13๊ธฐ_59์ผ์ฐจ_"์„ธ์…˜, JWT"

LEFT 2025. 3. 5. 17:22

๐Ÿฆ๋ฉ‹์Ÿ์ด์‚ฌ์ž์ฒ˜๋Ÿผ ๋ฐฑ์—”๋“œ ๋ถ€ํŠธ์บ ํ”„ 13๊ธฐ ๐Ÿฆ
TIL ํšŒ๊ณ  - [59]์ผ์ฐจ

๐Ÿš€59์ผ์ฐจ์—๋Š” Spring Security์—์„œ ์„ธ์…˜์„ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ์„ธ์…˜์„ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์ธ JWT์— ๋Œ€ํ•ด ์‹ค์Šตํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

ํ•™์Šต ๋ชฉํ‘œ : JWT์˜ ๊ฐœ๋…๊ณผ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ๋ฐฐ์šฐ๊ณ  ์ธ์ฝ”๋”ฉ, ๋””์ฝ”๋”ฉ ๊ณผ์ • ์‹ค์Šต

ํ•™์Šต ๊ณผ์ • : ํšŒ๊ณ ๋ฅผ ํ†ตํ•ด ์ž‘์„ฑ


CustomUserDetailsService

  • Spring Security์˜ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” UserDetailsService ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ง์ ‘ ์ปค์Šคํ…€ํ•ด์„œ
    ๊ตฌํ˜„ํ•œ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด ๋กœ๋“œ ํด๋ž˜์Šค
.csrf(csrf -> csrf.disable())
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/myinfo","/signup","/userreg", "/userreg_role","/loginform","/").permitAll()
                        .requestMatchers("/welcome","/shop/**").hasRole("USER")
                        .requestMatchers("/admin/**").hasRole("ADMIN")
                        .anyRequest().authenticated()
                );
  • .authorizeHttpRequests( … ) : ์ธ์ฆํ–ˆ์„ ๊ฒฝ์šฐ์˜ Http ์š”์ฒญ์— ๋Œ€ํ•œ ์„ค์ • ๋ถ€๋ถ„์„ ๋‹ด๋‹น
  • .requestMatchers() : ํŠน์ • ์š”์ฒญ ํŽ˜์ด์ง€๋“ค์„
  • .permitAll() : ์ง€์ •ํ•œ ํŽ˜์ด์ง€๋“ค์„ ํ—ˆ์šฉ
  • .hasRole() : ํŠน์ • ๊ถŒํ•œ์ด ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์„ ํ—ˆ์šฉ
  • . anyRequest().authenticated() : ๊ทธ ์™ธ ํŽ˜์ด์ง€๋“ค์— ๋Œ€ํ•ด์„œ๋Š” “์ธ์ฆ”์ด ๋˜์–ด์•ผ๋งŒ ๋ณด์—ฌ์คŒ

  • CsrfFilter : CSRF๊ณต๊ฒฉ์œผ๋กœ๋ถ€ํ„ฐ ๋ณดํ˜ธ
  • UsernamePasswordAuthenticationFilter : ํผ ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ
  • BasicAuthenticationFilter : HTTP ๊ธฐ๋ณธ ์ธ์ฆ ์ฒ˜๋ฆฌ
  • AuthorizationFilter : ์š”์ฒญ์˜ ๊ถŒํ•œ ๋ถ€์—ฌ ์ฒ˜๋ฆฌ

์„ธ์…˜ ๋งค๋‹ˆ์ง€๋จผํŠธ Session Management

  • ๋กœ๊ทธ์ธ ํ›„ ์‹œํฌ๋ฆฟ๋ชจ๋“œ๋กœ ๊ฐ™์€ URL์— ์ ‘๊ทผํ•˜๋ฉด ์ด์ „์— ๋กœ๊ทธ์ธํ–ˆ๋˜ ์ •๋ณด๊ฐ€
    ๊ทธ๋Œ€๋กœ ๊ฐ€์ ธ์™€์ ธ์„œ ๋ณด์—ฌ์ง€๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธ ๊ฐ€๋Šฅ
  • ๋ณด์•ˆ์„ ์œ„ํ•ด ์„ธ์…˜์„ ์„ค์ •ํ•˜์—ฌ ๋กœ๊ทธ์ธ ํ—ˆ์šฉ์„ ์„ค์ •ํ•ด์ค„ ์ˆ˜ ์žˆ์Œ

http
        .formLogin(form ->form
                .loginPage("/loginform")
                .loginProcessingUrl("/login")
                .defaultSuccessUrl("/welcome")
        )
        .logout(logout ->logout
                .logoutUrl("/logout")
                .logoutSuccessUrl("/")
        )
        .sessionManagement(session -> session
                .maximumSessions(1) // ๋™์‹œ ์ ‘์† ๊ฐ€๋Šฅํ•œ ์„ธ์…˜ ์ˆ˜ ์„ค์ •
                
        )
        .userDetailsService(customUserDetailsService);
  • ๊ธฐ์กด http ์ฝ”๋“œ์— Session Management ์†์„ฑ์„ ๋„ฃ์–ด์„œ ์„ธ์…˜์„ ์„ค์ •

  • .maximumSessions(1) : ๋™์‹œ ์ ‘์† ๊ฐ€๋Šฅํ•œ ์„ธ์…˜ ์ˆ˜ ์„ค์ •
    ex. 3์ด๋ฉด 3๊ฐœ ์ด์ƒ ์„ธ์…˜๋ถ€ํ„ฐ๋Š” ๋กœ๊ทธ์ธ ์œ ์ง€๋ฅผ ํ•˜์ง€ ์•Š์Œ

  • .maxSessionsPreventsLogin(false) : ๋™์‹œ์— ๋กœ๊ทธ์ธ์ด ๋“ค์–ด์™”์„๋•Œ ๋ˆ„๊ตฐ๊ฐ€๋ฅผ ์ฐจ๋‹จํ•ด์•ผํ•  ๊ฒƒ
    ๊ธฐ๋ณธ๊ฐ’์€ false → // ์ฒซ๋ฒˆ์งธ ๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž๊ฐ€ ์ฐจ๋‹จ๋จ
    true๋กœ ๋ฐ”๊พธ๊ฒŒ๋˜๋ฉด → ๋‘๋ฒˆ์งธ ๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž๋ถ€ํ„ฐ ์ฐจ๋‹จ๋จ

Spring Security ์„ธ์…˜

  • Spring Security๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ธ์ฆ, ์ธ๊ฐ€๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ์ธ์ฆ์— ํ•„์š”ํ•œ ์ •๋ณด๋Š” ์ฃผ๋กœ ์„ธ์…˜์— ์ €์žฅ
  • ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ•˜๋ฉด ์‚ฌ์šฉ์ž์˜ ์ธ์ฆ์ƒํƒœ, ์‚ฌ์šฉ์ž ๊ถŒํ•œ์ •๋ณด๊ฐ€ ์„ธ์…˜์— ์ €์žฅ๋˜๋Š” ๊ฒƒ
  • ์„ธ์…˜์— ์ €์žฅ๋œ ์ •๋ณด๋กœ ์„œ๋ฒ„๊ฐ€ ์‚ฌ์šฉ์ž๋ฅผ ์‹๋ณ„ํ•˜๊ณ  ์ธ์ฆ์ƒํƒœ๋ฅผ ์œ ์ง€ํ• ๋•Œ ์‚ฌ์šฉ
    ex. jsessionid๊ฐ€ ์ฟ ํ‚ค๋กœ ์ €์žฅ๋˜์–ด์žˆ์„๋•Œ ์„œ๋ฒ„๋Š” ์„ธ์…˜์„ ์‹๋ณ„ํ•˜๊ณ 
    ์„ธ์…˜์— ์ €์žฅ๋œ ์ •๋ณด๋ฅผ ์ด์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž๋ฅผ ์ธ์ฆํ•˜๊ณ  ๊ด€๋ฆฌ

  • ์„ธ์…˜์— ์ €์žฅ๋˜๋Š” ์ฃผ์š” ํด๋ž˜์Šค : SecurityContext (ํ˜„์žฌ ์‚ฌ์šฉ์ž์˜ ์ธ์ฆ์ •๋ณด์™€ ๊ถŒํ•œ์ •๋ณด๋ฅผ ๋‹ด์Œ)
  • SecurityContext๋Š” SecurityContextHolder๋ฅผ ํ†ตํ•ด ์ ‘๊ทผํ•˜๊ณ  ๊ด€๋ฆฌ

JWT

  • ๋ฌธ์ž์—ด๋กœ์จ JSON๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ •๋ณด๋ฅผ ์ „๋‹ฌ
  • Json Web Token(=JWT) : ์ธ์ฆ์— ํ•„์š”ํ•œ ์ •๋ณด๋“ค์„ Token์— ๋‹ด์•„ ์•”ํ˜ธํ™”์‹œ์ผœ ์‚ฌ์šฉํ•˜๋Š” ํ† ํฐ
  • JWT์ž์ฒด๋Š” ์ธ์ฆ/์ธ๊ฐ€์™€๋Š” ๊ด€๋ จ์ด ์—†์Œ
  • ์ฆ‰ JSON ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๊ณ  ๋””์ง€ํ„ธ ์„œ๋ช…์„ ํ†ตํ•ด ๊ฒ€์ฆํ•œ๋‹ค.
  • JWT ๊ตฌ์„ฑ์š”์†Œ : Header(ํ—ค๋”) + Payload(ํŽ˜์ด๋กœ๋“œ : ์‹ค์ œ ์ €์žฅํ•ด์•ผํ•  ์ •๋ณด) + Signature(์„œ๋ช… : ๊ฒ€์ฆํ•˜๋Š” ์šฉ๋„)

  • JWT๋Š” ์„ธ์…˜์„ ์ €์žฅํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ์ธ์ฆ ์ •๋ณด๋ฅผ ํฌํ•จํ•œ ํ† ํฐ์„ ์ œ๊ณตํ•˜๋Š” ๋ฐฉ์‹
  • ์ฆ‰, JWT ์ž์ฒด๊ฐ€ ์„ธ์…˜ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ, ๋กœ๊ทธ์ธ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋Š” ๋ฐ ํ™œ์šฉ
    โžก๏ธJWT๋Š” ํด๋ผ์ด์–ธํŠธ์— ์ €์žฅ๋˜๋ฉฐ, ๋กœ๊ทธ์ธ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Œ

JWT Header

  • JWT ํƒ€์ž…๊ณผ ํ•ด์‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ •๋ณด๊ฐ€ ๋‹ด๊น€

 

JWT Payload

  • ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์œผ๋กœ ์‹ค์ œ๋กœ ์ „์†กํ•  ๋ฐ์ดํ„ฐ๊ฐ€ ๋‹ด๊น€
    โญํด๋ ˆ์ž„(claim)์ด๋ผ ๋ถˆ๋ฆฌ๋Š” ์ •๋ณด๋“ค์ด ํฌํ•จ๋จ

  • ํด๋ ˆ์ž„์˜ 3๊ฐ€์ง€ ์œ ํ˜•
    - Registered claims : ํŠน์ •ํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์ „์— ์ •์˜๋œ ํด๋ ˆ์ž„๋“ค (๋ฐœํ–‰์ž, ๋งŒ๋ฃŒ์‹œ๊ฐ„, ์ฃผ์ฒด)
    - Public claims : ์‚ฌ์šฉ์ž ์ •์˜ ํด๋ ˆ์ž„์œผ๋กœ ์ถฉ๋Œ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด URIํ˜•์‹์œผ๋กœ ์ž‘์„ฑ
    - Private claims : ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํด๋ ˆ์ž„

 

JWT Signature

  • Header, Payload์˜ ๋‚ด์šฉ์„ ์ธ์ฝ”๋”ฉ
  • ๋น„๋ฐ€ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ช… : ๋ฉ”์‹œ์ง€๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜์Œ์„ ํ™•์ธ, ๊ฒ€์ฆํ•˜๋Š”๋ฐ ์‚ฌ์šฉ

 

JWT ์ž‘๋™๋ฐฉ์‹

1. ์‚ฌ์šฉ์ž๋กœ๊ทธ์ธ
2. ์„œ๋ฒ„์˜ JWT ์ƒ์„ฑ
3. ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฐ˜ํ™˜
4. JWT๋Š” ํด๋ผ์ด์–ธํŠธ์˜ ์ €์žฅ์†Œ์— ์ €์žฅ
5. ํด๋ผ์ด์–ธํŠธ๋Š” JWT๋ฅผ ์„œ๋ฒ„์— ์ „๋‹ฌ
6. ์„œ๋ฒ„๋Š” JWT์˜ ์„œ๋ช…์„ ํ†ตํ•ด ํ•ด๋‹น ํ† ํฐ์ด ์œ ํšจํ•œ์ง€ ๊ฒ€์ฆํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์š”์ฒญํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰


JWT ํ† ํฐ ์ข…๋ฅ˜

  • Access Token : ์‹œ๊ฐ„์„ ์งง๊ฒŒ ๋งŒ๋“ฆ (* 30๋ถ„ ์ •๋„ : ์งง๊ฒŒ ์„ค์ •ํ• ์ˆ˜๋ก ๋ณด์•ˆ์€ ์ข‹์ง€๋งŒ ์„œ๋ฒ„์— ๋ถ€ํ•˜ ๊ฐ€๋Šฅ์„ฑ ๋†’์•„์ง)
  • Refresh Token : ์‹œ๊ฐ„์„ ๊ธธ๊ฒŒ ๋งŒ๋“ฆ (* ํ•œ๋‹ฌ, 1๋…„ ๋“ฑ๋“ฑ : DB์— ์ €์žฅํ•ด์„œ ๊ด€๋ฆฌํ•˜๊ฒŒํ•จ)

์ผ๋ฐ˜์ ์œผ๋กœ๋Š” ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ฐ€ ํŠน์ • ์‹œ๊ฐ„๋งˆ๋‹ค ์•ก์„ธ์Šค ํ† ํฐ์„ ๋ฐœ๊ธ‰์‹œํ‚ค๋Š” ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉ

ex. ์ด๋ฉ”์ผ๋กœ “ํ˜„์žฌ ์–ด๋А ์œ„์น˜์—์„œ ๋กœ๊ทธ์ธ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋ณธ์ธ์ด ๋งž์œผ์‹œ๋ฉด ์˜ˆ, ์•„๋‹ˆ์‹œ๋ฉด ์•„๋‹ˆ์˜ค๋ฅผ ์„ ํƒํ•˜์„ธ์š”” ๋ฐ›์•˜์„๋•Œ
์•„๋‹ˆ์˜ค๋ฅผ ์„ ํƒํ•˜๊ฒŒ๋˜๋ฉด ์„œ๋ฒ„๊ฐ€ ๊ฐ–๊ณ  ์žˆ๋˜ Refresh Token ์‚ญ์ œ

โ“Refresh Token์„ ์‚ญ์ œํ•˜๋Š” ์ด์œ 

1. ๋ณด์•ˆ ๊ฐ•ํ™”
โžก๏ธ
Refresh Token์€ ์ƒˆ๋กœ์šด Access Token์„ ๋ฐœ๊ธ‰ํ•  ์ˆ˜ ์žˆ๋Š” ์ค‘์š”ํ•œ ํ‚ค์ด๋ฏ€๋กœ
ํƒˆ์ทจ๋˜์—ˆ์„๊ฒฝ์šฐ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž๊ฐ€ ์žฅ๊ธฐ๊ฐ„ ๋กœ๊ทธ์ธํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€

๋”ฐ๋ผ์„œ ๋ณธ์ธ์ด ์•„๋‹ˆ๋ผ๋ฉด Refresh Token์„ ์ฆ‰์‹œ ์‚ญ์ œํ•˜์—ฌ ๋” ์ด์ƒ ์ƒˆ๋กœ์šด Access Token์ด ๋ฐœ๊ธ‰๋˜์ง€ ์•Š๋„๋ก ํ•จ

2. ์žฌ๋กœ๊ทธ์ธ ์œ ๋„
โžก๏ธ
Refresh Token์ด ์‚ญ์ œ๋˜๋ฉด ์‚ฌ์šฉ์ž๋Š” ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž๊ฐ€ ์ง€์†์ ์œผ๋กœ ์‹œ์Šคํ…œ์— ์ ‘๊ทผํ•˜๋Š” ๊ฑธ ๋ฐฉ์ง€


JWT ์žฅ๋‹จ์ 

  • ์žฅ์  : ๊ฐ„๋‹จํ•˜๊ณ  ๋ถ„์‚ฐ ํ™˜๊ฒฝ ์ง€์› ๊ฐ€๋Šฅ
  • ๋‹จ์  : ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๋ฉด์„œ ํฌ๊ธฐ๊ฐ€ ์ปค์งˆ ์ˆ˜ ์žˆ๊ณ  ๋ณด์•ˆ๋ฌธ์ œ ๋ฐœ์ƒ ๊ฐ€๋Šฅ์„ฑ (=ํ† ํฐํƒˆ์ทจ๊ฐ€๋Šฅ์„ฑ)

ํผ ๋กœ๊ทธ์ธ ๊ณผ์ •์—์„œ ์„ธ์…˜

1. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์›น์—์„œ "ํผ ์ •๋ณด์— ๋”ฐ๋ผ" ๋กœ๊ทธ์ธ
2. ์„ธ์…˜์— ์ •๋ณด๊ฐ€ ์ €์žฅ
3.์„ธ์…˜์ •๋ณด๋Š” ์„œ๋ฒ„๊ฐ€ ๊ด€๋ฆฌํ•จ


โ“์„œ๋ฒ„๊ฐ€ ์—ฌ๋Ÿฌ๋Œ€ ์ผ๋•Œ์˜ ๋ฌธ์ œ์ 

์‚ฌ์šฉ์ž๊ฐ€ ํผ์— ๋กœ๊ทธ์ธํ•œ ์ •๋ณด๊ฐ€ ์„œ๋ฒ„์— ์ €์žฅ๋˜๋ ค๊ณ ํ• ๋•Œ ์‚ฌ์šฉ์ž์˜ ์š”์ฒญ์„
์—ฌ๋Ÿฌ ์„œ๋ฒ„๋กœ ๋ถ„์‚ฐ์‹œํ‚ค๋Š” ์—ญํ• ์„ “๋กœ๋“œ ๋ฐธ๋Ÿฐ์„œ”๊ฐ€ ๋‹ด๋‹นํ•จ

ํผ ๋กœ๊ทธ์ธ ๋ฐฉ์‹์—์„œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ•˜๋ฉด ์„ธ์…˜(Session) ์„ ์ƒ์„ฑํ•˜๊ณ , ์ด ์„ธ์…˜ ์ •๋ณด๋ฅผ ์„œ๋ฒ„์—์„œ ๊ด€๋ฆฌ

๋กœ๋“œ ๋ฐธ๋Ÿฐ์„œ (Load Balancer) : ์—ฌ๋Ÿฌ ๋Œ€์˜ ์„œ๋ฒ„๊ฐ€ ์žˆ์„ ๋•Œ ์š”์ฒญ์„ ๋ถ„์‚ฐ์‹œ์ผœ์ฃผ๋Š” ์—ญํ• 

โœ…ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• : ์„ธ์…˜ ๊ด€๋ฆฌ ๋ฐฉ๋ฒ• 3๊ฐ€์ง€

1. Sticky Session (๊ณ ์ • ์„ธ์…˜) ์‚ฌ์šฉ
โžก๏ธ๋กœ๋“œ ๋ฐธ๋Ÿฐ์„œ๊ฐ€ ํ•œ ๋ฒˆ ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ์š”์ฒญ์„ ํ•ญ์ƒ ๊ฐ™์€ ์„œ๋ฒ„๋กœ ๋ณด๋‚ด๋Š” ๋ฐฉ์‹
โžก๏ธํŠน์ • ์„œ๋ฒ„์— ์žฅ์• ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์„ธ์…˜์ด ์‚ฌ๋ผ์ง€๋Š” ๋‹จ์ 

2. ์„ธ์…˜์„ ์™ธ๋ถ€ ์ €์žฅ์†Œ์— ์ €์žฅ (DB ๋˜๋Š” Redis ํ™œ์šฉ)
โžก๏ธ์—ฌ๋Ÿฌ ์„œ๋ฒ„์—์„œ ์„ธ์…˜์„ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋„๋ก, ์„ธ์…˜์„ Redis, Memcached, DB ๋“ฑ์— ์ €์žฅ
โžก๏ธ์„œ๋ฒ„๊ฐ€ ๋‹ฌ๋ผ์ ธ๋„ ์„ธ์…˜ ์ •๋ณด๊ฐ€ ์œ ์ง€๋˜๋ฏ€๋กœ ์•ˆ์ •์ 

3. JWT (JSON Web Token) ์‚ฌ์šฉ
โžก๏ธ
์„œ๋ฒ„์— ์„ธ์…˜์„ ์ €์žฅํ•˜๋Š” ๋Œ€์‹ , JWT๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ์ธ์ฆ ์ •๋ณด๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Œ
โžก๏ธ์„œ๋ฒ„ ๊ฐ„ ์„ธ์…˜ ๋™๊ธฐํ™” ๋ฌธ์ œ๊ฐ€ ์‚ฌ๋ผ์ง€๊ณ , ๋กœ๋“œ ๋ฐธ๋Ÿฐ์‹ฑ์ด ์ž์œ ๋กœ์›Œ์ง\

์ •๋ฆฌํ•˜์ž๋ฉด
์„œ๋ฒ„๊ฐ€ ์—ฌ๋Ÿฌ ๋Œ€์ผ ๊ฒฝ์šฐ, ์„ธ์…˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฐ ์„œ๋ฒ„์— ๊ฐœ๋ณ„์ ์œผ๋กœ ์ €์žฅ๋˜๋ฉด ์„ธ์…˜ ๋ถˆ์ผ์น˜ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ ๊ฐ€๋Šฅ
์ด๋•Œ ๋กœ๋“œ ๋ฐธ๋Ÿฐ์„œ๋Š” ์š”์ฒญ์„ ๋ถ„์‚ฐ์‹œํ‚ฌ ๋ฟ, ์„ธ์…˜์„ ์ง์ ‘ ๊ด€๋ฆฌํ•˜์ง€๋Š” ์•Š์œผ๋ฏ€๋กœ JWT ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ํ•ด๊ฒฐํ•ด์•ผํ•จ

JWT๋Š” ์„ธ์…˜์„ ์„œ๋ฒ„๊ฐ€ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๊ณ , ํ† ํฐ์„ ํด๋ผ์ด์–ธํŠธ์—์„œ ๊ด€๋ฆฌํ•˜๋„๋ก ํ•˜๋Š” ๊ธฐ์ˆ ์ž„

๋ณด์•ˆ์— ์ทจ์•ฝํ•  ์ˆ˜ ์žˆ์–ด ์„ธ์…˜์„ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์•„๋‹Œ ์„œ๋ฒ„๊ฐ€ ๊ฐ€์กŒ๋˜ ๊ธฐ์กด์˜ ๋ฐฉ๋ฒ•์—์„œ 
ํด๋ผ์ด์–ธํŠธ ์ธก์— “๋ณด์•ˆ๋œ ์ƒํƒœ๋กœ” ์ธ์ฆ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๋Š” ๊ฒƒ์ด JWT ๊ธฐ์ˆ ์ธ ๊ฒƒ

  • ์ด ์ธ์ฝ”๋”ฉ๋œ ์ •๋ณด๋ฅผ “๋””์ฝ”๋”ฉ De-coding”์œผ๋กœ ํ’€์–ด๋‚ด์–ด ๋‹ค์‹œ ๊ฐ’์„ ์–ป์–ด๋‚ผ ์ˆ˜ ์žˆ์„ ๊ฒƒ
  • JWT ์ž์ฒด๋Š” ์•”ํ˜ธํ™”๋˜์ง€ ์•Š์œผ๋ฉฐ, ๋ˆ„๊ตฌ๋‚˜ ๋””์ฝ”๋”ฉํ•˜์—ฌ ๋‚ด์šฉ์„ ๋ณผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ค‘์š”ํ•œ ์ •๋ณด(ex. ๋น„๋ฐ€๋ฒˆํ˜ธ)๋Š”
    JWT์— ํฌํ•จํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์›์น™

  • JWT์—๋Š” ์„œ๋ช…(Signature) ์ด ํฌํ•จ๋˜์–ด ์žˆ์–ด,
    ๋น„๋ฐ€ํ‚ค(Secret Key) ๋˜๋Š” ๊ณต๊ฐœํ‚ค/๊ฐœ์ธํ‚ค(Public/Private Key) ๋กœ ์„œ๋ช…์„ ๊ฒ€์ฆ

  • ์ด๋Ÿฌํ•œ ์„œ๋ช…์œผ๋กœ JWT๊ฐ€ ์œ„์กฐ๋˜์ง€ ์•Š์•˜์Œ์„ ํ™•์ธํ•˜๋Š”๋ฐ ์ฆ‰, JWT์˜ ๋‚ด์šฉ์„ ๋ณ€๊ฒฝํ•˜๋ ค๋ฉด
    ์„œ๋ช…(Signature)๋„ ํ•จ๊ป˜ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ๋น„๋ฐ€ํ‚ค ์—†์ด ์œ„์กฐ๋Š” ๋ถˆ๊ฐ€๋Šฅํ•จ (
    ๋น„๋ฐ€ํ‚ค๋Š” ์„œ๋ฒ„๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ์Œ)

์„ธ์…˜ ๊ณต์œ ์˜ ๋‹จ์ 

  • ์—ฌ๋Ÿฌ ์™ธ๋ถ€ ์ €์žฅ์†Œ์—์„œ ๊ฐ€์ ธ์˜ค๋„๋ก ๊ตฌํ˜„์ด ๋˜์–ด์žˆ์œผ๋ฉด ์„ธ์…˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ณผ์ •์—์„œ
    ๋„คํŠธ์›Œํฌ ์ง€์—ฐ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ
  • ์™ธ๋ถ€ ์ €์žฅ์†Œ์— ์„ธ์…˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ฒŒ๋˜๋ฉด ๋ณด์•ˆ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Œ
  • ์„ฑ๋Šฅ ๋ฌธ์ œ๋กœ ๋งค์šฐ ๋น ๋ฅธ ์ธ๋ฉ”๋ชจ๋ฆฌ ์„ธ์…˜ ์Šคํ† ์–ด์— ๋น„ํ•ด ์™ธ๋ถ€ ์ €์žฅ์†Œ๋Š” ๋А๋ฆด ์ˆ˜ ์žˆ์Œ
    ๋˜ํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅ๋œ ์„ธ์…˜์€ DB์˜ ๋ถ€ํ•˜๋กœ ์„ฑ๋Šฅ ์ €ํ•˜ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Œ

JWT์—์„œ ์ž๋ฐ” ์‚ฌ์šฉ

  • application.yml์— ๋น„๋ฐ€ ํ‚ค, ๋ฆฌํ”„๋ ˆ์‹œ ํ‚ค ์ถ”๊ฐ€ (32๋น„ํŠธ ์ •๋„ ๊ธธ์ด๋กœ ์„ค์ •)
  • SignatureAlgorithm ์ƒ์„ฑ

  • ์ˆซ์ž๊ฐ€ ๋งŽ์„์ˆ˜๋ก ๋” ๋งŽ์€ ๋น„ํŠธ ์ˆ˜๋ฅผ ์ฐจ์ง€ํ•  ์ˆ˜ ์žˆ๊ฒŒ๋จ
public static void main(String[] args) {
    SecretKey secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);

    String jwt = Jwts.builder()
            .setIssuer("juunb-app") // ์–ด๋””์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ธ์ง€ ์„ค์ •
            .setSubject("juunb123")
            .setExpiration(new Date(System.currentTimeMillis() + 36000)) // ๋งŒ๋ฃŒ ์‹œ๊ฐ„ ์„ค์ • (ms ๊ธฐ์ค€)
            .claim("role", "ADMIN")
            .signWith(secretKey) // SIGN์„ ๋งŒ๋“ฆ (secretKey๋ฅผ ์ด์šฉํ•ด์„œ ๋งŒ๋“ฆ)
            .compact();

    System.out.println(jwt); // ํ† ํฐ ์ถœ๋ ฅํ•ด๋ณด๊ธฐ
}

์ถœ๋ ฅ : ํ† ํฐ {eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqdXVuYi1hcHAiLCJzdWIiOiJqdXVuYjEyMyIsImV4cCI6MTc0MTE1MzczMSwicm9sZSI6IkFETUlOIn0.Tw6kHrKKc2BmJCrZ3Cks4FTSwDewEnlDCKa2wv0XLBo}

  • ํ† ํฐ์„ jwt.io์™€ ๊ฐ™์€ ํŽ˜์ด์ง€๋ฅผ ํ†ตํ•ด ๋””์ฝ”๋”ฉํ•ด๋ณด๋ฉด ์„ค์ •ํ•ด๋†จ๋˜ ์ •๋ณด๋“ค์ด ์ถœ๋ ฅ๋˜๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธ (payload ๋ถ€๋ถ„)

Decoding ๋””์ฝ”๋”ฉ

  • ๋””์ฝ”๋”ฉ ํ•˜๋Š” ๊ณผ์ •์„ ์ง์ ‘ ์ž‘์„ฑํ•  ์ˆ˜๋„ ์žˆ์Œ
// JWT ํŒŒ์‹ฑ, ๊ฒ€์ฆ ํŒŒํŠธ
Claims claims = Jwts.parserBuilder()
        .setSigningKey(secretKey)
        .build()
        .parseClaimsJws(jwt)
        .getBody();

log.info("[Decoding Result] - Expiration Time : {}", claims.getExpiration());
log.info("[Decoding Result] - Subject : {}", claims.getSubject());
log.info("[Decoding Result] - Role : {}", claims.getAudience());


SecretKey๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ• 2๊ฐ€์ง€

// 1. ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ secretKey๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•
//        SecretKey secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);

// 2. ์‚ฌ์šฉ์ž ์ •์˜ secretKey๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ• - ์ ์ ˆํ•œ SecretKey(32๋ฐ”์ดํŠธ ์ด์ƒ)๋ฅผ ์ˆ˜๋™ ์ƒ์„ฑ
String secret = "abcdefghijklmnopqrstuvwxzy123456789012"; // ์ตœ์†Œ 32๋ฐ”์ดํŠธ ์œ ์ง€
byte[] bytes = secret.getBytes(StandardCharsets.UTF_8);
SecretKey secretKey = Keys.hmacShaKeyFor(bytes);

1. ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ SecretKey๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•

โžก๏ธ32๋ฐ”์ดํŠธ(256๋น„ํŠธ) ์ด์ƒ์˜ ํ‚ค๋ฅผ ๋‚ด๋ถ€์ ์œผ๋กœ ์•Œ์•„์„œ ์„ค์ •
โžก๏ธSecretKey๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํŽธ๋ฆฌํ•˜์ง€๋งŒ, ๊ณ ์ •๋œ ๊ฐ’์„ ์œ ์ง€ํ•˜๊ธฐ ์–ด๋ ค์›€

โžก๏ธ๋‹จ์  : SecretKey๊ฐ€ ์‹คํ–‰ํ•  ๋•Œ๋งˆ๋‹ค ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Œ
- JWT ์„œ๋ช…์„ ๊ฒ€์ฆ ์‹œ ๊ฐ™์€ SecretKey๊ฐ€ ํ•„์š”ํ•˜๋ฏ€๋กœ, ์ผ์ •ํ•œ ํ‚ค๋ฅผ ์œ ์ง€ํ•ด์•ผ ํ•จ

2. ์‚ฌ์šฉ์ž ์ •์˜ SecretKey๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•

โžก๏ธSecretKey๋ฅผ ์ง์ ‘ ์ •์˜ํ•œ ๋ฌธ์ž์—ด์„ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ์„ฑ
โžก๏ธ๊ณ ์ •๋œ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ, ์„œ๋ฒ„๊ฐ€ ์žฌ์‹œ์ž‘๋˜์–ด๋„ ๊ฐ™์€ SecretKey๋กœ JWT๋ฅผ ๊ฒ€์ฆ ๊ฐ€๋Šฅ

โžก๏ธ์žฅ์  : application.yml ๋˜๋Š” ํ™˜๊ฒฝ ๋ณ€์ˆ˜(.env)์— ์ €์žฅํ•˜์—ฌ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ
์„œ๋ฒ„๊ฐ€ ์žฌ์‹œ์ž‘๋˜๋”๋ผ๋„ ๊ฐ™์€ SecretKey๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ JWT ์„œ๋ช…์„ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ์Œ

โžก๏ธ๋‹จ์  : SecretKey๋ฅผ ์ง์ ‘ ๊ด€๋ฆฌํ•ด์•ผ ํ•จ (๋ณด์•ˆ ์ทจ์•ฝ)


ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์ถ”๊ฐ€ application.yml (SecretKey, RefreshKey)

jwt:
  secretKey: 12345678901234567890123456789012
  refreshKey: 12345678901234567890123456789012

 

JwtTokenizer ํด๋ž˜์Šค

  • JWT ํ† ํฐ์„ ๊ด€๋ฆฌํ•  ํด๋ž˜์Šค, JWT ํ† ํฐ์„ ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ Util ํด๋ž˜์Šค
// JWTํ† ํฐ์„ ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ Util ํด๋ž˜์Šค
@Component
public class JwtTokenizer {
    private final byte[] accessSecret;
    private final byte[] refreshSecret;

    // ์ด accessSecret๊ณผ refreshSecret์„ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ํŒŒ์ผ (application.yml)์—์„œ ๊บผ๋‚ด์„œ ์‚ฌ์šฉํ•  ๊ฒƒ
    public JwtTokenizer(@Value("${jwt.secretKey}") String accessSecret, @Value("${jwt.refreshKey}") String refreshSecret) {
        this.accessSecret = accessSecret.getBytes(StandardCharsets.UTF_8); // String -> byte๋กœ ๋ณ€ํ™˜
        this.refreshSecret = refreshSecret.getBytes(StandardCharsets.UTF_8); // String -> byte๋กœ ๋ณ€ํ™˜
    }
}
  •  @Value("${jwt.secretKey}") String accessSecret
    โžก๏ธ
    @Value ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ํŒŒ์ผ (application.yml)์— ์žˆ๋Š” ๊ฐ’์— ์ ‘๊ทผ ($ { } ํ™œ์šฉ)

  • getBytes(StandardCharsets.UTF_8);
    โžก๏ธString -> byte๋กœ ๋ณ€ํ™˜

 

JwtTokenizer - createToken() ๋ฉ”์†Œ๋“œ ์ถ”๊ฐ€

// ํ† ํฐ์— ํฌํ•จํ•  ์ •๋ณด๋ฅผ ํ•จ๊ป˜ ๋งŒ๋“ฆ
private String createToken(Long id, String email, String name,
                           String username, List<String> roles,
                           Long expire, byte[] secretKeys){
    Claims claims = Jwts.claims().setSubject(email);

    // ํ•„์š”ํ•œ ์ •๋ณด๋“ค ์ €์žฅ
    claims.put("username", username);
    claims.put("name", name);
    claims.put("userId", id);
    claims.put("roles", roles);

    return Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(new Date())
                .setExpiration(new Date(new Date().getTime()+expire))
                .signWith(getSigningKey(secretKeys))
                .compact();
}

  • โ“@Component ์‚ฌ์šฉ ์ด์œ 
    โžก๏ธJwtTokenizer ํด๋ž˜์Šค๋ฅผ Spring์ด ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋„๋ก ํ•จ

    JWT ๊ด€๋ จ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ๊ณตํ†ต ์œ ํ‹ธ ํด๋ž˜์Šค๋กœ์จ ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ์žฌ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋„๋ก ํ•จ
    (= ๋งค๋ฒˆ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ , Spring์ด ํ•œ ๋ฒˆ๋งŒ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌ)

  • Claims claims = Jwts.claims().setSubject(email);
    โžก๏ธid, name ๋“ฑ ์›ํ•˜๋Š” ๊ฒƒ์„ ๋„ฃ์–ด์ฃผ๋ฉด ๋จ
    โžก๏ธ๊ฐ€๊ธ‰์ ์ด๋ฉด ๊ณ ์œ ํ•œ ์‹๋ณ„์ž๊ฐ’ (์ค‘๋ณต X)์„ ๋„ฃ์–ด์ฃผ๋Š” ๊ฒƒ์ด ์ข‹์Œ

    ex. ํ•ด๋‹น Subject์˜ ํ‚ค ๊ฐ’ (๋งŒ์•ฝ ์ด๋ฉ”์ผ ์ธ์ฆ ์„œ๋น„์Šค๋ฉด ์ด๋ฉ”์ผ์„ ๋„ฃ์–ด์คŒ)

    โžก๏ธClaims: JWT์˜ ํŽ˜์ด๋กœ๋“œ(payload) ๋ถ€๋ถ„์„ ์˜๋ฏธ
    setSubject(email): ํ† ํฐ์˜ ์ฃผ์ œ(Subject)๋ฅผ ์ด๋ฉ”์ผ๋กœ ์„ค์ •

  • .setExpiration(new Date(new Date().getTime()+expire))
    expire : 1000ms (1 sec) >> 1000 * 60 * 60 = 1 hour

  • .signWith(getSigningKey(secretKeys))
private static Key getSigningKey(byte[] secretKey){
    return Keys.hmacShaKeyFor(secretKey);
}
  • ์ •์˜ํ•œ ๋ฉ”์†Œ๋“œ getSigninKey() ๋ฅผ ์ด์šฉํ•ด ์ˆ˜ํ–‰
  • JWT์˜ ์„œ๋ช…์„ ์œ„ํ•œ SecretKey ๊ฐ์ฒด ์ƒ์„ฑ
    createToken()์—์„œ ์‚ฌ์šฉํ•˜์—ฌ JWT์˜ Signature(์„œ๋ช…) ๋ถ€๋ถ„์„ ์ƒ์„ฑ

  • signWith() ๋ฉ”์„œ๋“œ๋Š” Key ๊ฐ์ฒด๊ฐ€ ํ•„์š”ํ•˜๋ฏ€๋กœ,→ ๋ฐ”์ดํŠธ ๋ฐฐ์—ด(byte[]) → SecretKey ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜
  • ์ฆ‰, getSigningKey() ๋ฉ”์†Œ๋“œ : ์„œ๋ช…์„ ์œ„ํ•œ SecretKey ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜

 

์ •๋ฆฌํ•˜์ž๋ฉด

1. SecretKey๋ฅผ application.yml์—์„œ ๊ฐ€์ ธ์™€ ์ €์žฅ
2. createToken()์—์„œ JWT์˜ Payload(์‚ฌ์šฉ์ž ์ •๋ณด) ์„ค์ •
3. JWT์˜ ๋ฐœ๊ธ‰ ์‹œ๊ฐ„, ๋งŒ๋ฃŒ ์‹œ๊ฐ„ ์„ค์ •
4. getSigningKey()๋ฅผ ์‚ฌ์šฉํ•ด SecretKey ๊ฐ์ฒด ์ƒ์„ฑ
5. JWT์˜ ์„œ๋ช…(Signature) ์ถ”๊ฐ€
6. ๋งˆ์ง€๋ง‰.compact()๋ฅผ ํ†ตํ•ด JWT ๋ฌธ์ž์—ด ๋ฐ˜ํ™˜


Access Token, Refresh Token ์žฌ์‚ฌ์šฉ

public static final Long ACCESS_TOKEN_EXPIRE_COUNT = 1000L * 60 * 30; // ์•ก์„ธ์Šค ํ† ํฐ ์œ ์ง€์‹œ๊ฐ„ 30๋ถ„
public static final Long REFRESH_TOKEN_EXPIRE_COUNT = 1000L * 60 * 60 * 24 * 7; // ์•ก์„ธ์Šค ํ† ํฐ ์œ ์ง€์‹œ๊ฐ„ 7์ผ

  • ์žฅ์  : ํ† ํฐ ๋งŒ๋ฃŒ ์‹œ๊ฐ„์ด ๊ณ ์ •๋˜์–ด ์žˆ์–ด ๋งค๋ฒˆ ๋‹ค๋ฅด๊ฒŒ ๋ณ€ํ•˜์ง€ ์•Š์Œ

 

Access Token, Refresh Token ์ƒ์„ฑ ๋ฉ”์†Œ๋“œ

// ์•ก์„ธ์Šค ํ† ํฐ ์ƒ์„ฑ
public String createAccessToken(Long id, String email, String name,
                                String username, List<String> roles){

    return createToken(id, email, name, username, roles, ACCESS_TOKEN_EXPIRE_COUNT, accessSecret);
}

// ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ ์ƒ์„ฑ
public String createRefreshToken(Long id, String email, String name,
                                String username, List<String> roles){

    return createToken(id, email, name, username, roles, REFRESH_TOKEN_EXPIRE_COUNT, refreshSecret);
}
  •  ๋‘ ๋ฉ”์†Œ๋“œ๋Š” createToken() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ JWT๋ฅผ ์ƒ์„ฑ
  • Access Token(AT)API ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ ์ธ์ฆ ์šฉ๋„๋กœ ์‚ฌ์šฉ (์งง์€ ์‹œ๊ฐ„ ์œ ์ง€)
  • Refresh Token(RT)Access Token์ด ๋งŒ๋ฃŒ๋˜์—ˆ์„ ๋•Œ ์ƒˆ๋กœ ๋ฐœ๊ธ‰๋ฐ›๋Š” ์šฉ๋„๋กœ ์‚ฌ์šฉ (๋” ๊ธด ์‹œ๊ฐ„ ์œ ์ง€)

  • createToken() ๋ฉ”์†Œ๋“œ์—์„œ๋Š”
    โžก๏ธํ† ํฐ ์ƒ์„ฑ์˜ ํ•ต์‹ฌ ๋กœ์ง์„ ๋‹ด๋‹น
    โžก๏ธ
    ๊ณตํ†ต์ ์ธ JWT ์ƒ์„ฑ ๊ณผ์ •์„ ์บก์Аํ™”ํ•˜์—ฌ ์ฝ”๋“œ ์ค‘๋ณต์„ ์ค„์ž„

 

Main ํ…Œ์ŠคํŠธ

public static void main(String[] args) {
    JwtTokenizer jwtTokenizer = new JwtTokenizer(
            "12345678901234567890123456789012",
            "12345678901234567890123456789012");

    String accessToken = jwtTokenizer.createAccessToken(1L, "test@test.com", "test", "testuser", Arrays.asList("ROLE_USER"));

    log.info("[ACCESS TOKEN] : {}", accessToken);
}

โžก๏ธ์ถœ๋ ฅ : [ACCESS TOKEN] : eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0Q……


๐Ÿš€ํšŒ๊ณ  ๊ฒฐ๊ณผ :
์ด๋ฒˆ ํšŒ๊ณ ์—์„œ๋Š” ์„ธ์…˜์— ๋Œ€ํ•œ ๊ฐœ๋…์„ ๋‹ค์‹œ ํ•™์Šตํ•˜๊ณ  Spring Security์—์„œ์˜ ์ ์šฉ๊ณผ JWT ์‚ฌ์šฉ์„ ๋‹ค์–‘ํ•œ ์˜ˆ์ œ๋กœ ์ ‘ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

- Session Management๋ฅผ ํ†ตํ•œ ์„ธ์…˜ ์„ค์ •
- JWT๋กœ AccessToken, Refresh Token ์ƒ์„ฑ

๋А๋‚€ ์  : 
์ด๋ฉ”์ผ๋กœ ์ „์†ก๋˜๋Š” "๋กœ๊ทธ์ธ ํ™•์ธ ๋ฉ”์ผ"๊ณผ ๊ธฐ์กด ๋ธŒ๋ผ์šฐ์ €์—์„œ "์ƒˆ ํƒญ"์„ ์—ด์—ˆ์„๋•Œ๋„ ๋กœ๊ทธ์ธ์ด ์ง€์†๋˜์—ˆ๋˜ ๊ฒƒ์ด
์„ธ์…˜๊ณผ ๊ด€๋ จ์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ๋‹ค.
์‹œํฌ๋ฆฟ๋ชจ๋“œ์—์„œ๋„ ์„ธ์…˜์ด ์œ ์ง€๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ  ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Session Management๋กœ ์„ธ์…˜์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

ํ–ฅํ›„ ๊ณ„ํš : 

- JwtTokenizer์˜ ํ† ํฐ ์ƒ์„ฑ ๊ณผ์ • ํ•™์Šต
- REFRESH TOKEN ์ƒ์„ฑํ•ด๋ณด๊ธฐ