【问题标题】:Is it possible to have custom error response with jwt authentication?是否可以使用 jwt 身份验证进行自定义错误响应?
【发布时间】:2021-09-19 18:10:34
【问题描述】:

我开始基于自定义错误响应构建我的项目,以便仅发送包含我需要的字段的 json 正文。出于这个原因,我有一个

@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler

捕获所有异常并返回具有自定义错误主体的 ResponseEntity。

我有一个用于保存用户的 postgres 数据库。目前我有 /signin、/signup 和 /profile 端点。我想使用 jwt 身份验证。我使用了this github repo,当我在 /signin 端点上发送用户凭据时,我可以获得令牌。

这就是问题所在。阅读 JwtTokenFilter.java 的这一部分

  protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
    String token = jwtTokenProvider.resolveToken(httpServletRequest);
    try {
      if (token != null && jwtTokenProvider.validateToken(token)) {
        Authentication auth = jwtTokenProvider.getAuthentication(token);
        SecurityContextHolder.getContext().setAuthentication(auth);
      }
    } catch (CustomException ex) {
      //this is very important, since it guarantees the user is not authenticated at all
      SecurityContextHolder.clearContext();
      httpServletResponse.sendError(ex.getHttpStatus().value(), ex.getMessage());
      return;
    }

    filterChain.doFilter(httpServletRequest, httpServletResponse);
  }

假设我想注册一个新用户。然后我的请求头将没有令牌(令牌为空),程序将执行filterChain.doFilter(httpServletRequest, httpServletResponse);。这项工作很好,用户注册了,我得到了我的控制器在成功注册后返回的201。 但是,假设我在 /profile 端点再次发出没有令牌的 GET 请求。这也将执行 filterChain.doFilter。然而,这一次 spring 将响应 NON-custom 403 错误响应。 我找不到在我的 RestControllerHandler 上捕获异常的方法,因为 spring 会为我处理它。

另外,当我在doFilterInternal 中抛出异常时,我的 GlobalHandler 将不再处理该异常,spring 会处理它。

【问题讨论】:

    标签: java spring jwt response handler


    【解决方案1】:

    必须添加自定义 AuthenticationFailureHandler

    public class CustomAuthenticationFailureHandler 
      implements AuthenticationFailureHandler {
    
    private ObjectMapper objectMapper = new ObjectMapper();
    
    @Override
    public void onAuthenticationFailure(
      HttpServletRequest request,
      HttpServletResponse response,
      AuthenticationException exception) 
      throws IOException, ServletException {
    
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        Map<String, Object> data = new HashMap<>();
        data.put(
          "timestamp", 
          Calendar.getInstance().getTime());
        data.put(
          "exception", 
          exception.getMessage());
    
        response.getOutputStream()
          .println(objectMapper.writeValueAsString(data));
     }
    }
    

    然后在这里配置

    @Configuration
    @EnableWebSecurity
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) 
      throws Exception {
        auth.inMemoryAuthentication()
          .withUser("user1").password(passwordEncoder.encode("user1Pass")).roles("USER");
    }
    
    @Override
    protected void configure(HttpSecurity http) 
      throws Exception {
        http
          .authorizeRequests()
          .anyRequest()
          .authenticated()
          .and()
          .formLogin()
          .failureHandler(authenticationFailureHandler());
    }
    
    @Bean
    public AuthenticationFailureHandler authenticationFailureHandler() {
        return new CustomAuthenticationFailureHandler();
    }
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
     }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-04-22
      • 1970-01-01
      • 2018-07-16
      • 2018-05-17
      • 2017-02-20
      • 1970-01-01
      • 2016-04-07
      • 2021-11-14
      • 2019-01-06
      相关资源
      最近更新 更多