์ค๋ ์ง์คํด์ ํ๋ฉด ๋ง๋ฌด๋ฆฌ ํ ์ค ์์๋๋ฐ ์ธ์ฆ ๋ถ๋ถ์์ ๋๋ฌด ์ค๋ ์๊ฐ์ด ๊ฑธ๋ ธ๋ค.
ํ๋ก ํธ ์ฝ๋์ API ์คํ์ Flask์ ๊ฑฐ์ ๋์ผํ๊ฒ ํ๋ ค๋ค ๋ณด๋ ์ธ์ผ Spring์ด ๋ถํธํ๊ฒ ๋๊ปด์ก๋ค..
์ผ๋จ ์ธ์ฆ๋ถ๋ถ.
์๋ ํ๋ ๋๋ก JWT ํ ํฐ์ ๋ฐ๊ธํ๊ณ ํด๋ผ์ด์ธํธ์ localStorage์ ์ ์ฅํ๊ณ ๋งค ajax ์์ฒญ๋ง๋ค ํ ํฐ์ ๋ค๊ณ ์ค๋๋ก ๊ตฌํํ๋ค.
์ฐ์ JWT ํ ํฐ์ ์์ฑํ๊ณ ๊ฒ์ฆํ๋ ๊ธฐ๋ฅ์ ์ํํ๋ ํด๋์ค๋ฅผ ์ ์ํ๋ค.
์ด ๋ถ๋ถ์ ์์ ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ์ ๊ณตํด์ฃผ์ง ์๋ ๊ฒ์ด ์ฌํ๋ค..ใ
@Slf4j
@Component
public class JwtUtils {
private final String SECRET = "secret";
private final SignatureAlgorithm SIGNATURE = SignatureAlgorithm.HS256;
// ํ ํฐ ์์ฑ
// Claim์ subject ์ญํ ์ username๊ณผ ๋ง๋ฃ์๊ฐ ๋๊ฐ์ง๋ฅผ ์ค์
public String createToken(String subject) {
Claims claims = Jwts.claims();
claims.put("username", subject);
return Jwts.builder()
.claim("username", subject)
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60))
.signWith(SIGNATURE, SECRET)
.compact();
}
// ํ ํฐ์ Claim์์ username์ ๊ฐ์ ธ์จ๋ค.
public String getUsernameFromToken(String token) {
Claims claims = getAllClaims(token);
return String.valueOf(claims.get("username"));
}
// ํ ํฐ ์ ํจ์ฌ๋ถ ํ์ธ
// ํ์ฌ๋ ํ ํฐ์ ๋ง๋ฃ์๊ฐ๋ง์ ๊ฒ์ฆ
public Boolean isValidToken(String token) {
Date expiration = getAllClaims(token).getExpiration();
return expiration.after(new Date());
}
private Claims getAllClaims(String token) {
return Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token)
.getBody();
}
}
Spring Security์ ํํฐ์ฒด์ธ์ JWT๋ฐฉ์์ ์ธ์ฆ์ด ๊ฐ๋ฅํ๋๋ก ํํฐ๋ฅผ ์ ์ํ์ฌ ์ถ๊ฐํด์ค์ผ ํ๋ค.
์์ง ๋ง์ด ๊ฐ์ ์ด ํ์ํ ๋ถ๋ถ์ด๋ค.
์ต๋ํ ๋ํผ๋ฐ์ค ์์ด ์ฝ๋๋ฅผ ๊ตฌํ์ ์๋ฃํ๋๋ฐ ๋ค ํ๊ณ ์ฌ๋ฌ ์ฌ๋ฌ ์ฝ๋๋ฅผ ์ฐพ์๋ณด๋ ์ง๊ธ์ ํํฐ๋ ์กฐ๊ธ ๋ถ์กฑํ ๊ฒ ๊ฐ๋ค. ์๋ฌดํผ!
๊ฐ๋จํ๊ฒ ์ ์ฐจ๋ฅผ ์ ๋ฆฌํด๋ณด์.
UsernamePasswordAuthenticationToken
) SecurityContextHolder
์ ์ ์ฅํ๋ค.doFilter
์ฒ๋ฆฌ@Component
@Slf4j
@RequiredArgsConstructor
public class JwtAuthenticateFilter extends OncePerRequestFilter {
private final UserDetailsServiceImpl userDetailsService;
private final JwtUtils jwtUtils;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authorization = request.getHeader("Authorization");
if (authorization != null && authorization.startsWith("Bearer ")) {
String token = authorization.substring(7);
if (jwtUtils.isValidToken(token)) {
log.info("JWT ํํฐ = {}", token);
String username = jwtUtils.getUsernameFromToken(token);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken
= new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
filterChain.doFilter(request, response);
}
}
๋ง์ง๋ง์ผ๋ก Controller์์์ ์ฒ๋ฆฌ์ด๋ค.
์ด ์ํธํฌ์ธํธ์ ์๋ค๋ ๊ฒ์ ํ์ฌ JWT ํ ํฐ์ด ์๋ ์ํ์์ ๋ก๊ทธ์ธ์ ํ๋ค๋ ๊ฒ์ด๋ค.
์ ๋ฌ๋ฐ์ ์์ด๋, ํจ์ค์๋๋ฅผ ๊ฒ์ฆํด๋ณด๊ณ ์ด์์๋ค๋ฉด ์ ๋ฌ๋ฐ์ ๋ก๊ทธ์ธ ์ ๋ณด๋ก UserDetails
๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ ์ด๋ฅผ ์ด์ฉํด์ JWT ํ ํฐ์ ์์ฑํ๊ณ ํด๋ผ์ด์ธํธ์๊ฒ ์ ๋ฌํ๋ค.
ํด๋ผ์ด์ธํธ๋ ๋ฐ์์ ์ ์ ์ฅํ๊ณ ์ ๋ณด๋ด์ฃผ๋ฉด ๋๋ค.
@PostMapping("/signin")
public TokenResponseDto signin(@RequestBody SignupRequestDto requestDto) {
log.info("๋ก๊ทธ์ธ ์์ฒญ = {}", requestDto.getUsername());
try {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(requestDto.getUsername(), requestDto.getPassword())
);
} catch (BadCredentialsException e) {
throw new BadCredentialsException("๋ก๊ทธ์ธ์ ์คํจํ์ต๋๋ค.");
}
UserDetails userDetails = userDetailsService.loadUserByUsername(requestDto.getUsername());
String token = jwtUtils.createToken(userDetails.getUsername());
log.info("๋ก๊ทธ์ธ ํ ํ ํฐ = {}", token);
return new TokenResponseDto(token, "๋ก๊ทธ์ธ์ ์ฑ๊ณตํ์ต๋๋ค.");
}
์ด ๋ฐฉ๋ํ ํ๋ ์์ํฌ์ ๋ฃฐ์ ๋ฐ๋ผ์ผ ํ๋ ๊ฒ์ด ๊ฐ๋ฐ์ ํ๋ค๊ฒ ํ์ง๋ง ๋ค ์ด์ ๊ฐ ์์ง ์์๊น ์ถ๋ค..ใ ๊ผญ ์ด์ ๊ฐ ์์ด์ผ ํ๋ค ..