使用 AuthenticationFailureHandler 在 Spring Security 中自定义身份验证失败响应
目前,每当用户身份验证失败时,spring security 都会响应:
Currently, whenever a user fails authentication, spring security responds with:
{"error": "invalid_grant","error_description": "Bad credentials"}
我想用一个响应代码来增强这个响应:
And I would like to enhance this response with a response code like:
{"responsecode": "XYZ","error": "invalid_grant","error_description": "Bad credentials"}
经过一番摸索,看起来我需要做的是实现一个AuthenticationFailureHandler,我已经开始这样做了.但是,每当我提交无效的登录凭据时,似乎永远不会到达 onAuthenticationFailure 方法.我已经逐步完成了代码,并在 onAuthenticationFailure 方法中进行了登录以确认它没有被访问.
After some poking around, it looks like what I need to do this is implement an AuthenticationFailureHandler, which I have begun to do. However, the onAuthenticationFailure method never seems to be reached whenever I submit invalid login credentials. I have stepped through the code, and placed logging in the onAuthenticationFailure method to confirm it is not being reached.
我的失败处理程序是:
@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 包含:
And my WebSecurityConfigurerAdapter contains:
@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 方法?
谢谢!
您可以通过在配置方法中对 HttpSecurity 对象调用 .exceptionHandling() 来为 Spring Security 添加异常处理.如果您只想处理坏凭据,您可以忽略 .accessDeniedHandler(accessDeniedHandler()).
You can add exception handling to you Spring Security by calling .exceptionHandling() on your HttpSecurity object in your configure method. If you only want to handle just bad credentials you can ignore the .accessDeniedHandler(accessDeniedHandler()).
访问被拒绝处理程序处理您在方法级别保护应用程序的情况,例如使用@PreAuthorized、@PostAuthorized 和@安全.
The access denied handler handles situations where you hav secured you app at method level such as using the @PreAuthorized, @PostAuthorized, & @Secured.
您的安全配置示例可能是这样的
An example of your security config could be like this
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
CustomAuthenticationEntryPoint.java
您可以在它自己的单独文件中创建它.这是入口点处理无效凭据.在该方法中,我们必须创建自己的 JSON 并将其写入 HttpServletResponse 对象.好使用我们在安全配置中创建的 Jackson 对象映射器 bean.
You can create this in its own separate file. This is Entry point handles the invalid credentials. Inside the method we'll have to create and write our own JSON to the HttpServletResponse object. We'll use the Jackson object mapper bean we created in the Security Config.
@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
CustomAccessDeniedHandler.java
这会处理授权错误,例如尝试访问没有适当的特权.您可以按照我们在上面对错误凭据异常所做的相同方式实现它.
This handles authorization errors such as trying to access method without the appropriate priviledges. You can implement it in the same way we did above with the bad credentials 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.
}
}
希望这有点帮助.