【发布时间】:2021-03-12 04:15:45
【问题描述】:
我在 Project 中使用带有 JWT 和 Spring Security 的 Spring Boot。 春季启动:2.3.5.RELEASE JJWT 版本:0.11.2
我已经创建了用于中断请求的 JWT 身份验证过滤器类。如果请求在标头中包含 JWT 令牌,则解析令牌、获取角色并在 spring 安全上下文中设置身份验证对象。我的身份验证过滤器类如下
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;
import io.jsonwebtoken.Claims;
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String header = request.getHeader(JwtConstant.AUTHORIZATION);
if (StringUtils.isNotBlank(header) && header.startsWith(JwtConstant.BEARER)) {
String authToken = header.replace(JwtConstant.BEARER, "");
Claims claims = jwtTokenUtil.getJwtClaims(authToken);
String username = claims.getSubject();
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails,
"", getAuthoritiesFromString(claims));
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
logger.info("authenticated user " + username + ", setting security context");
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(request, response);
}
private Collection<? extends GrantedAuthority> getAuthoritiesFromString(Claims claims) {
return Arrays.stream(claims.get(JwtConstant.AUTHORITIES).toString().split(",")).map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
}
}
令牌解析方法如下:
public Claims getJwtClaims(String token) {
Claims claims = null;
try {
claims = Jwts.parserBuilder().setSigningKey(getPublicKey()).build().parseClaimsJws(token).getBody();
} catch (ExpiredJwtException e) {
throw new CustomException(env.getProperty(ExceptionMessage.TOKEN_EXPIRED),e, ErrorCode.TOKEN_EXPIRE);
} catch (SignatureException | MalformedJwtException e) {
throw new CustomException(env.getProperty(ExceptionMessage.TOKEN_INVALID),e, ErrorCode.TOKEN_INVALID);
} catch (Exception e) {
throw new CustomException(env.getProperty(ExceptionMessage.TOKEN_PARSING),e, ErrorCode.INTERNAL_SERVER_ERROR);
}
return claims;
}
如果 oken 无效或过期,则在解析令牌时,我将抛出具有 Integer errorCode 的自定义异常。
当请求包含过期或无效令牌时,首先它会进入 jwt 身份验证过滤器类。在解析令牌时,我得到以下响应:
{
"timestamp": "2020-11-30T08:28:40.319+00:00",
"status": 500,
"error": "Internal Server Error",
"message": "Token Expired",
"path": "/api/users/profile"
}
因为这个异常是从 servlet 过滤器抛出的,它不会去 @RestControllerAdvise 和它抛出的内置异常响应。在这种情况下,我想用错误代码抛出我的自定义异常类。我尝试了不同的解决方案,但无法解决我的问题。有没有办法从这种情况下抛出自定义错误代码。
我想要下面的异常响应,这是我的自定义响应类:
{
"message": "Token Expired",
"code": 101,
"error": true,
"timestamp": "2020-11-30T08:31:46.911+00:00"
}
【问题讨论】:
标签: java spring-boot jwt