概述
上一篇文章讲了,登陆完后会给我们返回信息,这没毛病,但是问题来了,他跳转了页面,假设我们不想跳转页面,只想返回固定格式的JSON呢?这就需要我们自定义成功处理器了。失败的情况也雷同。
一、创建登录成功处理器LoginSuccessHandler,并重写onAuthenticationSuccess方法
@Slf4j
@Component
public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
log.info("登录成功!");
/* 默认:会帮我们跳转到上一次请求的页面上 */
//super.onAuthenticationSuccess(request, response, authentication);
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
PrintWriter writer = response.getWriter();
writer.write("登录成功");
writer.flush();
writer.close();
}
}
Spring Security完成用户登录后跳转回原页面的处理是在SavedRequestAwareAuthenticationSuccessHandler类里面进行的,如果想要自定义登录成功后的操作可以继承该类,重写该方法。为什么不实现AuthenticationSuccessHandler接口,而是继承SavedRequestAwareAuthenticationSuccessHandler类的方式?因为SavedRequestAwareAuthenticationSuccessHandler这个类记住了你上一次的请求路径,比如:你请求user.html。然后被拦截到了登录页,这时候你输入完用户名密码点击登录,会自动跳转到user.html,而不是主页面。
若是前后分离项目则实现接口即可,因为我弄的是通用的权限组件,所以选择了继承。
一种成功的身份验证策略,通过ExceptionTranslationFilter,默认将DefaultSavedRequest存储在session中当这样的请求被截获并需要身份验证时,在身份验证过程开始之前存储请求数据以记录原始目的地(url)并允许在重定向到相同的URL时重键请求,如果合适的话,这个类负责执行到原始URL的重定向。
在成功进行验证之后,它根据以下场景确定重定向目标:
- 如果alwaysUseDefaultTargetUrl属性设置为true,则defaultTargetUrl将用于目标.会话中存储的任何defaultSavedRequest将被删除。
- 如果在请求中设置了targetUrlParameter,则该值将用作目标。defaultTargetUrl将再次被删除
- 如果在RequestCache中找到SavedRequest(由ExceptionTranslationFilter所设置,在验证过程开始之前记录原始目的地),将对原始目的地的Url执行重定向。当收到重定向请求时,SavedRequest对象将保持缓存状态并被拾取(请参阅SavedRequestAwareWrapper)
- 如果找不到SavedRequest它将委托给基类(父类)。
二、创建登录失败处理器,并重写onAuthenticationFailure方法
@Slf4j
@Component
public class LoginFailureHandler extends SimpleUrlAuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
/* 默认:执行重定向或转发到defaultfailureurl(如果设置),Otherw返回401错误代码 */
//super.onAuthenticationFailure(request,response,exception)
log.error("登录错误 [{}] ",exception.getMessage());
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
PrintWriter writer = response.getWriter();
writer.write(exception.getMessage());
writer.flush();
writer.close();
}
}
AuthenticationFailureHandler接口定义了Spring Security Web在遇到认证错误时所使用的处理策略。
典型做法一般是将用户重定向到认证页面(比如认证机制是用户名表单认证的情况)让用户再次认证。当然具体实现类可以根据需求实现更复杂的逻辑,比如根据异常做不同的处理等等。举个例子,如果遇到CredentialsExpiredException异常(AuthenticationException异常的一种,表示密码过期失效),可以将用户重定向到修改密码页面而不是登录认证页面。
在Spring Security Web框架内部,缺省使用的认证错误处理策略是AuthenticationFailureHandler的实现类SimpleUrlAuthenticationFailureHandler。它由配置指定一个defaultFailureUrl,表示认证失败时缺省使用的重定向地址。一旦认证失败,它的方法onAuthenticationFailure被调用时,它就会将用户重定向到该地址。如果该属性没有设置,它会向客户端返回一个401状态码。另外SimpleUrlAuthenticationFailureHandler还有一个属性useForward,如果该属性设置为true,页面跳转将不再是重定向(redirect)机制,取而代之的是转发(forward)机制。
三、把自定义处理器加入security认证中
在SecurityConfig配置类的configure(HttpSecurity http)方法中加入我们自定义的处理Handler
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() //需要授权的请求
.antMatchers("/login","/home").permitAll() //过滤不需要认证的路径
.anyRequest().authenticated() //对任何一个请求,都需要认证
.and() //完成上一个配置,进行下一步配置
//.httpBasic();
.formLogin() //配置表单登录
.loginPage("/login") //设置登录页面
.successHandler(successHandler) /* 设置成功处理器 */
.failureHandler(failureHandler) /* 设置失败处理器*/
.and()
.logout() //登出
.logoutSuccessUrl("/home"); //设置退出页面
}