认证服务器颁发Token逻辑-密码认证模式(源码解释)

本文详细介绍了OAuth2认证服务器中密码模式的认证逻辑,包括客户端认证的Basic Authentication Filter和Username/Password的校验过程。重点讲解了TokenEndpoint、TokenRequest对象构建、OAuth2AccessToken的创建以及ResourceOwnerPasswordTokenGranter在密码验证中的作用。在密码验证完成后,用户信息并未立即存储,而是在用户使用Token访问资源时,由OAuth2AuthenticationProcessingFilter处理并存储到SecurityContextHolder中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

密码模式认证 其实有两块认证,第一个是客户端认证,还有课是密码认证,客户端认证 也就是 你的 Basic Auth 里面传的 Username(ClientId) 和 Password(Secret); 而密码认证 也就是你再Body中传的 Username(用户名) 和 Password(密码); 他们两个认证前部分代码逻辑都是一致的,入口都是 TokenEndpoint , 后面部分逻辑不一样 ,下面根据这部分知识对应源码进行解释

ClientId And ClientSecret 校验

BasicAuthenticationFilter

这个是客户端和秘钥的校验入口过滤器


// 默认是 ProviderManager;
private AuthenticationManager authenticationManager;

@Override
protected void doFilterInternal(HttpServletRequest request,
		HttpServletResponse response, FilterChain chain)
				throws IOException, ServletException {
   
	final boolean debug = this.logger.isDebugEnabled();
	try {
   
		UsernamePasswordAuthenticationToken authRequest = authenticationConverter.convert(request);
		if (authRequest == null) {
   
			chain.doFilter(request, response);
			return;
		}

		String username = authRequest.getName();

		if (debug) {
   
			this.logger
					.debug("Basic Authentication Authorization header found for user '"
							+ username + "'");
		}

		if (authenticationIsRequired(username)) {
   
			
			// 核心方法再此处 
			Authentication authResult = this.authenticationManager
					.authenticate(authRequest);

			if (debug) {
   
				this.logger.debug("Authentication success: " + authResult);
			}

			SecurityContextHolder.getContext().setAuthentication(authResult);

			this.rememberMeServices.loginSuccess(request, response, authResult);

			onSuccessfulAuthentication(request, response, authResult);
		}

	}
	catch (AuthenticationException failed) {
   
		SecurityContextHolder.clearContext();

		if (debug) {
   
			this.logger.debug("Authentication request for failed!", failed);
		}

		this.rememberMeServices.loginFail(request, response);

		onUnsuccessfulAuthentication(request, response, failed);

		if (this.ignoreFailure) {
   
			chain.doFilter(request, response);
		}
		else {
   
			this.authenticationEntryPoint.commence(request, response, failed);
		}

		return;
	}

	chain.doFilter(request, response);
}

ProviderManager

public Authentication authenticate(Authentication authentication) throws AuthenticationException {
   
	Class<? extends Authentication> toTest = authentication.getClass();
	AuthenticationException lastException = null;
	AuthenticationException parentException = null;
	Authentication result = null;
	Authentication parentResult = null;
	boolean debug = logger.isDebugEnabled();

	for (AuthenticationProvider provider : getProviders()) {
   
		if (!provider.supports(toTest)) {
   
			continue;
		}

		if (debug) {
   
			logger.debug("Authentication attempt using "
					+ provider.getClass().getName());
		}

		try {
   
			// 这个是核心方法 获取认证对象
			result = provider.authenticate(authentication);

			if (result != null) {
   
				copyDetails(authentication, result);
				break;
			}
		}
		catch (AccountStatusException | InternalAuthenticationServiceException e) {
   
			prepareException(e, authentication);
			// SEC-546: Avoid polling additional providers if auth failure is due to
			// invalid account status
			throw e;
		} catch (AuthenticationException e) {
   
			lastException = e;
		}
	}

	if (result == null && parent != null) {
   
		// Allow the parent to try.
		try {
   
			result = parentResult = parent.authenticate(authentication);
		}
		catch (ProviderNotFoundException e) {
   
			// ignore as we will throw below if no other exception occurred prior to
			// calling parent and the parent
			// may throw ProviderNotFound even though a provider in the child already
			// handled the request
		}
		catch (AuthenticationException e) {
   
			lastException = parentException = e;
		}
	}

	if (result != null) {
   
		if (eraseCredentialsAfterAuthentication
				&& (result instanceof CredentialsContainer)) {
   
			// Authentication is complete. Remove credentials and other secret data
			// from authentication
			((CredentialsContainer) result).eraseCredentials();
		}

		// If the parent AuthenticationManager was attempted and successful then it will publish an AuthenticationSuccessEvent
		// This check prevents a duplicate AuthenticationSuccessEvent if the parent AuthenticationManager already published it
		if (parentResult == null) {
   
			eventPublisher.publishAuthenticationSuccess(result);
		}
		// 客户端的认证 结束了 到此就返回 走下面的过滤器链
		return result;
	}

	// Parent was null, or didn't authenticate (or throw an exception).

	if (lastException == null) {
   
		lastException = new ProviderNotFoundException(messages.getMessage(
				"ProviderManager.providerNotFound",
				new Object[] {
    toTest.getName() },
				"No AuthenticationProvider found for {0}"));
	}

	// If the parent AuthenticationManager was attempted and failed then it will publish an AbstractAuthenticationFailureEvent
	// This check prevents a duplicate AbstractAuthenticationFailureEvent if the parent AuthenticationManager already published it
	if (parentException == null) {
   
		prepareException(lastException, authentication);
	}

	throw lastException;
}

AbstractUserDetailsAuthenticationProvider

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值