赞
踩
AuthorizationEndpoint:用于服务授权请求。 请求地址:/oauth/authorize
TokenEndPoint: 用于服务访问令牌的请求。请求地址:/oauth/token
OAuth2AuthenticationProcessingFilter:用于加载给定的认证访问令牌请求的认证
生成token的流程图:
@EnableAuthorizationServer源码:授权认证服务器核心注解
从源码我们知道引入了AuthorizationServerEndpointsConfiguration和AuthorizationServerSecurityConfiguration这2个配置类。AuthorizationServerEndpointsConfiguration源码
从官方文档我们知道这个配置类会存在AuthorizationEndpoint和TokenEndPoint创建。
AuthorizationServerSecurityConfiguration源码如下:
主要的配置ClientDetailsService、UserDetailsService
ClientDetailsService
内部仅有loadClientByClientId(),从方法名我们可以知道是通过clientId来获取client信息,官方提供俩个实现类,我们也可以像UserDetailsService一样自已编写实现类。UserDetailsService
UserDetailsService
内部仅有loadUserByUsername方法
ClientDetailsUserDetailsService UserDetailsService子类,内部维护了ClientDetailsService, loadUserByUsername()方法重写后调用了ClientDetailsService的loadClientByClientId()方法。public class AuthorizationServerConfigurerAdapter implements AuthorizationServerConfigurer { //.配置AuthorizationServer安全认证的相关信息,创建ClientCredentialsTokenEndpointFilter @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { } //配置oauth2的客户端相关信息 @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { } //配置ClientCredentialsTokenEndpointFilter相关类 //配置身份认证器、配置认证方式 //TokenStore,TokenGranter,OAuth2RequestFactory @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { }}
clientCredentialsTokenEndPointFilter源码
1.拦截/oauth/token,获取到clientId和clientsecret信息
2.创建UsernamepasswordAutherticationToken
3.作为AuthenticationManager().authenticate(authRequest)参数调用认证过程
整个认证过程唯一最大的区别在于:
DaoAuthenticationProvider.retrieveUser() 获取认证用户信息时调用的是 ClientDetailsUserDetailsService,根据前面讲述的其内部其实是调用ClientDetailsService 获取到客户端信息。
@EnableResourceServer解析从源码我们知道引入了ResourceServerConfiguration配置类,这个配置类是应用了ResourceServerSecurityConfigurer
ResourceServerSecurityConfigurer的源码 1.创建OAuth2AuthenticationManager对象 2.创建OAuth2AuthenticationProcessingFilter 过滤器 3.将OAuth2AuthenticationProcessingFilter过滤器加载到过滤链上 AuthorizationEndPoint源码 1.getOAuth2RequestFactory根据参数创建AuthorizationRequest。2.判断principal是否已授权,oauth/authorize 设置为无权限访问 ,如果 判断失败则抛出 InsufficientAuthenticationException异常会被 ExceptionTranslationFilter 处理 ,然后重定向到登录页。3.通过getClientDetailsService()获取到ClientDetails客户端信息。4.获取参数中的回调地址和系统配置的回调地址对比。5.验证scope。6.检测客户端是否设置自动授权,客户端配置autoApprove(true)。7.如果设置 autoApprove(true) 则 调用 getAuthorizationCodeResponse() 方法生成code码并回调到设置的回调地址。8.真实生成Code 的方法是generateCode(AuthorizationRequest authorizationRequest, Authentication authentication) 方法:其内部是调用authorizationCodeServices.createAuthorizationCode()方法生成code。 TokenEndPoint解析 1.从principal中获取clientId,进而load client信息。2.从paramters中拿clientid,scope,grantType组装tokenRequest。3.校验client信息,确保从principal拿到的client信息与根据paramters得到的client信息一致。4.根据grantType设置tokenRequest的scope,授权类型有password 模式、authorization_code 模式、refresh_token 模式、client_credentials 模式、implicit 模式。5.如果是授权模式,则清空scope,因为授权请求会确定scope,所以没必要传。6.如果是刷新Token模式,解析并设置scope。7.通过令牌授予者获取token。
TokenGranter
CompositeTokenGranter源码
官方默认调用CompositeTokenGranter的grant()方法,debug追踪知道默认有五个子类加上一个共同的父类(AbstractTokenGranter),然后遍历尝试看使用的是哪种授权方式,ClientCredentialsTokenGranter重写了父类的grant()方法,其余四种都是直接调用父类进行处理。
AbstractTokenGranter.grant()方法实现 1.判断grantType是否匹配。2.获取client信息并验证grantType。3.调用用 getAccess T oken()方法生成token返回。 getAccessToken()方法实现1.通过getOAuth2Authentication()方法获取OAuth2Authentication对象。
2.调用tokenServices.createAccessToken()方法生成token AuthorizationCodeTokenGranter.getOAuth2Authentication()方法实现 1.从tokenRequest中获取code和回调url2.authorizationCodeServices.consumeAuthorizationCode(authorizationCode)通过code获取OAuth2Authentication对象
3.从OAuth2Authentication对象获取OAuth2Request对象并验证回调url和clientid
4.创建一个新的OAuth2Request,并从OAuth2Authentication中获取到Authentication对象
5.通过新的OAuth2Request对象和Authentication对象创建一个全新的OAuth2Authentication对象
生成OAuth2Authentication调用tokenServices.createAccessToken()
查看DefaultTokenServices(AuthorizationServerTokenServices的实现类)的createAccessToken()方法
1.通过tokenStore获取之前存在的token并判断是否为空和是否过期,如果不为空且未过期就直接返回token(我们常用Jwt 这里是 JwtTokenStore ,且 existingAccessToken 永远为空,即每次请求获取token的值均不同,跟RedisTokenStore 是不一样的)。
2.调用createRefreshToken()生成refreshToken。
3.调用createAccessToken(authentication, refreshToken)生成accesstoken。
从源码看出token通过uuid生成的,生成过程相对简单,但是如果我们配置了token增强器(TokenEnhancer)jwtToken就是使用了增强器实现。4.重新覆盖原有的刷新token(原有的 refreshToken 为UUID 数据,覆盖为 jwtToken)并返回token。
token的源码解析流程图如下:
我们获取到了token,就会通过token去拿到资源信息。那么资源服务器是如何通过传入的token去辨别用户并允许返回资源信息的。
整个oauth2与HttpSecurity相关的核心配置
1.创建OAuth2AuthenticationProcessingFilter
2.为OAuth2AuthenticationProcessingFilter提供固定的AuthenticationManager即OAuth2AuthenticationManager,它并没有将OAuth2AuthenticationManager添加到spring的容器中,不然可能会影响spring security的普通认证流程(非oauth2请求),只有被OAuth2AuthenticationProcessingFilter拦截到的oauth2相关请求才被特殊的身份认证器处理。3.设置了TokenExtractor默认的实现—-BearerTokenExtractor
4.相关的异常处理器,可以重写实现
1.调用tokenExtractor.extract()从请求中解析出token信息并存放到authentication 的 principal 字段 中
2.调用 authenticationManager.authenticate() 认证过程:注意此时的 authenticationManager 是 OAuth2AuthenticationManager
authenticationManager.authenticate() 方法实现
1.从authentication获取token
2.调用tokenServices.loadAuthentication()方法通过token参数获取到OAuth2Authentication对象,tokenServices就是我们资源服务器所配置的。
3.checkClientDetails()检测客户端信息,由于授权服务器和资源服务器分离设计,这个检测方法实际没有进行检测
4.设置认证成功标识并返回,返回的是OAuth2Authentication
回顾:
创建token需要的几个必要类 :clientDetailsService,authorizationServerTokenServices,ClientDetails ,TokenRequest,OAuth2Request,authentication和OAuth2Authentication 。要了解这几个类直接的联系。
clientDetailsService和authorizationServerTokenServices可以直接从spring 容器获取,ClientDetails可以从请求参数中获取,有了ClientDetails 就有了TokenRequest,有了TokenRequest和authentication就有了OAuth2Authentication,有了OAuth2Authentication就能生成OAuth2AccessToken。
对spring security oauth2的源码解析完毕,有觉得还不错的小伙伴可以关注我,更多精彩好文等得你。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。