์์ฒด ํฌํจํ (Self-Contained): JWT๋ ํ ํฐ์ ํ์ํ ๋ชจ๋ ์ ๋ณด๋ฅผ ๋ด๋ถ์ ํฌํจํ์ฌ ์ ์ฅ
์ธํฐ๋ท ์ ๋ฌ ์ฉ์ด์ฑ: JWT๋ URL-Safeํ ํ ์คํธ๋ก ๊ตฌ์ฑ๋์ด ์์ด HTTP ํ๋กํ ์ฝ์ ์ด๋ ์์น์๋ ์ฝ๊ฒ ์ ๋ฌ ๊ฐ๋ฅ
์๋ณ์กฐ ๊ฒ์ฆ ๊ฐ๋ฅ: JWT๋ ๋ฐ์ดํฐ์ ๋ฌด๊ฒฐ์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํด ์๋ช (Signature)์ ํฌํจํ๋ฉฐ, ์ด ์๋ช ์ ํตํด ํ ํฐ์ด ์๋ณ์กฐ๋์ง ์์์์ ๊ฒ์ฆ
์ฅ์
์์ฒด ํฌํจํ ๋ฐ์ดํฐ
Active User ๊ด๋ฆฌ ์ฉ์ด์ฑ
๋จ์
ํ ํฐ ํฌ๊ธฐ ์ ํ
๊ฐ์ ์ ์ธ ๋ง๋ฃ ์ฒ๋ฆฌ ์ด๋ ค์
์ํ ๊ด๋ฆฌ์ ์ด๋ ค์
@Component
@ConfigurationProperties(prefix = "jwt")
@Data
public class JwtConfigure {
private String header;
private String issuer;
private String clientSecret;
private int expirySeconds;
}
public final class Jwt {
private final String issuer;
private final String clientSecret;
private final int expirySeconds;
private final Algorithm algorithm;
private final JWTVerifier jwtVerifier;
public Jwt(String issuer, String clientSecret, int expirySeconds) {
this.issuer = issuer;
this.clientSecret = clientSecret;
this.expirySeconds = expirySeconds;
this.algorithm = Algorithm.HMAC512(clientSecret);
this.jwtVerifier = com.auth0.jwt.JWT.require(algorithm)
.withIssuer(issuer)
.build();
}
public String sign(Claims claims) {
Date now = new Date();
JWTCreator.Builder builder = com.auth0.jwt.JWT.create();
builder.withIssuer(issuer);
builder.withIssuedAt(now);
if (expirySeconds > 0) {
builder.withExpiresAt(new Date(now.getTime() + expirySeconds * 1000));
}
builder.withClaim("username", claims.username);
builder.withArrayClaim("roles", claims.roles);
return builder.sign(algorithm);
}
public Claims verify(String token) throws JWTVerificationException {
return new Claims(jwtVerifier.verify(token));
}
// ... ์๋ต ...
static public class Claims {/*์๋ต*/}
}
public class JwtAuthenticationFilter extends GenericFilterBean {
private final Logger log = LoggerFactory.getLogger(getClass());
private final String headerKey;
private final Jwt jwt;
public JwtAuthenticationFilter(String headerKey, Jwt jwt) {
this.headerKey = headerKey;
this.jwt = jwt;
}
/**
* HTTP ์์ฒญ ํค๋์ JWT ํ ํฐ์ด ์๋์ง ํ์ธ
* JWT ํ ํฐ์ด ์๋ค๋ฉด, ์ฃผ์ด์ง ํ ํฐ์ ๋์ฝ๋ฉ ํ๊ณ ,
* username, roles ๋ฐ์ดํฐ๋ฅผ ์ถ์ถํ๊ณ , UsernamePasswordAuthenticationToken ์์ฑ
* ์ด๋ ๊ฒ ๋ง๋ค์ด์ง UsernamePasswordAuthenticationToken ์ฐธ์กฐ๋ฅผ SecurityContext์ ๋ฃ์ด์ค
*/
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (SecurityContextHolder.getContext().getAuthentication() == null) {
String token = getToken(request);
if (token != null) {
try {
Jwt.Claims claims = verify(token);
log.debug("Jwt parse result: {}", claims);
String username = claims.username;
List<GrantedAuthority> authorities = getAuthorities(claims);
if (isNotEmpty(username) && authorities.size() > 0) {
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, authorities);
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception e) {
log.warn("Jwt processing failed: {}", e.getMessage());
}
}
} else {
log.debug("SecurityContextHolder not populated with security token, as it already contained: '{}'", SecurityContextHolder.getContext().getAuthentication());
}
chain.doFilter(request, response);
}
private String getToken(HttpServletRequest request) {
//์๋ต
}
private Jwt.Claims verify(String token) {
return jwt.verify(token);
}
private List<GrantedAuthority> getAuthorities(Jwt.Claims claims) {
//์๋ต
}
}
@Configuration
public class WebSecurityConfigure {
private final JwtConfigure jwtConfigure;
@Bean
public Jwt jwt() {
return new Jwt(
jwtConfigure.getIssuer(),
jwtConfigure.getClientSecret(),
jwtConfigure.getExpirySeconds()
);
}
public JwtAuthenticationFilter jwtAuthenticationFilter(Jwt jwt) {
return new JwtAuthenticationFilter(
this.jwtConfigure.getHeader(),
jwt
);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
/**
* Jwt ํํฐ ์ถ๊ฐ
*/
.addFilterAfter(jwtAuthenticationFilter(jwt), SecurityContextHolderFilter.class)
.build();
}
}
๋ง์ ๋์์ด ๋์์ต๋๋ค, ๊ฐ์ฌํฉ๋๋ค.