Spring Security์์ JWT(JSON Web Token) ์ธ์ฆ์ ์ผ๋ฐ์ ์ผ๋ก ๋ค์ ๋จ๊ณ๋ฅผ ๊ฑฐ์นฉ๋๋ค.
Authorization: Bearer <ํ ํฐ>).JwtAuthenticationFilter)๊ฐ ์์ฒญ์ ๊ฐ๋ก์ฑ์:SecurityContext์ ์ธ์ฆ ๊ฐ์ฒด ์ ์ฅ@AuthenticationPrincipal ๋ฑ์ ํตํด ์ธ์ฆ๋ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ํ์ฉ.์ด ํํฐ๋ ๋ชจ๋ HTTP ์์ฒญ์ ๊ฐ๋ก์ฑ JWT๋ฅผ ๊ฒ์ฆํ๊ณ ์ธ์ฆ ์ฌ๋ถ๋ฅผ ํ์ธํ๋ ํต์ฌ์ ์ธ ์ญํ ์ ํฉ๋๋ค.
package com.example.demo.security;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.*;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.*;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtTokenProvider jwt;
private final UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
throws ServletException, IOException {
// 1. ์์ฒญ ํค๋์์ Authorization ๊ฐ ๊ฐ์ ธ์ค๊ธฐ
String header = req.getHeader("Authorization");
// 2. "Bearer "๋ก ์์ํ๋์ง ํ์ธ
if (header != null && header.startsWith("Bearer ")) {
String token = header.substring(7);
// 3. ํ ํฐ ์ ํจ์ฑ ๊ฒ์ฆ
if (jwt.validate(token)) {
// 4. ํ ํฐ์์ ์ฌ์ฉ์ ์ด๋ฆ(username) ์ถ์ถ
String username = jwt.getUsername(token);
// 5. DB์์ ์ฌ์ฉ์ ์ ๋ณด ๋ก๋
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
// 6. ์ฌ์ฉ์ ์ ๋ณด ๊ธฐ๋ฐ ์ธ์ฆ ๊ฐ์ฒด ์์ฑ
UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
// 7. SecurityContext์ ์ธ์ฆ ๊ฐ์ฒด ์ ์ฅ
SecurityContextHolder.getContext().setAuthentication(auth);
}
}
// 8. ๋ค์ ํํฐ/์ปจํธ๋กค๋ฌ๋ก ์์ฒญ ์ ๋ฌ
chain.doFilter(req, res);
}
}
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter
@Component: ์ด ํด๋์ค๋ฅผ Spring Bean์ผ๋ก ๋ฑ๋กํ์ฌ Spring IoC ์ปจํ
์ด๋๊ฐ ๊ด๋ฆฌํ๊ฒ ํฉ๋๋ค.OncePerRequestFilter: ํ ๋ฒ์ ์์ฒญ(request)์ ๋ํด ๋จ ํ ๋ฒ๋ง ์คํ๋๋ ํํฐ๋ฅผ ๋ณด์ฅํฉ๋๋ค.@RequiredArgsConstructor: final ํ๋(jwt, userDetailsService)๋ฅผ ์ธ์๋ก ๋ฐ๋ ์์ฑ์๋ฅผ ์๋์ผ๋ก ์์ฑํ์ฌ **์์กด์ฑ ์ฃผ์
(DI)**์ ์ฒ๋ฆฌํฉ๋๋ค.Authorization ํค๋ ์ฒ๋ฆฌString header = req.getHeader("Authorization");
if (header != null && header.startsWith("Bearer ")) {
String token = header.substring(7);
}
ํด๋ผ์ด์ธํธ๊ฐ ์ ์กํ HTTP ์์ฒญ์ Authorization ํค๋์์ JWT๋ฅผ ์ถ์ถํฉ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก JWT๋ "Bearer <ํ ํฐ๊ฐ>" ํ์์ผ๋ก ์ ๋ฌ๋๋ฏ๋ก, "Bearer " ์ ๋์ด๋ฅผ ์ ๊ฑฐํ๊ณ ์์ ํ ํฐ ๊ฐ๋ง ์ป์ต๋๋ค.
if (jwt.validate(token)) {
String username = jwt.getUsername(token);
}
**JwtTokenProvider**๋ฅผ ์ฌ์ฉํ์ฌ ํ ํฐ์ ์ ํจ์ฑ์ ๊ฒ์ฌํฉ๋๋ค. ํ ํฐ์ด ์ ํจํ๋ค๋ฉด, ํ ํฐ ๋ด์ ์ ์ฅ๋ **์ฌ์ฉ์ ์ด๋ฆ(Subject)**์ ์ถ์ถํฉ๋๋ค.
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
**UserDetailsService**๋ Spring Security์์ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ ๊ณตํ๋ ํต์ฌ ์ธํฐํ์ด์ค์
๋๋ค. ์ด๋ฅผ ํตํด ์ถ์ถํ ์ฌ์ฉ์ ์ด๋ฆ์ผ๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ๋ค๋ฅธ ์ ์ฅ์์์ ์ฌ์ฉ์ ๊ณ์ ์ ๋ณด๋ฅผ UserDetails ๊ฐ์ฒด๋ก ๊ฐ์ ธ์ต๋๋ค.
SecurityContext ์ ์ฅUsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(auth);
**์ธ์ฆ ๊ฐ์ฒด(Authentication)**๋ฅผ ์์ฑํ๊ณ SecurityContextHolder์ ์ ์ฅํฉ๋๋ค.
null๋ก ์ค์ ๊ฐ๋ฅ.์ด๋ ๊ฒ SecurityContextHolder์ ์ ์ฅ๋ ์ธ์ฆ ์ ๋ณด๋ ์ดํ ์ปจํธ๋กค๋ฌ๋ ์๋น์ค ๊ณ์ธต์์ ์ ์ญ์ ์ผ๋ก ์ ๊ทผํ ์ ์์ต๋๋ค.
JwtAuthenticationFilter๋ ๋ชจ๋ ์์ฒญ์ ๊ฐ๋ก์ฑ JWT๋ฅผ ๊ฒ์ฆํ๋ ํต์ฌ ํํฐ์
๋๋ค.SecurityContext์ ์ธ์ฆ ๊ฐ์ฒด๋ฅผ ์ ์ฅํ์ฌ Spring Security ์ ์ญ์์ ์ธ์ฆ ์ํ๋ฅผ ์ ์งํฉ๋๋ค.@AuthenticationPrincipal ๋ฑ์ ํ์ฉํ์ฌ ์ธ์ฆ๋ ์ฌ์ฉ์ ์ ๋ณด์ ์์ฝ๊ฒ ์ ๊ทผํ ์ ์์ต๋๋ค.401 Unauthorized ์๋ต์ ๋ฐํํ๋๋ก ์์ธ ์ฒ๋ฆฌ๋ฅผ ์ถ๊ฐํ์ฌ ํํฐ๋ฅผ ๊ฐ์ ํ ์ ์์ต๋๋ค.