@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception{
http.formLogin()//采用form的方式提交账号密码,默认传入字段名为username,password
.loginPage("/login.html")
.loginProcessingUrl("/doLogin")
.usernameParameter("uname")
.passwordParameter("password")
.successHandler(new LoginSuccessHandler( ))//登录成功由LoginSuccessHandler处理,LoginSuccessHandler需要继承AuthenticationSuccessHandler
.failureHandler(new LoginFailureHandler( )) //登录失败由LoginFailureHandler处理
.permitAll()
}
}
在Spring Security中,如果我们需要自定义配置的话,就需要编写配置类,继承WebSecurityConfigurerAdapter
(1)首先configure方法是一个链式配置,当然也可以不用链式配置,每一个属性配置完毕后从http.从新写起
(2)formLogin()表示开启表单登陆配置,loginPage用来指定登陆页面地址,usernameParameter指定表单传入的账号的属性名,passwordParameter指定表单传入的密码的属性名,loginProcessingUrl用来配置登录接口地址,需要注意的是usernameParameter,passwordParameter,passwordParameter需要和前端表格中一样,successHandler表明登录成功后的处理器,failureHandler表明登录失败的处理器,permitAll表明跟登陆有关的页面和接口不做拦截,defaultSuccessUrl表明登陆成功后的跳转到之前访问的地址,successForwardUrl表明登陆成功后会跳转到指定的地址,failureUrl表明登陆失败的跳转地址
源码分析
无论是defaultSuccessUrl,successForwardUrl都是调用了AuthenticationSuccessHandler接口的实例(SavedRequestAwareAuthenticationSuccessHandler 和 ForwardAuthenticationSuccessHandler)
SavedRequestAwareAuthenticationSuccessHandler 类
defaultSuccessUrl调用的就是这个类的实例,我们看一下源码
public class SavedRequestAwareAuthenticationSuccessHandler extends
SimpleUrlAuthenticationSuccessHandler {
protected final Log logger = LogFactory.getLog(this.getClass());
private RequestCache requestCache = new HttpSessionRequestCache();
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws ServletException, IOException {
//这里取出了一个request
SavedRequest savedRequest = requestCache.getRequest(request, response);
if (savedRequest == null) {
super.onAuthenticationSuccess(request, response, authentication);
return;
}
String targetUrlParameter = getTargetUrlParameter();
if (isAlwaysUseDefaultTargetUrl()
|| (targetUrlParameter != null && StringUtils.hasText(request
.getParameter(targetUrlParameter)))) {
requestCache.removeRequest(request, response);
super.onAuthenticationSuccess(request, response, authentication);
return;
}
clearAuthenticationAttributes(request);
// Use the DefaultSavedRequest URL !!关键的一句!!
String targetUrl = savedRequest.getRedirectUrl();
logger.debug("Redirecting to DefaultSavedRequest Url: " + targetUrl);
// 这里有一个很明显的跳转操作,追踪targetUrl怎么来的
getRedirectStrategy().sendRedirect(request, response, targetUrl);
}
public void setRequestCache(RequestCache requestCache) {
this.requestCache = requestCache;
}
}
(1)先从requestCache取出之前缓存的请求,如果没有,就说明用户在登录页面之前没有访问其他页面,就调用父类的onAuthenticationSuccess方法,跳转到defaultSuccessUrl指定的地址
(2)如果targetUrl (用户显示定义 http://localhost:8080/login?target=/hello)存在,则登录成功后跳转到targetUrl中,如果alwaysUseDefaultTargetUrl为true,则登陆成功后跳转到defaultSuccessUrl指定的地址
(3)以上条件都不满足,登陆成功后则从requestCache取出之前缓存的请求,进行跳转
自定义登陆成功/失败处理器
在前后端分离的项目中,我们需要后端返回的是json数据,而不是进行页面的跳转,此时就需要我们自定义一个AuthenticationSuccessHandler接口的实现类,并通过successHandler/failureHandler 指定
AuthenticationSuccessHandler接口的核心方法就是onAuthenticationSuccess
@Comp
public class LoginSuccessHandler implements AuthenticationSuccessHandler{
@Override
public void onAuthenticationSuccess(HttpServletRequest request,HttpServletResponse response,Authentication authentication) throws IOException,ServletException{
//这里返回我们封装好的统一结果类实例即可
}
}
登录失败处理器同理,不过继承的是AuthenticationFailureHandler接口
注销登录
http.logout()
.logoutUrl("/logout")
.invaildateHttpSession(true)
.clearAuthentication(true)
.logoutSuccessUrl("/mylogin.html")
(1).logout()方法表示开启注销登录功能
(2).logoutUrl()制定了注销登录的请求地址,默认是GET请求
(3).invaildateHttpSession 表明是否使session失效,默认为true
(4).clearAuthentication表明是否消除认证信息,默认为true
(5).logoutSuccessUrl()表明注销成功后的跳转地址
也可以使用自定义的登出成功处理器
.logoutSuccessHandler(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//返回我们的统一结果封装类
}
})