OAuth2TokenEndpointFilter
是负责颁发token
的过滤器。
负责将提交的参数转换为Authentication
. 该属性的实例为DelegatingAuthenticationConverter
, 是一个委派转换器,委派给下面的Convert执行
下面三个convert
0 = {OAuth2AuthorizationCodeAuthenticationConverter@7035}
1 = {OAuth2RefreshTokenAuthenticationConverter@7036}
2 = {OAuth2ClientCredentialsAuthenticationConverter@7037}
在构造方法中初始化的。
this.authenticationConverter = new DelegatingAuthenticationConverter(
Arrays.asList(
new OAuth2AuthorizationCodeAuthenticationConverter(),
new OAuth2RefreshTokenAuthenticationConverter(),
new OAuth2ClientCredentialsAuthenticationConverter())
);
Converter负责将请求信息转换为 Authentication
1. OAuth2ClientCredentialsAuthenticationConverter
得到的是 OAuth2ClientCredentialsAuthenticationToken
.
2. OAuth2RefreshTokenAuthenticationConverter
得到的是 OAuth2RefreshTokenAuthenticationToken
.
3. OAuth2AuthorizationCodeAuthenticationConverter
得到的是 OAuth2AuthorizationCodeAuthenticationToken
.
负责对Authentication
进行认证。它的实例对象是ProviderManager
,也是类似一个委派验证类。他让注册在他下面的AuthenticationManager
依次去验证。
0 = {AnonymousAuthenticationProvider@7368}
1 = {OAuth2ClientAuthenticationProvider@7369}
2 = {OAuth2AuthorizationCodeRequestAuthenticationProvider@7370}
3 = {OAuth2AuthorizationCodeAuthenticationProvider@7371}
4 = {OAuth2RefreshTokenAuthenticationProvider@7372}
5 = {OAuth2ClientCredentialsAuthenticationProvider@7373}
6 = {OAuth2TokenRevocationAuthenticationProvider@7374}
7 = {OidcUserInfoAuthenticationProvider@7375}
8 = {OAuth2TokenIntrospectionAuthenticationProvider@7376}
9 = {JwtAuthenticationProvider@7377}
只是与上面的Converter
不同的是,
converter
是通过grant_type
之类的来判断是否执行AuthenticationManager
是直接调用supports方法来判断是否执行的.if (!provider.supports(toTest)) {
continue;
}
该类在authentication
客户端模式的AuthenticationManager
为OAuth2ClientCredentialsAuthenticationProvider
. 他验证的Authentication
对象为OAuth2ClientCredentialsAuthenticationToken
,验证成功后返回的Authentication
对象为OAuth2AccessTokenAuthenticationToken
. 这个里面没有再验证客户端信息,是因为在Converter
得到OAuth2ClientCredentialsAuthenticationToken
对象时就是从SecurityContextHolder
中获取的。
Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();
....
return new OAuth2ClientCredentialsAuthenticationToken(
clientPrincipal,
requestedScopes,
additionalParameters
);
从上面的代码分析可以推测,在前面的filter中应该验证过.在里面把客户端的认证信息放进去的,中filter链中看最可能是应该是OAuth2ClientAuthenticationFilter
。
0 = {WebAsyncManagerIntegrationFilter@7962}
1 = {SecurityContextPersistenceFilter@7963}
2 = {ProviderContextFilter@7964}
3 = {HeaderWriterFilter@7965}
4 = {LogoutFilter@7966}
5 = {OAuth2AuthorizationEndpointFilter@6806}
6 = {OidcProviderConfigurationEndpointFilter@7967}
7 = {NimbusJwkSetEndpointFilter@7968}
8 = {OAuth2AuthorizationServerMetadataEndpointFilter@7969}
9 = {OAuth2ClientAuthenticationFilter@7970}
10 = {UsernamePasswordAuthenticationFilter@7971}
11 = {DefaultLoginPageGeneratingFilter@6834}
12 = {DefaultLogoutPageGeneratingFilter@7972}
13 = {BearerTokenAuthenticationFilter@7973}
14 = {RequestCacheAwareFilter@7974}
15 = {SecurityContextHolderAwareRequestFilter@7975}
16 = {AnonymousAuthenticationFilter@7976}
17 = {SessionManagementFilter@7977}
18 = {ExceptionTranslationFilter@7978}
19 = {FilterSecurityInterceptor@7979}
20 = {OAuth2TokenEndpointFilter@6868}
21 = {OAuth2TokenRevocationEndpointFilter@7980}
22 = {OidcUserInfoEndpointFilter@7981}
23 = {OAuth2TokenIntrospectionEndpointFilter@7982}
OAuth2ClientAuthenticationFilter
核心代码:
Authentication authenticationRequest = this.authenticationConverter.convert(request);
if (authenticationRequest instanceof AbstractAuthenticationToken) {
((AbstractAuthenticationToken) authenticationRequest).setDetails(
this.authenticationDetailsSource.buildDetails(request));
}
if (authenticationRequest != null) {
Authentication authenticationResult = this.authenticationManager.authenticate(authenticationRequest);
this.authenticationSuccessHandler.onAuthenticationSuccess(request, response, authenticationResult);
}
从头里面获取OAuth2ClientAuthenticationToken
对象,OAuth2ClientAuthenticaitonProvider
负责验证OAuth2ClientAuthenticationToken
.
OAuth2ClientAuthenticaitonProvider
校验的操作是通过RegisteredClientRepository
去查询client
信息然后比对密码等信息。
在onAuthenticationSuccess
方法中将认证的客户端存储到SecurityContextHolder
。
private void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
securityContext.setAuthentication(authentication);
SecurityContextHolder.setContext(securityContext);
}
从前面的分析可以知道OAuth2ClientCredentialsAuthenticationProvider
其实已经把token
颁发了,后续token能继续被使用那服务端一定有存储相应的token吗?
token
吗?服务端会存储token。而负责存储token业务的操作在OAuth2AuthorizationService
中,OAuth2AuthorizationService是一个接口,该接口存在两个对应的实现:
token
存在内存里面,另外一个将token
存到数据库中.注入实现的时候如下:static <B extends HttpSecurityBuilder<B>> OAuth2AuthorizationService getAuthorizationService(B builder) {
OAuth2AuthorizationService authorizationService = builder.getSharedObject(OAuth2AuthorizationService.class);
if (authorizationService == null) {
authorizationService = getOptionalBean(builder, OAuth2AuthorizationService.class);
if (authorizationService == null) {
authorizationService = new InMemoryOAuth2AuthorizationService();
}
builder.setSharedObject(OAuth2AuthorizationService.class, authorizationService);
}
return authorizationService;
}
所以希望自定义存储的位置,可以去实现OAuth2AuthorizationService
,并且在SpringSecurity
初始化配置的时候,设置到SharedObject
中。
OAuth2ResourceOwnerPasswordAuthenticationProvider