自定义登录成功处理
有时候页面跳转并不能满足我们,特别是在前后端分离开发中就不需要成功之后跳转页面。只需要给前端返回一个 JSON 通知登录成功还是失败与否。这个时候可以通过自定义 AuthenticationSucccessHandler
实现
public interface AuthenticationSuccessHandler {
/**
* Called when a user has been successfully authenticated.
* @param request the request which caused the successful authentication
* @param response the response
* @param authentication the <tt>Authentication</tt> object which was created during
* the authentication process.
*/
void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException;
}
根据接口的描述信息,也可以得知登录成功会自动回调这个方法,进一步查看它的默认实现,你会发现successForwardUrl、defaultSuccessUrl也是由它的子类实现的
- 自定义 AuthenticationSuccessHandler 实现
/**
* 自定义认证成功之后的处理
*/
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler{
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
Map<String,Object> result=new HashMap<>();
result.put("msg", "登录成功");
result.put("status", 200);
response.setContentType("application/json;charset=UTF-8");
String s = new ObjectMapper().writeValueAsString(result);
response.getWriter().println(s);
}
}
- 配置 AuthenticationSuccessHandler
@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeHttpRequests()
.mvcMatchers("/login.html").permitAll()
.mvcMatchers("/index").permitAll()//放行资源写在任何前面
.anyRequest().authenticated()
.and().formLogin()
.loginPage("/login.html")//用来指定默认登录页面 注意:一旦自定义登录页面后必须只能登录url
.loginProcessingUrl("/doLogin")//指定处理登录请求url
.usernameParameter("uname")
.passwordParameter("passwd")
//.successForwardUrl("/index")//认证成功 forward 跳转路径 始终在认证成功之后跳转到指定请求
//.defaultSuccessUrl("/hello")//认证成功 redirect 如果之前请求路径,会有优先跳转之前请求路径
!!!!
.successHandler(new MyAuthenticationSuccessHandler())//认证成功时处理 前后端分离时的处理方案
.and()
.csrf().disable();
}
}
运行并测试,可以发现前端返回json数据
显示登录失败信息
为了能更直观在登录页面看到异常错误信息,可以在登录页面中直接获取异常信息。Spring Security 在登录失败之后会将异常信息存储到 request
、session
作用域中 key 为SPRING_SECURITY_LAST_EXCEPTION
命名属性中
- 显示异常信息
<div th:text="${session.SPRING_SECURITY_LAST_EXCEPTION}"></div>
- 配置
@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeHttpRequests()
//...............
.failureForwardUrl("/login.html")//认证失败之后 forward跳转
.failureUrl("/login.html")//认证失败之后 redirect跳转
//................
}
}
-
failureUrl、failureForwardUrl 关系类似于之前提到的 successForwardUrl
、defaultSuccessUrl 方法- failureUrl 失败以后的重定向跳转
- failureForwardUrl 失败以后的 forward 跳转
注意:因此获取 request 中异常信息,这里只能使用failureForwardUrl
-
运行项目并测试
自定义登录失败处理
和自定义登录成功处理一样,Spring Security 同样为前后端分离开发提供了登录失败的处理,这个类就是 AuthenticationFailureHandler,源码为:
public interface AuthenticationFailureHandler {
/**
* Called when an authentication attempt fails.
* @param request the request during which the authentication attempt occurred.
* @param response the response.
* @param exception the exception which was thrown to reject the authentication
* request.
*/
void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException;
}
根据接口的描述信息,也可以得知登录失败会自动回调这个方法,进一步查看它的默认实现,你会发现failureUrl、failureForwardUrl也是由它的子类实现的
- 自定义 AuthenticationFailureHandler 实现
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
Map<String, Object> result = new HashMap<String, Object>();
result.put("msg", "登录失败: "+exception.getMessage());
result.put("status", 500);
response.setContentType("application/json;charset=UTF-8");
String s = new ObjectMapper().writeValueAsString(result);
response.getWriter().println(s);
}
}
- 配置 AuthenticationFailureHandler
@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeHttpRequests()
//......
.failureHandler(new MyAuthenticationFailureHandler())
//......
}
}
注销登录
Spring Security 中也提供了默认的注销登录配置,在开发时也可以按照自己需求对注销进行个性化定制。
- 开启注销登录
默认开启
@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeHttpRequests()
//.............
.successHandler(new MyAuthenticationSuccessHandler())//认证成功时处理 前后端分离时的处理方案
//.failureForwardUrl("/login.html")//认证失败之后 forward跳转
//.failureUrl("/login.html")//认证失败之后 redirect跳转
.failureHandler(new MyAuthenticationFailureHandler())
//................
.and()
.logout()
//.logoutUrl("/logout")//指定注销登录url
.logoutRequestMatcher(new OrRequestMatcher(
new AntPathRequestMatcher("/aa","GET"),
new AntPathRequestMatcher("/bb","POST")
))
.invalidateHttpSession(true)//默认 会话失效
.clearAuthentication(true)//默认 清除认证标记
.logoutSuccessUrl("/login.html")//注销登录 成功之后跳转页面
//..............
.and()
.csrf().disable();
}
}
- 通过 logout() 方法开启注销配置
- logoutUrl 指定退出登录请求地址,默认是 GET 请求,路径为
/logout
- invalidateHttpSession 退出时是否是 session 失效,默认值为 true
- clearAuthentication 退出时是否清除认证信息,默认值为 true
- logoutSuccessUrl 退出登录时跳转地址
前后端分离注销登录配置
如果是前后端分离开发,注销成功之后就不需要页面跳转了,只需要将注销成功的信息返回前端即可,此时我们可以通过自定义 LogoutSuccessHandler 实现来返回注销之后信息:
/**
* 自定义注销成功之后处理
*/
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
Map<String, Object> result = new HashMap<String, Object>();
result.put("msg", "注销成功,当前认证对象为:"+authentication);
result.put("status", 200);
response.setContentType("application/json;charset=UTF-8");
String s = new ObjectMapper().writeValueAsString(result);
response.getWriter().println(s);
}
}
@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeHttpRequests()
//...................
.logoutSuccessHandler(new MyLogoutSuccessHandler())
//....................
}
}