第2章 Spring Security登录认证流程

本文详细剖析了Spring Security的登录认证流程,包括认证流程图、重定向实现、默认登录页面的配置与实现,以及登录成功后的跳转策略。通过解析DefaultLoginPageGenerationFilter的属性和初始化过程,展示了Spring Security如何生成登录页面并处理登录请求。

Spring Security登录认证流程

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

认证流程图

在这里插入图片描述

这幅图大致描述登录认证流程:

  1. 首先访问未被授权的请求 /private 资源
  2. FilterSecurityInterceptor 过滤器拒绝这个请求并抛出 AccessDeniedException 的异常。
  3. 因为请求没有被认证,ExceptionTranslationFilter 将开始认证并且重定向到一个地址(这个地址由 AuthenticationEntryPoint 配置的,在多数情况下 AuthenticationEntryPoint 的实现类都是 LoginUrlAuthenticationEntryPoint)。
  4. 然后浏览器重定向到该地址。
重定向实现

我们先来看一下重定向流程,在重定向过程中主要涉及:FilterSecurityInterceptorExceptionTranslationLoginUrlAuthenticationEntryPoint 三个类。

在这里插入图片描述

(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 接口有是 SimpleUrlAuthenticationSuccessHandlerSavedRequestAwareAuthenticationSuccessHandlerForwardAuthenticationSuccessHandler 三个实现类。其中 defaultSuccessUrl() 方法是依托类 SavedRequestAwareAuthenticationSuccessHandler 来做重定向的;而 successForwardUrl() 方法是依托类 ForwardAuthenticationSuccessHandler 来做服务端转发的。他们都是在过滤器 UsernamePasswordAuthenticationFilter 认证成功后,调用父类的 successfulAuthentication() 方法进行处理。下图是接口继承关系。

在这里插入图片描述

备注
本系列都是学习《深入浅出Spring Security》的笔记

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值