Spring Security登录认证流程
在上一章节,我们看到未登录时,请求被拦截然后重定向到登录页面。那Spring Security登录认证流程是怎样的呢?现在,来分析一下。
认证流程图

这幅图大致描述登录认证流程:
- 首先访问未被授权的请求
/private资源 FilterSecurityInterceptor过滤器拒绝这个请求并抛出AccessDeniedException的异常。- 因为请求没有被认证,
ExceptionTranslationFilter将开始认证并且重定向到一个地址(这个地址由AuthenticationEntryPoint配置的,在多数情况下AuthenticationEntryPoint的实现类都是LoginUrlAuthenticationEntryPoint)。 - 然后浏览器重定向到该地址。
重定向实现
我们先来看一下重定向流程,在重定向过程中主要涉及:FilterSecurityInterceptor、ExceptionTranslation 、LoginUrlAuthenticationEntryPoint 三个类。

(1)这个请求会被Spring Security的过滤器链的最后一个 FilterSecurityInterceptor 拦截下来。然后由父类判断没有授权,抛出 AccessDeniedException 异常。
(2)抛出的异常会被 FilterSecurityInterceptor 的前一个过滤器 ExceptionTranslationFilter 捕获,然后过滤器 ExceptionTranslationFilter 调用 LoginUrlAuthenticationEntryPoint#commence 方法返回给客户端302,要求客户端重定向到 /login 页面
(3)客户端发送/login请求,/login 请求会被 DefaultLoginPageGeneratingFilter 过滤器拦截,并在该过滤器生产登录页面并返回。
默认登录页面实现
默认登录页面是由过滤器 DefaultLoginPageGenerationFilter 生成的。我们先来看一下过滤器 DefaultLoginPageGeneratingFilter 的属性和初始化过程。
DefaultLoginPageGenerationFilter属性和初始化
public class DefaultLoginPageGeneratingFilter extends GenericFilterBean {
private String loginPageUrl; // 登录页地址
private String logoutSuccessUrl; //登出成功后跳转地址
private String failureUrl; // 登录失败后跳转地址
private String formLoginEnabled;
private String usernameParameter; // 表单参数用户名
private String passwordParameter; // 表单参数密码
// 省略其他属性
private void init(UsernamePasswordAuthenticationFilter authFilter, AbstractAuthenticationProcessingFilter openIDFilter) {
this.loginPageUrl = "/login";
this.logoutSuccessUrl = "/login?logout";
this.failureUrl = "/login?error";
if (authFilter != null) {
this.formLoginEnabled = true;
this.usernameParameter = authFilter.getUsernameParameter();
this.passwordParameter = authFilter.getPasswordParameter();
}
//省略其他
}
}
DefaultLoginPageGenerationFilter拦截部分实现
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
// 判断请求地址是否为failureUrl指定的地址
boolean loginError = this.isErrorPage(request);
// 判断请求地址是否为logoutSuccessUrl指定地址
boolean logoutSuccess = this.isLogoutSuccess(request);
// 如果请求地址不是loginPageUrl地址&&不是failureUrl指定的地址&&不是logoutSuccessUrl指定地址
// 不需要生成默认登录页
if (!this.isLoginUrlRequest(request) && !loginError && !logoutSuccess) {
chain.doFilter(request, response);
} else {
String loginPageHtml = this.generateLoginPageHtml(request, loginError, logoutSuccess);
response.setContentType("text/html;charset=UTF-8");
response.setContentLength(loginPageHtml.getBytes(StandardCharsets.UTF_8).length);
response.getWriter().write(loginPageHtml);
}
}
登录表单配置
这里给出一些表单登录配置项,和之前讲解地方有涉及到,如下所示。
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/loginPage.html")
.loginProcessingUrl("/doLogin")
.defaultSuccessUrl("/hello/security").permitAll()
.and()
.csrf().disable();
}
}
formLogin() 开启表单配置,loginPage() 配置表单页面地址,loginProcessingUrl() 配置表单处理地址,defaultSuccessUrl() 配置表单登录成功后的跳转地址。
这里除了 defaultSuccessUrl() 可以用来登录成功做跳转还可以使用 successForwardUrl() 来做跳转。
defaultSuccessUrl():如果用户在未认证的情况下,访问/hello,会被重定向到登录页面,登录成功时,会重定向到/hello;如果用户直接访问的登录页面,登录成功时,会重定向到defaultSucessUrl()指定的URL。successForWardUrl():该方法不会考虑之前用户访问的地址,登录成功时,由服务自动转发到successForwardUrl()指定的地址。
登录成功跳转实现
defaultSuccessUrl() 还是 successForwardUrl() ,他们都是基于 AuthenticationHandler 接口的实现类。AuthenticationHandler 接口有是 SimpleUrlAuthenticationSuccessHandler 、SavedRequestAwareAuthenticationSuccessHandler 和 ForwardAuthenticationSuccessHandler 三个实现类。其中 defaultSuccessUrl() 方法是依托类 SavedRequestAwareAuthenticationSuccessHandler 来做重定向的;而 successForwardUrl() 方法是依托类 ForwardAuthenticationSuccessHandler 来做服务端转发的。他们都是在过滤器 UsernamePasswordAuthenticationFilter 认证成功后,调用父类的 successfulAuthentication() 方法进行处理。下图是接口继承关系。

备注
本系列都是学习《深入浅出Spring Security》的笔记
本文详细剖析了Spring Security的登录认证流程,包括认证流程图、重定向实现、默认登录页面的配置与实现,以及登录成功后的跳转策略。通过解析DefaultLoginPageGenerationFilter的属性和初始化过程,展示了Spring Security如何生成登录页面并处理登录请求。
5830

被折叠的 条评论
为什么被折叠?



