【SpringSecurity系列02】SpringSecurity 表单认证逻辑源码解读

概要

前面一节,通过简单配置即可实现SpringSecurity表单认证功能,而今天这一节将通过阅读源码的形式来学习SpringSecurity是如何实现这些功能, 前方高能预警,本篇分析源码篇幅较长

过滤器链

前面我说过SpringSecurity是基于过滤器链的形式,那么我解析将会介绍一下具体有哪些过滤器。

Filter Class 介绍
SecurityContextPersistenceFilter 判断当前用户是否登录
CrsfFilter 用于防止csrf攻击
LogoutFilter 处理注销请求
UsernamePasswordAuthenticationFilter 处理表单登录的请求(也是我们今天的主角)
BasicAuthenticationFilter 处理http basic认证的请求

由于过滤器链中的过滤器实在太多,我没有一一列举,调了几个比较重要的介绍一下。

通过上面我们知道SpringSecurity对于表单登录的认证请求是交给了UsernamePasswordAuthenticationFilter处理的,那么具体的认证流程如下:

Spring Security ç™"录流程.jpg

从上图可知,UsernamePasswordAuthenticationFilter继承于抽象类AbstractAuthenticationProcessingFilter

具体认证是:

  1. 进入doFilter方法,判断是否要认证,如果需要认证则进入attemptAuthentication方法,如果不需要直接结束
  2. attemptAuthentication方法中根据username跟password构造一个UsernamePasswordAuthenticationToken对象(此时的token是未认证的),并且将它交给ProviderManger来完成认证。
  3. ProviderManger中维护这一个AuthenticationProvider对象列表,通过遍历判断并且最后选择DaoAuthenticationProvider对象来完成最后的认证。
  4. DaoAuthenticationProvider根据ProviderManger传来的token取出username,并且调用我们写的UserDetailsService的loadUserByUsername方法从数据库中读取用户信息,然后对比用户密码,如果认证通过,则返回用户信息也是就是UserDetails对象,在重新构造UsernamePasswordAuthenticationToken(此时的token是 已经认证通过了的)。

接下来我们将通过源码来分析具体的整个认证流程。

AbstractAuthenticationProcessingFilter

AbstractAuthenticationProcessingFilter 是一个抽象类。所有的认证认证请求的过滤器都会继承于它,它主要将一些公共的功能实现,而具体的验证逻辑交给子类实现,有点类似于父类设置好认证流程,子类负责具体的认证逻辑,这样跟设计模式的模板方法模式有点相似。

现在我们分析一下 它里面比较重要的方法

1、doFilter

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {
   
		// 省略不相干代码。。。
    // 1、判断当前请求是否要认证
		if (!requiresAuthentication(request, response)) {
   
      // 不需要直接走下一个过滤器
			chain.doFilter(request, response);
			return;
		}
		try {
   
      // 2、开始请求认证,attemptAuthentication具体实现给子类,如果认证成功返回一个认证通过的Authenticaion对象
			authResult = attemptAuthentication(request, response);
			if (authResult == null) {
   
				return;
			}
      // 3、登录成功 将认证成功的用户信息放入session SessionAuthenticationStrategy接口,用于扩展
			sessionStrategy.onAuthentication(authResult, request, response);
		}
		catch (InternalAuthenticationServiceException failed) {
   
      //2.1、发生异常,登录失败,进入登录失败handler回调
			unsuccessfulAuthentication(request, response, failed);
			return;
		}
		catch (AuthenticationException failed) {
   
      //2.1、发生异常,登录失败,进入登录失败处理器
			unsuccessfulAuthentication(request, response, failed);
			return;
		}
		// 3.1、登录成功,进入登录成功处理器。
		successfulAuthentication(request, response, chain, authResult);
	}

2、successfulAuthentication

登录成功处理器

protected void successfulAuthentication(HttpServletRequest request,
			HttpServletResponse response, FilterChain chain, Authentication authResult)
			throws IOException, ServletException {
   
    //1、登录成功 将认证成功的Authentication对象存入SecurityContextHolder中
    // 	 SecurityContextHolder本质是一个ThreadLocal
		SecurityContextHolder.getContext().setAuthentication(authResult);
    //2、如果开启了记住我功能,将调用rememberMeServices的loginSuccess 将生成一个token
  	//   将token放入cookie中这样 下次就不用登录就可以认证。具体关于记住我rememberMeServices的相关分析我					们下面几篇文章会深入分析的。
		rememberMeServices.loginSuccess(request, response, authResult
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值