๋๋ ์ง๊ธ
JWT ํ ํฐ ์์ฑ + ์ ํจ์ฑ ๊ฒ์ฌํ๋ ํด๋์ค ๊ณต๋ถํ๋ค๊ฐ
์๊ธด ๊ถ๊ธ์ฆ๋ค์ด ์์ด์
์ ๋ฆฌ ํ๋ ค๊ณ ํจ
โ
๊ฑ ๋ด๊ฐ ์ดํดํ๋ฉด์ ์ฃผ์ ์ฃผ์ ์ฐ๋๊ฑฐ๋ผ
์ฝ๊ธฐ ์์ข์ ์ ์์..ใ
โ
/*
ํ ํฐ ์์ฑ & ์ฌ๋ฐ๋ฅธ ํ ํฐ์ธ์ง ์ ํจ์ฑ ๊ฒ์ฌ
ํ ํฐ์์ ํ์ํ ์ ๋ณด ๊ฐ์ ธ์ค๋ ํด๋์ค
*/
@RequiredArgsConstructor
@Service
public class TokenProvider {
private final JwtProperties jwtProperties;
public String generateToken(User user, Duration expiredAt) {
Date now = new Date();
return makeToken(new Date(now.getTime() + expiredAt.toMillis()), user);
}
// JWT ํ ํฐ ์์ฑ ๋ฉ์๋
private String makeToken(Date expiry, User user) {
Date now = new Date();
return Jwts.builder()
.setHeaderParam(Header.TYPE, Header.JWT_TYPE)
.setIssuer(jwtProperties.getIssuer())
.setIssuedAt(now)
.setExpiration(expiry)
.setSubject(user.getEmail())
.claim("id", user.getId())
.signWith(SignatureAlgorithm.HS256, jwtProperties.getSecretKey())
.compact();
}
// JWT ํ ํฐ ์ ํจ์ฑ ๊ฒ์ฆ ๋ฉ์๋
public boolean validToken(String token) {
try{
Jwts.parser().setSigningKey(jwtProperties.getSecretKey())
.parseClaimsJws(token);
return true;
} catch (Exception e){
return false;
}
}
// ํ ํฐ ๊ธฐ๋ฐ์ผ๋ก ์ธ์ฆ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ๋ฉ์๋
public Authentication getAuthentication(String token) {
Claims claims = getClaim(token);
Set<SimpleGrantedAuthority> authorities = Collections.singleton(new SimpleGrantedAuthority("ROLE_USER"));
return new UsernamePasswordAuthenticationToken(new org.springframework.security.core.userdetails.User(claims.getSubject(), "", authorities), token, authorities);
}
// ํ ํฐ ๊ธฐ๋ฐ์ผ๋ก ์ ์ ID ๊ฐ์ ธ์ค๋ ๋ฉ์๋
public Long getUserId(String token) {
Claims claims = getClaim(token);
return claims.get("id", Long.class);
}
private Claims getClaim(String token) {
return Jwts.parser()
.setSigningKey(jwtProperties.getSecretKey())
.parseClaimsJws(token)
.getBody();
}
}
์ผ๋จ JWT์ ์ญํ ์
ํฐ์ผ๊ฐ์๊ฑฐ์. ์ฆ๋ช ์ ์ญํ ??
์๋ฒ์ ์ฅ์์๋, '์ด ์ ์ ๊ฐ ์ง์ง ๋ก๊ทธ์ธํ๋ค ๊ทธ ์ฌ์ฉ์๊ฐ ๋ง๊ตฌ๋'๋ผ๊ณ
ํ์ธํ๋ ์ฆ๋ช ์์ ๋ถ๊ณผํจ.
โ
๋ฐ๋ฉด์ Authenticaion๊ฐ์ฒด๋
์คํ๋ง ์ํ๋ฆฌํฐ๊ฐ ๋ด๋ถ์์ ์ฐ๋
๋ก๊ทธ์ธ ์ํ ํํ ๊ฐ์ฒด ๋ผ๊ณ ํจ.
์๋ฒ๋ ์ด ๊ฐ์ฒด๋ฅผ ๊ธฐ์ค์ผ๋ก
'์ง๊ธ ์์ฒญ ๋ณด๋ธ ์ฌ๋ ๋๊ตฌ์ง?'
'์ด ์ฌ๋ ๊ถํ ์๋?'
'๋ก๊ทธ์ธ ๋์ด์๋?'
๋ฑ๋ฑ์ ํ๋จํ๊ฒ ๋จ.
โ
โ
โ
๊ตณ์ด Authentication๊ฐ์ฒด๋ฅผ ์ ๋ง๋ค๊น?
JWT์์๋ ํ์ด๋ก๋ ๋ด์ฉ์ด ์๋๋ฐ,
๊ทธ๊ฑธ ๋ณด๊ณ ๋๊ตฐ์ง, ์ ํจ๊ธฐ๊ฐ ์ธ์ ์ง ๋ณด๋ฉด ๋๋๊ฑฐ ์๋?!
๋ ์ด๋ฌ์ผ ์๊ฐํ๊ธฐ๋๋ฌธ์
Authentication๊ฐ์ฒด์ ํ์์ฑ์ ๋ํด์ ๊ถ๊ธํ์.
โ
์ผ๋จ ํ์ํ ์ด์
1. Spring Security ๊ฐ ์๋ํ๋ ค๋ฉด ํ์ํจ
์คํ๋ง ์ํ๋ฆฌํฐ๋ ๋ด๋ถ์ ์ผ๋ก
โ
a. ํด๋ผ์ด์ธํธ๊ฐ JWT ๊ฐ๊ณ ์์ฒญํจ
b. ํํฐ๊ฐ JWT๋ฅผ ํ์ฑ -> ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ถ์ถํจ
c. ๊ทธ๊ฑธ ๋ฐํ์ผ๋ก Authentication๊ฐ์ฒด ๋ง๋ฆ
d. ๊ทธ๊ฑธ SecurityContextHolder์ ์ ์ฅ
e. ์ดํ์ @AuthenticationPrinciple, hasRole ๋ฑ์์ ์ธ์ฆ๋ ์ฌ์ฉ์๋ก ์ธ์.
โ
-> ์ฆ, ์คํ๋ง ์ํ๋ฆฌํฐ๊ฐ ์ธ์ฆ๋ ์ฌ์ฉ์๋ก ์ธ์ํ๊ณ ๊ถํ ์ฒดํฌํ ๋ผ๋ฉด
๋ฐ๋์ Authentication๊ฐ์ฒด๊ฐ ํ์ํ๊ฑฐ์.
โ
โ
2. ์๋ฒ ๋ด๋ถ์์ ์ธ์ฆ/์ธ๊ฐ ์ฒ๋ฆฌ๋ฅผ ์ํด ํ์ํจ
์๋ฅผ ๋ค์ด, ์ปจํธ๋กค๋ฌ์์ ํ์ฌ ๋ก๊ทธ์ธํ ์ฌ์ฉ์ ์ ๋ณด๊ฐ ํ์ํ ๋
@GetMapping("/profile")
public ResponseEntity<UserProfile> myProfile(@AuthenticationPrincipal UserDetails userDetails) {
// ์ฌ๊ธฐ์ userDetails = Authentication ๊ฐ์ฒด ์์ ์๋ principal
return userService.getProfile(userDetails.getUsername());
}
์ด๋ฐ์์ผ๋ก ์.
์ด๊ฒ ๊ฐ๋ฅํ๋ ค๋ฉด Authentication๊ฐ์ฒด ๋ง๋ค์ด์
SecurityContextHolder์ ๋ฑ๋กํด์ผ๋จ. ๊ทธ๋์ผ
@AuthenticationPrinciple ์ด๋ ธํ ์ด์ ์ธ ์ ์์.
โ
โ
โ
โ
์๋ฌดํผ JWT๋ ๊ทธ๋ฅ Stirng ๋ฌธ์์ด, ์ฆ๊ฑฐ์ผ๋ฟ.
Spring Security๋ ๊ทธ ํ ํฐ์ ๋ณด๊ณ ํ์ฑํด์
Authentication๊ฐ์ฒด ๋ง๋ค์ด์ ์ ์ฅํด๋ฌ์ผํจ.
โ
๊ทธ๊ฑธ ์ํ ๋ฉ์๋๊ฐ getAuthentication()๋ฉ์๋!
(์ด ๋ฉ์๋ ๋ณด๋ฉด getClaimํจ์ ์จ์ ๋ญ ๊ฐ์ ธ์ค๊ณ ์๋๋ฐ,
์ด๊ฒ token๋ฐ์์ ๊ทธ ์์ ์ ๋ณด ์ถ์ถํด์ค๋ ๋ถ๋ถ์!)