【问题标题】:Spring Boot Security: Exception handling with custom authentication filtersSpring Boot Security:使用自定义身份验证过滤器处理异常
【发布时间】:2016-03-25 04:50:10
【问题描述】:

我正在使用 Spring Boot + Spring Security(java 配置)。 我的问题是旧问题,但我发现的所有信息都已部分过时,并且大部分包含 xml-config(很难甚至不可能适应一段时间)

我正在尝试使用令牌(不存储在服务器端)进行无状态身份验证。长话短说 - 它是 JSON Web Tokens 身份验证格式的简单模拟。 我在默认过滤器之前使用了两个自定义过滤器:

  • TokenizedUsernamePasswordAuthenticationFilter 在之后创建令牌 入口点成功验证(“/myApp/login”)

  • TokenAuthenticationFilter 尝试对所有受限 URL 使用令牌(如果提供)对用户进行身份验证。

如果我想要一些,我不明白如何正确处理自定义异常(使用自定义消息或重定向)... 过滤器中的异常与控制器中的异常无关,因此它们不会由相同的处理程序处理...

如果我理解正确的话,我不能用

.formLogin()

                .defaultSuccessUrl("...")
                .failureUrl("...")
                .successHandler(myAuthenticationSuccessHandler)
                .failureHandler(myAthenticationFailureHandler)

自定义异常,因为我使用自定义过滤器... 那么该怎么做呢?

我的配置:

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()  .anonymous()

        .and()  .authorizeRequests()                      
                .antMatchers("/").permitAll()
                ...
                .antMatchers(HttpMethod.POST, "/login").permitAll()                    
        .and()                    
                .addFilterBefore(new TokenizedUsernamePasswordAuthenticationFilter("/login",...), UsernamePasswordAuthenticationFilter.class)                      
                .addFilterBefore(new TokenAuthenticationFilter(...), UsernamePasswordAuthenticationFilter.class)

    }

【问题讨论】:

    标签: java spring-mvc spring-security spring-boot


    【解决方案1】:

    我们也可以在您的自定义过滤器中设置 AuthenticationSuccessHandler 和 AuthenticationFailureHandler。

    在你的情况下,

    // Constructor of TokenizedUsernamePasswordAuthenticationFilter class
    public TokenizedUsernamePasswordAuthenticationFilter(String path, AuthenticationSuccessHandler successHandler, AuthenticationFailureHandler failureHandler) {
        setAuthenticationSuccessHandler(successHandler);
        setAuthenticationFailureHandler(failureHandler);
    }
    

    现在要使用这些处理程序,只需调用 onAuthenticationSuccess()onAuthenticationFailure() 方法。

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                              FilterChain chain, Authentication authentication) throws IOException, ServletException {
    
        getSuccessHandler().onAuthenticationSuccess(request, response, authentication);
    }
    
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request,
                                                HttpServletResponse response,
                                                AuthenticationException failed)
              throws IOException, ServletException {
    
        getFailureHandler().onAuthenticationFailure(request, response, failed);
    }
    

    您可以创建自定义身份验证处理程序类来处理成功或失败的情况。例如,

    public class LoginSuccessHandler implements AuthenticationSuccessHandler {
    
      @Override
      public void onAuthenticationSuccess(HttpServletRequest httpServletRequest,
                                          HttpServletResponse httpServletResponse,
                                          Authentication authentication)
              throws IOException, ServletException {
    
        SecurityContextHolder.getContext().setAuthentication(authentication);
        // Do your stuff, eg. Set token in response header, etc.
      }
    }
    

    现在处理异常,

    public class LoginFailureHandler implements AuthenticationFailureHandler {
    
      @Override
      public void onAuthenticationFailure(HttpServletRequest httpServletRequest,
                                          HttpServletResponse httpServletResponse,
                                          AuthenticationException e)
              throws IOException, ServletException {
    
        String errorMessage = ExceptionUtils.getMessage(e);
    
        sendError(httpServletResponse, HttpServletResponse.SC_UNAUTHORIZED, errorMessage, e);
      }
    
    
      private void sendError(HttpServletResponse response, int code, String message, Exception e) throws IOException {
        SecurityContextHolder.clearContext();
    
        Response<String> exceptionResponse =
                new Response<>(Response.STATUES_FAILURE, message, ExceptionUtils.getStackTrace(e));
    
        exceptionResponse.send(response, code);
      }
    }
    

    用于生成所需 JSON 响应的自定义响应类,

    public class Response<T> {
    
      public static final String STATUES_SUCCESS = "success";
      public static final String STATUES_FAILURE = "failure";
    
      private String status;
      private String message;
      private T data;
    
      private static final Logger logger = Logger.getLogger(Response.class);
    
      public Response(String status, String message, T data) {
        this.status = status;
        this.message = message;
        this.data = data;
      }
    
      public String getStatus() {
        return status;
      }
    
      public String getMessage() {
        return message;
      }
    
      public T getData() {
        return data;
      }
    
      public String toJson() throws JsonProcessingException {
        ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
        try {
          return ow.writeValueAsString(this);
        } catch (JsonProcessingException e) {
          logger.error(e.getLocalizedMessage());
          throw e;
        }
      }
    
      public void send(HttpServletResponse response, int code) throws IOException {
        response.setStatus(code);
        response.setContentType("application/json");
        String errorMessage;
    
        errorMessage = toJson();
    
        response.getWriter().println(errorMessage);
        response.getWriter().flush();
      }
    }
    

    我希望这会有所帮助。

    【讨论】:

    • 这将在失败时发送一条一般错误消息。如何根据不同的情况发送不同的错误信息
    猜你喜欢
    • 2021-04-21
    • 2020-12-05
    • 2015-02-14
    • 2018-12-11
    • 2019-04-27
    • 2013-09-18
    • 2014-04-26
    • 2019-06-05
    • 2013-06-12
    相关资源
    最近更新 更多