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

目前,每当用户validation失败时,Spring安全性响应:

{"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安全认证响应)
  2. 如果是这样,我是否做错了尝试设置我的身份validation失败处理程序(因为错误的登录似乎没有达到onAuthenticationFailure方法?

谢谢!

您可以通过在configure方法中的HttpSecurity对象上调用.exceptionHandling()来向Spring Security添加exception处理。 如果您只想处理错误的凭据,则可以忽略.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对象。 我们将使用我们在Security Config中创建的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

这会处理授权错误,例如尝试访问没有相应权限的方法。 您可以使用与上面的错误凭据exception相同的方式实现它。

 @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. } } 

希望这有点帮助。