springsecurity认证(1)

springsecurity的认证流程

 springsecurity的认证流程如下,登录请求被UsernamePasswordAuthenticationFilter拦截,过滤器调用认证管理器,认证管理器使用authenticationprovider来进行认证,userdetailservice用来提供用户信息(userdetails)给authenticationprovider以便认证

UsernamePasswordAuthenticationFilter

UsernamePasswordAuthenticationFilter继承了AbstractAuthenticationProcessingFilter,AbstractAuthenticationProcessingFilter里doFilter负责拦截请求,调用虚拟方法attemptAuthentication认证,UsernamePasswordAuthenticationFilter重写attemptAuthentication方法来实现认证。doFilter源码方法如下

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {

		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;
        
//     判断是否拦截请求,默认的拦截路径是/login,post请求
		if (!requiresAuthentication(request, response)) {
			chain.doFilter(request, response);

			return;
		}

		if (logger.isDebugEnabled()) {
			logger.debug("Request is to process authentication");
		}

		Authentication authResult;

		try {
//          认证
			authResult = attemptAuthentication(request, response);
			if (authResult == null) {
				// return immediately as subclass has indicated that it hasn't completed
				// authentication
				return;
			}
			sessionStrategy.onAuthentication(authResult, request, response);
		}
		catch (InternalAuthenticationServiceException failed) {
			logger.error(
					"An internal error occurred while trying to authenticate the user.",
					failed);
			unsuccessfulAuthentication(request, response, failed);

			return;
		}
		catch (AuthenticationException failed) {
			// 认证方法通过抛出异常AuthenticationException 来通知过滤器认证失败,调用认证失败后的处理方法
			unsuccessfulAuthentication(request, response, failed);

			return;
		}

		// Authentication success
		if (continueChainBeforeSuccessfulAuthentication) {
			chain.doFilter(request, response);
		}
//      认证成功后的处理方法
		successfulAuthentication(request, response, chain, authResult);
	}

UsernamePasswordAuthenticationFilter通过重写attemptAuthentication来实现认证,源码如下,其中获取用户名密码,默认的字段是username和password,认证管理器会调用AuthenticationProvider来进行认证,AuthenticationProvider有多个实现,默认的是ProviderManager,ProviderManager持有多个AuthenticationProvider的集合,通过遍历调用来实现认证。

public Authentication attemptAuthentication(HttpServletRequest request,
			HttpServletResponse response) throws AuthenticationException {
		if (postOnly && !request.getMethod().equals("POST")) {
			throw new AuthenticationServiceException(
					"Authentication method not supported: " + request.getMethod());
		}
// 获取用户名密码
		String username = obtainUsername(request);
		String password = obtainPassword(request);

		if (username == null) {
			username = "";
		}

		if (password == null) {
			password = "";
		}

		username = username.trim();

		UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
				username, password);

		// Allow subclasses to set the "details" property
		setDetails(request, authRequest);
// 调用认证管理器进行认证
		return this.getAuthenticationManager().authenticate(authRequest);
	}

认证成功

认证成功后,会将认证信息放入SecurityContext中,SecurityContext可以通过SecurityContextHolder来获取,SecurityContext存放在SecurityContextHolderStrategy中,SecurityContextHolderStrategy有多重实现,一般我们web项目里的实现用的是ThreadLocalSecurityContextHolderStrategy,ThreadLocalSecurityContextHolderStrategy将SecurityContext存放在ThreadLocal中,也就是存放在当前线程里,一般项目线程都是由线程池来管理,及时请求结束,也不会销毁线程,所以在请求结束前必须要清空ThreadLocal,认证中只负责在上下文中存放认证信息,上线文的管理由其他过滤器实现。源码如下

protected void successfulAuthentication(HttpServletRequest request,
			HttpServletResponse response, FilterChain chain, Authentication authResult)
			throws IOException, ServletException {

		if (logger.isDebugEnabled()) {
			logger.debug("Authentication success. Updating SecurityContextHolder to contain: "
					+ authResult);
		}
// 将认证成功的信息存放在security的上下文里
		SecurityContextHolder.getContext().setAuthentication(authResult);

		rememberMeServices.loginSuccess(request, response, authResult);

		// Fire event
		if (this.eventPublisher != null) {
			eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(
					authResult, this.getClass()));
		}

		successHandler.onAuthenticationSuccess(request, response, authResult);
	}

参考博文:

https://www.cnblogs.com/storml/p/10937486.html

https://www.jianshu.com/p/e3496a31781c

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值