前言:
资源服务器搭建分为两种:
(一) 授权中心与资源服务在同一进程中部署
(二)授权中心与资源服务各自在不同进程中部署
本文主要讲解OAuth2中授权服务与资源服务分离这种情况,并且资源服务器远程调用授权服务器进行身份验证
资源服务搭建
但实际上我只配置了以下内容:
因为我只要一配置客户端,服务我就起不起来,所以我就没有配置客户端client
这里,我配置的授权服务器token校验地址为http://10.1.62.33:8085/oauth/check_token,使用token进行校验(当然也可以使用用户信息进行校验,指定授权服务器获取用户认证信息地址并设置preferTokenInfo为false即可)
备注: /oauth/check_token 为oauth2.0自带的接口, 10.1.62.33:8085为认证服务器的部署地址
可以看到,我的资源服务除了登录之外,所有的接口都必须要登录认证后才能访问。
请求地址:
http://localhost:8085/oauth/token?grant_type=password&client_id=clientApp&client_secret=&username=user_1&password=
资源服务接口资源准备:
访问资源服务器接口,不带token的情况下,不能访问资源服务器接口:
访问资源服务器接口,带token的情况下,能正常访问资源服务器接口:
2、流程解析
(1)通过token方式从授权服务获取用户信息
这种方式对应的资源服务配置如下:
preferTokenInfo设置为true并且指定了token授权服务器验证地址,这种方式会通过token获取认证信息。具体流程我稍后慢慢解析。
通过《oauth2认证流程》一文的认证流程分析可以知道,OAuth客户端认证请求处理的过滤器是OAuth2AuthenticationProcessingFilter,我是我们首先看该过滤器的处理过程:
认证信息由TokenExtractor的实现类BearerTokenExtractor类生成,具体代码如下:
最后交给OAuth2AuthenticationManager认证管理器认证代码如下:
可以看到该认证管理器最终使用tokenServices(实现类RemoteTokenServices)到授权服务查询认证信息,具体查询实现代码如下:
那么问题来了,请求的地址url为“http://127.0.0.1:7000/oauth/check_token”的授权服务是如何返回用户认证信息的呢?通过《OAuth2认证流程解析》一文,我们可以直接定位到CheckTokenEndpoint端点,可以看到它的实现代码如下:
可以看到最终还是通过tokenStore读取token信息,这里我们注入的tokenStore为JdbcTokenStore所以会从数据库中查询对应的token和认证信息,最终见认证信息转为map后返回给客户端,我的token获取认证信息转为map后的结果如下:
可以看到查询到了包括如下重要信息:
可以访问的资源服务列表
- scope范围
- expire过期时间
- 用户名
- 权限数组
- 客户端id
- 客户端秘钥信息
以上信息很重要,是资源服务判断是否有权限访问的依据!!!
通过上述流程的解析,我们看到我们在资源服务与授权服务分离的情况下如何检验携带的token是否有对应访问权限的验证的整个过程。首先,oauth2会检查头部或查询参数是否携带access_token,没有则使用本地安全配置投票查看是否可以访问对应资源,如果存在则从授权服务指定地址获取认证信息,然后检查该token是否有改资源服务的访问权限;
以上就是通过token获取认证信息并授权访问的过程,这里只演示了认证部分,授权部分可以直接在资源服务的访问安全策略配置或者直接使用oauth2的注解形式进行控制;
(2)通过从授权服务通过用户名密码加密方式获取用户认证信息方式进行验证
这种方式其实是在访问资源服务的时候一并带上access_token(可以是请求头或查询参数),当请求达到后台之后,资源服务授权过滤器会从中获取对应的token,然后根据资源服务器配置的用户信息url传递至授权服务器获取用户认证信息。
这种方式对应的资源服务配置如下:
preferTokenInfo设置为false并且指定了授权服务器用户信息获取地址user-info-uri,这种方式会通过token获取认证信息。具体流程我们接下来一一解析。
有了以上通过token方式验证方式解析之后,我们可以直接定位到OAuth2AuthenticationProcessingFilter
最终调用认证管理器统一认证
此时我们的tokenServices的实现为UserInfoTokenServices,它是从授权服务获取用户认证信息:
它最终通过get方式从授权服务器获取用户的认证信息,地址为配置url“http://127.0.0.1:7000/user/principal”,token为访问的token,实现如下:
OAuth2RestTemplate 继承自RestTemplate,其实用法和参数也都差不多,用postForEntity发送post请求,getForEntity发送get请求。我们在授权服务提供对应的接口(与配置相同),例如我的授权服务给定的一个获取用户认证信息的接口为(http://127.0.0.1:7000/user/principal)
测试:
我们可以通过携带token(注意,如上所说这里的token是base64(真实用户名:密码))加密后的值如(base64(admin:123))的直接使用浏览器访问授权返回结果:
同样,如果资源服务器通过从授权服务器获取用户认证信息的方式进行验证,那么,浏览器直接访问资源服务器,同样也需要携带一个access_token参数(头或查询参数)直接访问资源服务器的对应资源或接口即可,但是要注意,这里的access_token不是从授权服务器获取的token,而是配置类型为base64或Bearer加密的用户名和密码的值(如base64(admin:),注意用户名不是客户端id,密码不是客户端秘钥)。Get请求如下:
根据以上介绍,授权服务器提供了一个获取用户认证信息的接口,在访问该接口前客户端将获取的token放入到请求授权服务器的Authorization头字段中,在到达端点前,授权服务器经过BasicAuthenticationFilter的过滤器拦截并解析出用户名、密码,然后通过userDetails接口获取用户名密码进行比对验证,通过之后则最后到达端点/principal,最后返回用户认真信息(注,用户认证信息会自注入到端点的参数中),请求过程如上所示getForEntity所示。
当授权服务器返回用户认证信息之后,接下来资源服务会通过认证信息鉴定用户权限,通过之后到达资源服务器的请求端点并提供对应服务。
认证成功之后,发布认证事件
最后达到我们的端点:
这里我访问的接口是/hi, 认证成功之后访问结果:
综上所述,资源服务器从授权服务器获取用户信息的方式有两种:
- 通过授权服务器获取的token到授权服务器获取用户认证信息
- 通过用户名密码编码后的token作为Authorization头字段从授权服务获取用户认证信息
之所以加载对应配置,原因是引入了OAuth2 的autoConfigure自动配置类注解:
这就是说通过配置文件配置的id是无效的,那么是通过什么途径配置上去的?让我们具体看看加载的关键细节:
其中ResourceServerSecurityConfigurer默认的安全配置加载:
在看看我们自己的资源服务配置:
默认资源服务名称为oauth2-resource:
我们重写了对应方法,给定了自己的资源服务器id,这样就覆盖了oauth2-resource,达到自定义资源服务id的目的;
所以,通过以上代码,我们可以看到在不配置资源服务名称的情况下,资源服务默认名称为oauth2-resource,如果注册客户端信息的时候,没有指定资源服务的id或id不相等的情况下,用户登录后是无法访问该资源服务的,如我的client注册信息记录如下:
指定对应client_id为my_client_id的用户只能访问id为gate_way_server的资源服务,多个则以逗号隔开,所以我的资源服务id配置必须该为gate_way_server才能使用对应token访问!!
知道原因之后,为了能让yaml文件配置的id生效,我们可以自己读取该属性然后配置上去:
token令牌校验
userInfo用户信息校验
那么问题来了,它是如何通过配置方式控制不同的校验方式的?首先我带领大家看看启动的堆栈信息与第三节加载一样
我们依然关注资源服务配置类ResourceServerConfiguration的configure方法即可:
这里的关键就是配置tokenStore的代码:
其他具体的实现resolveTokenServices如下所示:
它是从ResourceServerConfiguration自己的属性列表中获取的,经过调试tokenServices.size()正好为1(如UserInfoTokenServices),那么tokenServices是怎么来的? 我们看到tokenServices是Autowired自动装载进来的。这就有点难办了? 那配置文件的读取到时是哪个类?
其实想到这点,我们就可以知道,正式因为我们配置了资源服务器配置所以才会加载对应的配置文件,首先我们查看我们的资源服务器配置代码:
它很简单,是继承了ResourceServerConfigurerAdapter资源服务器配置类适配器,那么可想而知,配置文件的加载肯定是在ResourceServerConfigurerAdapter中了再次查看发现它又实现了接口ResourceServerConfigurer,我们顺着这个思路可以直接定位到父类的各个实现子类:
其源码如下所示:
看到没,终于见到久违的配置加载类了,他加载的是配置文件前缀为“security.oauth2.resource”的配置。我们也可以看到支持的token类型、Jwt等
通过设置断点到,我们可以看到配置加载的源头是OAuth2AutoConfiguration,这个正式我们pom中加载的自动加载jar包:
它加载了OAuth2ClientProperties属性,也就是客户端security.oauth2.client配置信息:
也就是说oauth2的client客户端信息是必须要配置的(我之前说过这里可以不配置,我这里道个歉,误导大家了,对不住,很多事还是的看源码!),最终我们跟进到tokenService的加载类:
当我们配置资源服务通过用户信息url方式验证的时候如下TokenServices配置生效:
当我们配置token认证方式的时候,如下配置生效:
也就是说两个tokenService是通过preferTokenInfo改变的。
以上就是资源服务与授权服务分离情况下使用token的方式访问资源服务的整个验证流程解析的全部。如有错误之处,欢迎各位提出宝贵意见。
参考文章:
- https://blog.csdn.net/lixiang/article/details/
- http://lzhpo.com/article/170
- https://zhuanlan.zhihu.com/p/
版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/qdvuejs/17354.html