我创建了一个过滤器,用于验证JWT令牌的每个请求标头:
public class JWTAuthenticationFilter extends GenericFilterBean {
private UserDetailsService customUserDetailsService;
private static Logger logger = LoggerFactory.getLogger(JWTAuthenticationFilter.class);
private final static UrlPathHelper urlPathHelper = new UrlPathHelper();
public JWTAuthenticationFilter(UserDetailsService customUserDetailsService) {
this.customUserDetailsService = customUserDetailsService;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
Authentication authentication = AuthenticationService.getAuthentication((HttpServletRequest) request, customUserDetailsService);
SecurityContextHolder.getContext().setAuthentication(authentication);
if (authentication == null) {
logger.debug("failed authentication while attempting to access " + urlPathHelper.getPathWithinApplication((HttpServletRequest) request));
}
filterChain.doFilter(request, response);
}
}
我想抛出一个自定义异常,该异常会返回一个响应:
@ResponseStatus(value=HttpStatus.SOMECODE, reason="There was an issue with the provided authentacion information") // 409
public class CustomAuthenticationException extends RuntimeException {
private static final long serialVersionUID = 6699623945573914987L;
}
我该怎么做?捕获过滤器抛出此类异常的最佳设计是什么? 我可以使用Spring安全性提供的任何异常处理机制并在一点上捕获所有内容吗? 有没有其他方法可以在过滤器中抛出自定义异常?
注意:还有另一个问题here,其接受的答案并未回答我的问题。我想在到达任何控制器之前返回响应。
我想要处理的错误情况: 1.客户端为Authorization标头发送空值。 2.客户端发送格式错误的令牌
在这两种情况下,我都会收到带有500
HTTP状态代码的回复。我希望得到4XX
代码。
答案 0 :(得分:4)
这是我项目的一个例子。
@ControllerAdvice
@RestController
public class GlobalExceptionHandler {
private final Logger log = Logger.getLogger(this.getClass().getSimpleName());
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(value = RuntimeException.class)
public Response handleBaseException(RuntimeException e) {
log.error("Error", e);
Error error = new Error(HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.name());
return Response.status(HttpStatus.BAD_REQUEST.value()).error(error, null).build();
}
@ResponseStatus(HttpStatus.NOT_FOUND)
@ExceptionHandler(value = NoHandlerFoundException.class)
public Response handleNoHandlerFoundException(Exception e) {
log.error("Error", e);
Error error = new Error(HttpStatus.NOT_FOUND.value(), HttpStatus.NOT_FOUND.name());
return Response.status(HttpStatus.NOT_FOUND.value()).error(error, null).build();
}
@ExceptionHandler(value = AuthenticationCredentialsNotFoundException.class)
public Response handleException(AuthenticationCredentialsNotFoundException e) {
log.error("Error", e);
Error error = new Error(ErrorCodes.INVALID_CREDENTIALS_CODE, ErrorCodes.INVALID_CREDENTIALS_MSG);
return Response.status(ErrorCodes.INVALID_CREDENTIALS_CODE).error(error, null).build();
}
@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ExceptionHandler(value = UnauthorisedException.class)
public Response handleNotAuthorizedExceptionException(UnauthorisedException e) {
// log.error("Error", e);
return Response.unauthorized().build();
}
@ExceptionHandler(value = Exception.class)
public String handleException(Exception e) {
log.error("Error", e);
return e.getClass().getName() + " 14" + e.getMessage();
}
}
修改强>
我相信你可以在里面做一些反应.sendError做过滤器方法。
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
Authentication authentication = AuthenticationService.getAuthentication((HttpServletRequest) request, customUserDetailsService);
SecurityContextHolder.getContext().setAuthentication(authentication);
if (authentication == null) {
logger.debug("failed authentication while attempting to access " + urlPathHelper.getPathWithinApplication((HttpServletRequest) request));
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid authentication.");
setUnauthorizedResponse(response);
return;
}
filterChain.doFilter(request, response);
}
public void setUnauthorizedResponse(HttpServletResponse response) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json");
Response unAuthorizedResponse = Response.unauthorized().build();
try {
PrintWriter out = response.getWriter();
out.println(unAuthorizedResponse.toJsonString());
} catch (IOException e) {
log.error("Error", e);
}
}
答案 1 :(得分:0)
我在JWT令牌上遇到了同样的问题并在此question上发布了解决方案,因为那里的问题类似(他在过滤异常方面遇到了麻烦)
答案 2 :(得分:0)
免责声明:这不是所问问题的答案,而是对 Arian 所问问题的后续回答。
如上所述,请查看如何在 spring 容器允许我们访问 bean 之前启动的地方自动装配。
这里我正在自动装配我的 BlacklistJwtRepo
if (blacklistJwtRepo == null) { //Lazy Load because filter
ServletContext servletContext = req.getServletContext();
WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
blacklistJwtRepo = webApplicationContext.getBean(BlacklistJwtRepo.class);
}
这是我获取 req 对象的地方 -
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
最终代码看起来像 -
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
System.out.println("blacklistJwtRepo : " + blacklistJwtRepo);
//till here the autowired repo (blacklistJwtRepo) is null
if (blacklistJwtRepo == null) { //Lazy Load because filter
ServletContext servletContext = req.getServletContext();
WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
blacklistJwtRepo = webApplicationContext.getBean(BlacklistJwtRepo.class);
}