[ ] Stateless Spring Security JWT |
@RequestMapping(value = "/login", produces = "application/json", method = RequestMethod.GET)
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void login(HttpServletResponse response) {
SessionUser user = (SessionUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
tokenAuthenticationService.addAuthentication(response, user);
SecurityContextHolder.getContext().setAuthentication(null);
}
public void addAuthentication(HttpServletResponse response, SessionUser user) {
Cookie access = new Cookie("access_token", tokenHandler.createAccessToken(user));
access.setPath("/");
access.setHttpOnly(true);
response.addCookie(access);
Cookie refresh = new Cookie("refresh_token", tokenHandler.createRefreshToken(user));
refresh.setPath("/");
refresh.setHttpOnly(true);
response.addCookie(refresh);
}
public String createRefreshToken(SessionUser user) {
// , username
}
public SessionUser parseRefreshToken(String token) {
// username UserDetailsService
}
public String createAccessToken(SessionUser user) {
// , SessionUser
}
public SessionUser parseAccessToken(String token) {
// SessionUser
}
@Bean
public TokenAuthenticationService tokenAuthenticationService() {
return new TokenAuthenticationService();
}
@Bean
public TokenHandler tokenHandler() {
return new TokenHandler();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//
.antMatchers("/", "/login").permitAll()
//
.anyRequest().authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService()), UsernamePasswordAuthenticationFilter.class)
}
public class StatelessAuthenticationFilter extends GenericFilterBean {
private final TokenAuthenticationService tokenAuthenticationService;
public StatelessAuthenticationFilter(TokenAuthenticationService tokenAuthenticationService) {
this.tokenAuthenticationService= tokenAuthenticationService;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
Authentication authentication = tokenAuthenticationService.getAuthentication(httpRequest, httpResponse);
SecurityContextHolder.getContext().setAuthentication(authentication);
filterChain.doFilter(request, response);
SecurityContextHolder.getContext().setAuthentication(null);
}
}
access ?TokenAuthenticationService:
? .
?
?
? .
? access refresh .
?
? , access .
? .
public Authentication getAuthentication(HttpServletRequest request, HttpServletResponse response) {
Cookie[] cookies = request.getCookies();
String accessToken = null;
String refreshToken = null;
if (cookies != null) {
for (Cookie cookie : cookies) {
if (("access_token").equals(cookie.getName())) {
accessToken = cookie.getValue();
}
if (("refresh_token").equals(cookie.getName())) {
refreshToken = cookie.getValue();
}
}
}
if (accessToken != null && !accessToken.isEmpty()) {
try {
SessionUser user = tokenHandler.parseAccessToken(accessToken);
return new UserAuthentication(user);
} catch (ExpiredJwtException ex) {
if (refreshToken != null && !refreshToken.isEmpty()) {
try {
SessionUser user = tokenHandler.parseRefreshToken(refreshToken);
Cookie access = new Cookie("access_token", tokenHandler.createAccessToken(user));
access.setPath("/");
access.setHttpOnly(true);
response.addCookie(access);
return new UserAuthentication(user);
} catch (JwtException e) {
return null;
}
}
return null;
} catch (JwtException ex) {
return null;
}
}
return null;
}
1. id (BIGINT)RefreshTokenDao JdbcTemplate :
2. username (VARCHAR)
3. token (VARCHAR)
4. expires (TIMESTAMP)
public void insert(String username, String token, long expires) {
String sql = "INSERT INTO refresh_token "
+ "(username, token, expires) VALUES (?, ?, ?)";
jdbcTemplate.update(sql, username, token, new Timestamp(expires));
}
public int updateIfNotExpired(String username, String token, long expiration) {
String sql = "UPDATE refresh_token "
+ "SET expires = ? "
+ "WHERE username = ? "
+ "AND token = ? "
+ "AND expires > ?";
Timestamp now = new Timestamp(System.currentTimeMillis());
Timestamp newExpirationTime = new Timestamp(now.getTime() + expiration);
return jdbcTemplate.update(sql, newExpirationTime, username, token, now);
}