繁体   English   中英

如何从 JWT 身份验证过滤器中抛出自定义异常

[英]How to throw Custom Exception from JWT Authentication Filter

我在项目中使用 Spring 引导和 JWT 和 spring 安全性。 Spring 引导:2.3.5.RELEASE JJWT 版本:0.11.2

I have created the JWT Authentication Filter class for interrupting requests.If the request contains JWT token in headers then parse the token, get roles, and set authentication object in the spring security context. 我的认证过滤器 class 如下

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());
    }

}

Token解析方法如下:

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 错误代码的自定义异常。

当请求包含过期或无效令牌时,首先它转到 jwt 身份验证过滤器 class。 在解析令牌时,我得到以下响应:

{
    "timestamp": "2020-11-30T08:28:40.319+00:00",
    "status": 500,
    "error": "Internal Server Error",
    "message": "Token Expired",
    "path": "/api/users/profile"
}

由于此异常是从 servlet 过滤器引发的,它不会去 @RestControllerAdvise 及其引发的内置异常响应。 在这种情况下,我想抛出带有错误代码的自定义异常 class。 我尝试了不同的解决方案,但无法解决我的问题。 有没有办法从这种情况下抛出自定义错误代码。

我想要下面的异常响应,这是我的自定义响应 class:

{
    "message": "Token Expired",
    "code": 101,
    "error": true,
    "timestamp": "2020-11-30T08:31:46.911+00:00"
}

“/error”创建一个customerErrorController,例如:

@RestController
public class CustomErrorController implements ErrorController {
    
    private static final String PATH = "/error";
    
    @RequestMapping(PATH)
    public ResponseEntity<ErrorDetails> handleError(final HttpServletRequest request,
            final HttpServletResponse response) throws Throwable {
        throw (Throwable) request.getAttribute("javax.servlet.error.exception");
    }
    
    @Override
    public String getErrorPath() {
        return PATH;
    }
}

然后@RestControllerAdvise 将能够选择异常。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM