좋아! 🔥 요즘 웹 서비스에서 JWT (JSON Web Token) 기반 인증은 거의 표준처럼 쓰이는 방식이라서 제대로 알고 구현하면 진짜 큰 무기가 돼.
서버가 사용자를 인증한 후, 사용자 정보가 들어있는 토큰을 발급해서
클라이언트가 이후 요청 시 그 토큰으로 인증하는 방식이야.
xxxxx.yyyyy.zzzzz
(Header).(Payload).(Signature)
[1] 로그인 요청
↓
[2] 서버가 사용자 정보 확인 후 JWT 발급
↓
[3] 클라이언트는 JWT를 로컬/세션스토리지에 저장
↓
[4] 이후 모든 요청 헤더에 JWT 포함 (Authorization: Bearer <token>)
↓
[5] 서버는 토큰 유효성 검사 후 요청 처리
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'
public class JwtUtil {
private static final String SECRET_KEY = "mySecretKey";
public String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60)) // 1시간
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
public String extractUsername(String token) {
return Jwts.parser().setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token);
return true;
} catch (JwtException e) {
return false;
}
}
}
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtUtil jwtUtil;
public JwtAuthenticationFilter(JwtUtil jwtUtil) {
this.jwtUtil = jwtUtil;
}
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String token = authHeader.substring(7);
if (jwtUtil.validateToken(token)) {
String username = jwtUtil.extractUsername(token);
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(username, null, List.of());
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
filterChain.doFilter(request, response);
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final JwtUtil jwtUtil;
public SecurityConfig(JwtUtil jwtUtil) {
this.jwtUtil = jwtUtil;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(new JwtAuthenticationFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class);
}
}
@RestController
public class AuthController {
private final JwtUtil jwtUtil;
public AuthController(JwtUtil jwtUtil) {
this.jwtUtil = jwtUtil;
}
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody LoginRequest req) {
// 아이디/비번 검증 (생략)
String token = jwtUtil.generateToken(req.getUsername());
return ResponseEntity.ok().body(Map.of("token", token));
}
}
| 이유 | 설명 |
|---|---|
| ✅ 서버에 세션 저장 안 해도 됨 (Stateless) | |
| ✅ 마이크로서비스, 모바일 앱 등과 연동 편함 | |
| ✅ 토큰 기반으로 인증·인가 분리 가능 |
UserDetailsService와 연동원하면 내가 JSP 기반 로그인 페이지 + JWT 연동 흐름으로도 맞춰서 짜줄게!
아니면 Spring + React 구조로도 스무스하게 이어줄 수 있어 😎
너 지금 어떤 방향으로 하고 있어? (JSP 기반이었나?)