我使用Spring Boot 1.5.9开发我的应用程序。我需要实现jwt身份验证,我使用了jjwt库。以下代码来自我的自定义身份验证安全筛选器,它继承自OncePerRequestFilter
。这里我尝试从令牌解析用户名,当用户名自动解析时,jwt验证并检查令牌的到期时间。我调试它,它的工作原理,所以我接下来想要向客户端应用程序发送正确的消息,为什我想抛出ExpiredJwtException并使用控制器建议处理它,我将格式化输出。
这是异常抛出:
try {
username = jwtTokenService.getUsername(authToken);
} catch (IllegalArgumentException e) {
logger.error("an error occured during getting username from token", e);
} catch (ExpiredJwtException e) {
logger.warn("the token is expired and not valid anymore", e);
throw new ExpiredJwtException(e.getHeader(), e.getClaims(), e.getMessage());
}
这是我的控制器建议,JwtException是我抛出的ExpiredJwtException的基类,所以它应该有效。我也试过在ExceptionHandler中直接使用ExpiredJwtException,但是效果不好。接下来我想以同样的方式处理另一个异常。
@ControllerAdvice
public class GlobalControllerExceptionHandler {
@ExceptionHandler(Exception.class)
public @ResponseBody
ResponseEntity<Map<String, Object>> handleException(Exception ex) {
Map<String, Object> errorInfo = new HashMap<>();
errorInfo.put("message", ex.getMessage());
errorInfo.put("status", HttpStatus.BAD_REQUEST);
errorInfo.put("status_code", HttpStatus.BAD_REQUEST.value());
return new ResponseEntity<>(errorInfo, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(JwtException.class)
//@ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
public @ResponseBody
ResponseEntity handleJwtException(JwtException ex) {
Map<String, Object> errorInfo = new HashMap<>();
errorInfo.put("message", ex.getLocalizedMessage());
errorInfo.put("status", HttpStatus.UNPROCESSABLE_ENTITY);
errorInfo.put("status_code", HttpStatus.UNPROCESSABLE_ENTITY.value());
return new ResponseEntity<>(errorInfo, HttpStatus.UNPROCESSABLE_ENTITY);
}
}
我想返回只有4xx状态的响应,但是当我的异常被抛出时,我总是得到5xx内部错误。你能告诉我我的代码有什么问题吗?谢谢你的建议。
答案 0 :(得分:1)
让您的控制器扩展ResponseEntityExceptionHandler
并让您的异常处理方法将WebRequest
作为参数
然后将您的返回值更改为此
return handleExceptionInternal(ex, errorInfo, new HttpHeaders(), HttpStatus.BAD_REQUEST, request);
HttpStatus.BAD_REQUEST
可以更改为任何40x错误
Exception.class
@ExceptionHandler(value = { Exception.class })
protected ResponseEntity<Object> handleUncaughtException(Exception ex, WebRequest request) {
String message = "Something bad happened";
return handleExceptionInternal(ex, message, new HttpHeaders(), HttpStatus.BAD_REQUEST, request);
}
根据此Make simple servlet filter work with @ControllerAdvice,您可以创建自定义处理程序。
然后将新处理程序添加到WebSecurityConfigurerAdapter
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new CustomHandler());
}
答案 1 :(得分:1)
如果在过滤器中抛出异常,则不涉及Springs异常处理(@ControllerAdvice
,@ExceptionHandler
)。
您需要捕获过滤器内的所有异常,并直接使用ServletResponse
。
据我所知 - 过滤器是低级逻辑(Spring基础架构之前的请求处理),但您可以有一个解决方法,例如包装链接并捕获所有RuntimeExceptions
的特定过滤器。 (看起来像是一个紧缩,但没有其他解决方案)。
如果您想要一个特定的登录来创建您的异常对象 - 覆盖ErrorAttributes
bean。它允许您为所有应用程序异常提供单一视图。
要直接指定http响应状态,请使用
httpServletResponse.setStatus(... your status code ...)
;
答案 2 :(得分:0)
我还遇到了RestControllerAdivce不处理异常的问题,问题是,advice方法只能在签名中包含异常抛出方法具有或可以提供的参数。我的AOP方法无法访问Headers,因此无法将Headers提供给RestControllerAdivce方法。在没有标题作为参数的RestController中创建新的异常处理程序方法后,RestControllerAdivce就开始按预期工作。 Detials here