簡體   English   中英

使用 AuthenticationFailureHandler 在 Spring Security 中自定義身份驗證失敗響應

[英]Customize authentication failure response in Spring Security using AuthenticationFailureHandler

目前,每當用戶身份驗證失敗時,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;
    }
}

我的問題是:

  1. 這是達到我想要的結果的正確方法嗎? (自定義spring security認證響應)
  2. 如果是這樣,我是否在嘗試設置身份驗證失敗處理程序時做錯了什么(因為錯誤的登錄似乎沒有到達 onAuthenticationFailure 方法?

謝謝!

您可以通過在配置方法中對 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.
    }

}

希望這有點幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM