使用 AuthenticationFailureHandler 在 Spring Security 中自定义身份验证失败响应

Posted

技术标签:

【中文标题】使用 AuthenticationFailureHandler 在 Spring Security 中自定义身份验证失败响应【英文标题】:Customize authentication failure response in Spring Security using AuthenticationFailureHandler 【发布时间】:2017-08-07 23:19:09 【问题描述】:

目前,每当用户身份验证失败时,spring security 都会响应:

"error": "invalid_grant","error_description": "Bad credentials"

我想使用如下响应代码来增强此响应:

"responsecode": "XYZ","error": "invalid_grant","error_description": "Bad credentials"

经过一番摸索,看起来我需要做的是实现一个AuthenticationFailureHandler,我已经开始这样做了。但是,每当我提交无效的登录凭据时,似乎永远无法达到 onAuthenticationFailure 方法。我已经单步执行了代码,并在 onAuthenticationFailure 方法中进行了登录,以确认它没有被访问。

我的失败处理程序是:

@Component
public class SSOAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
        AuthenticationException exception) throws IOException, ServletException 
        super.onAuthenticationFailure(request, response, exception);
        response.addHeader("responsecode", "XYZ");  
    

我的 WebSecurityConfigurerAdapter 包含:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter 

    @Autowired SSOAuthenticationFailureHandler authenticationFailureHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http.csrf().disable();
        http.formLogin().failureHandler(authenticationFailureHandler);
    

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception 
        auth.userDetailsService(service).passwordEncoder(passwordEncoder());
        auth.authenticationEventPublisher(defaultAuthenticationEventPublisher());
    

    @Bean
    public DefaultAuthenticationEventPublisher defaultAuthenticationEventPublisher()
        return new DefaultAuthenticationEventPublisher();
    

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception 
        return super.authenticationManagerBean();
    

    @Bean
    public SSOAuthenticationFailureHandler authenticationHandlerBean() 
        return new SSOAuthenticationFailureHandler();
    

    @Bean
    public PasswordEncoder passwordEncoder()
        PasswordEncoder encoder = new BCryptPasswordEncoder();
        return encoder;
    

我的问题是:

    这是实现我想要的结果的正确方法吗? (自定义spring安全认证响应) 如果是这样,我在尝试设置身份验证失败处理程序时是否做错了什么(因为错误的登录似乎没有到达 onAuthenticationFailure 方法?

谢谢!

【问题讨论】:

你可以在你的配置方法中添加异常处理 http.csrf().disable().exceptionHandling().authentcationEntryPoint(unauthorizedHanlderHere);您必须创建一个实现 AuthencationEntryPoint 的类。 【参考方案1】:

您可以通过在您的配置方法中对您的 HttpSecurity 对象调用 .exceptionHandling() 来为 Spring Security 添加异常处理。 如果您只想处理错误的凭据,您可以忽略 .accessDeniedHandler(accessDeniedHandler())。

拒绝访问处理程序处理您在方法级别保护应用程序的情况,例如使用@PreAuthorized、@PostAuthorized 和@Secured。

您的安全配置示例可能是这样的

SecurityConfig.java
/* 
   The following two are the classes we're going to create later on.  
   You can autowire them into your Security Configuration class.
*/
@Autowired
private CustomAuthenticationEntryPoint unauthorizedHandler;

@Autowired
private CustomAccessDeniedHandler accessDeniedHandler;    

/*
  Adds exception handling to you HttpSecurity config object.
*/
@Override
protected void configure(HttpSecurity http) throws Exception 
    http.csrf()
        .disable()
        .exceptionHandling()
            .authencationEntryPoint(unauthorizedHandler)  // handles bad credentials
            .accessDeniedHandler(accessDeniedHandler);    // You're using the autowired members above.


    http.formLogin().failureHandler(authenticationFailureHandler);


/*
  This will be used to create the json we'll send back to the client from
  the CustomAuthenticationEntryPoint class.
*/
@Bean
public Jackson2JsonObjectMapper jackson2JsonObjectMapper() 
ObjectMapper mapper = new ObjectMapper();
    mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
    return new Jackson2JsonObjectMapper(mapper);
   

CustomAuthenticationEntryPoint.java

您可以在其自己的单独文件中创建它。这是入口点处理无效凭据。 在方法内部,我们必须创建自己的 JSON 并将其写入 HttpServletResponse 对象。好吧 使用我们在安全配置中创建的 Jackson 对象映射器 bean。

 @Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable 

    private static final long serialVersionUID = -8970718410437077606L;

    @Autowired  // the Jackson object mapper bean we created in the config
    private Jackson2JsonObjectMapper jackson2JsonObjectMapper;

    @Override
    public void commence(HttpServletRequest request,
                         HttpServletResponse response,
                         AuthenticationException e) throws IOException 

        /* 
          This is a pojo you can create to hold the repsonse code, error, and description.  
          You can create a POJO to hold whatever information you want to send back.
        */ 
        CustomError error = new CustomError(HttpStatus.FORBIDDEN, error, description);

        /*
          Here we're going to creat a json strong from the CustomError object we just created.
          We set the media type, encoding, and then get the write from the response object and write
      our json string to the response.
        */
        try 
            String json = jackson2JsonObjectMapper.toJson(error);
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setCharacterEncoding(StandardCharsets.UTF_8.toString());
            response.getWriter().write(json);
         catch (Exception e1) 
            e1.printStackTrace();
        

    


CustomAccessDeniedHandler.java

这会处理授权错误,例如尝试在没有 适当的特权。您可以按照我们上面对错误凭据异常执行的相同方式来实现它。

@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler 

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response,
        AccessDeniedException e) throws IOException, ServletException 

    // You can create your own repsonse here to handle method level access denied reponses..
    // Follow similar method to the bad credentials handler above.
    


希望这有点帮助。

【讨论】:

以上是关于使用 AuthenticationFailureHandler 在 Spring Security 中自定义身份验证失败响应的主要内容,如果未能解决你的问题,请参考以下文章

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)