这一行:
Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
当我的 jwt token 过期时抛出这样的错误:JWT expired at 2020-05-13T07:50:39Z. Current time: 2020-05-16T21:29:41Z.
更具体地说,正是这个函数抛出了“ExpiredJwtException”异常:
我该如何处理这些异常?我是否应该捕获它们并将错误消息发送回客户端并强制它们重新登录?
如何实现刷新 token 功能?我在后端使用 Spring 和 mysql,在前端使用 vuejs。
我生成这样的初始 token :
@Override
public JSONObject login(AuthenticationRequest authreq) {
JSONObject json = new JSONObject();
try {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(authreq.getUsername(), authreq.getPassword()));
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
List<String> roles = userDetails.getAuthorities().stream().map(item -> item.getAuthority())
.collect(Collectors.toList());
if (userDetails != null) {
final String jwt = jwtTokenUtil.generateToken(userDetails);
JwtResponse jwtres = new JwtResponse(jwt, userDetails.getId(), userDetails.getUsername(),
userDetails.getEmail(), roles, jwtTokenUtil.extractExpiration(jwt).toString());
return json.put("jwtresponse", jwtres);
}
} catch (BadCredentialsException ex) {
json.put("status", "badcredentials");
} catch (LockedException ex) {
json.put("status", "LockedException");
} catch (DisabledException ex) {
json.put("status", "DisabledException");
}
return json;
}
然后在 JwtUtil 类中: public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return createToken(claims, userDetails.getUsername());
}
private String createToken(Map<String, Object> claims, String subject) {
return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + EXPIRESIN))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY).compact();
}
有关更多信息,这是我的 doFilterInternal 函数,用于过滤每个请求: @Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException, ExpiredJwtException, MalformedJwtException {
try {
final String authorizationHeader = request.getHeader("Authorization");
String username = null;
String jwt = null;
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
jwt = authorizationHeader.substring(7);
username = jwtUtil.extractUsername(jwt);
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userService.loadUserByUsername(username);
boolean correct = jwtUtil.validateToken(jwt, userDetails);
if (correct) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
chain.doFilter(request, response);
} catch (ExpiredJwtException ex) {
resolver.resolveException(request, response, null, ex);
}
}
最佳答案
有两种主要的方法来处理这种情况:
管理访问和刷新 token
在这种情况下,流程如下:
username
和 password
)2.1 访问 JWT token 过期时间通常“低”(15、30 分钟等)。
2.2 刷新 JWT token 过期时间大于访问时间。
access token
在 Authorization
每个请求的 header 。当后端返回时
401
,前端应用会尝试使用refresh token
(使用特定端点)获取新凭据,而不强制用户再次登录。Refresh token flow
(这只是一个例子,通常只发送刷新 token )
如果没有问题,那么用户将能够继续使用该应用程序。如果后端返回一个新的
401
=> 前端应该重定向到登录页面。仅管理一个 Jwt token
在这种情况下,流程与上一个类似,您可以创建自己的端点来处理这种情况:
/auth/token/extend
(例如),包括过期的 Jwt 作为请求的参数。现在由您来管理:
新端点将具有与上一节中的 refresh one 类似的行为,我的意思是,将返回一个新的 Jwt token 或
401
所以,从前端的角度来看,流程是一样的。一 重要的事情 ,独立于您要遵循的方法,“新端点”应从所需的 Spring 身份验证端点中排除,因为您将自己管理安全性:
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
..
@Override
protected void configure(HttpSecurity http) throws Exception {
http.
..
.authorizeRequests()
// List of services do not require authentication
.antMatchers(Rest Operator, "MyEndpointToRefreshOrExtendToken").permitAll()
// Any other request must be authenticated
.anyRequest().authenticated()
..
}
}
关于spring - 如何在 Spring 安全性中刷新 token ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63426347/