下面是SpringSecurity Jwt Token 自动刷新的实现的完整攻略。
1. 什么是Jwt Token?
Jwt Token(也称为 Json Web Token)是一种基于 JSON 格式的身份验证标准。通常用于 RESTful API,作为一种简单、轻量级的身份验证机制,用于跨域身份验证,以及在分布式系统中传递身份信息。它包含了三部分: Header、Payload 和 Signature。其中,Header 和 Payload 部分都是 Base64Url 编码的 JSON 字符串,Signature 是将 Header、Payload 和一个加密密钥进行签名得到的字符串。
2. Jwt Token 有哪些优势?
-
跨域身份验证:因为 Jwt Token 包含了身份验证信息,可以轻松在不同的域之间传递身份验证信息。
-
无状态:因为 Jwt Token 包含了所有必要的信息,可以不需要在服务器端保存任何信息,从而使服务器更加容易扩展。
-
自包含:Jwt Token 包含了所有必要的信息,因此客户端可以验证 Jwt Token 的有效性,而无需向服务器发出任何请求。
3. SpringSecurity Jwt Token 自动刷新的实现
3.1 环境准备
首先,需要在项目中添加以下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
同时,在 Spring Security 的配置类中,需要添加如下配置:
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable().authorizeRequests().antMatchers("/authenticate").permitAll()
.anyRequest().authenticated().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
其中,jwtRequestFilter
是我们自己实现的 Jwt Token 过滤器,用于验证 Jwt Token。
3.2 实现 Jwt Token 过滤器
为了实现 Jwt Token 过滤器,我们需要实现 OncePerRequestFilter
接口,并 Override doFilterInternal
方法。在该方法中,我们解析 Jwt Token,并验证其有效性。
以下是示例代码:
@Component
public class JwtRequestFilter extends OncePerRequestFilter {
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
final String requestTokenHeader = request.getHeader("Authorization");
String username = null;
String jwtToken = null;
// JWT Token is in the form "Bearer token". Remove Bearer word and get
// only the Token
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
jwtToken = requestTokenHeader.substring(7);
try {
username = jwtTokenUtil.getUsernameFromToken(jwtToken);
} catch (IllegalArgumentException e) {
logger.warn("Unable to get JWT Token");
} catch (ExpiredJwtException e) {
logger.warn("JWT Token has expired");
}
} else {
logger.warn("JWT Token does not begin with Bearer String");
}
// Once we get the token validate it.
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
// if token is valid configure Spring Security to manually set
// authentication
if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
chain.doFilter(request, response);
}
}
3.3 实现 Jwt Token 的自动刷新
为了实现 Jwt Token 的自动刷新,我们需要在 Jwt Token 过滤器中对过期的 Jwt Token 进行处理。具体而言,我们可以在每次验证 Jwt Token 的时候,检查 Jwt Token 是否快要过期,如果快要过期,就重新生成一个 Jwt Token,并将它添加到响应的头信息中。客户端收到这个响应之后,就会使用新的 Jwt Token 代替旧的 Jwt Token,从而实现自动刷新。
以下是示例代码:
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
final String requestTokenHeader = request.getHeader("Authorization");
String username = null;
String jwtToken = null;
// JWT Token is in the form "Bearer token". Remove Bearer word and get
// only the Token
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
jwtToken = requestTokenHeader.substring(7);
try {
username = jwtTokenUtil.getUsernameFromToken(jwtToken);
} catch (IllegalArgumentException e) {
logger.error("Unable to get JWT Token");
} catch (ExpiredJwtException e) {
logger.warn("JWT Token has expired");
}
} else {
logger.warn("JWT Token does not begin with Bearer String");
}
// Once we get the token validate it.
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
// if token is valid configure Spring Security to manually set
// authentication
if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
// 如果发现 Jwt Token 即将过期
if(jwtTokenUtil.isTokenAboutToExpire(jwtToken)) {
// 重新生成一个 Jwt Token
String refreshedToken = jwtTokenUtil.refreshToken(jwtToken);
// 设置响应的头信息
response.setHeader("Authorization", "Bearer " + refreshedToken);
}
}
}
chain.doFilter(request, response);
}
4. 总结
通过实现 Jwt Token 的自动刷新,我们可以保持用户的登录状态,同时避免 Jwt Token 过期而导致的用户需再次登录的情况。如有需要,我们可以自己实现一个简单的 Jwt Token 工具类。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringSecurity Jwt Token 自动刷新的实现 - Python技术站