授权码类型介绍
授权码类型(authorization code)通过重定向的方式让资源所有者直接与授权服务器进行交互来进行授权,避免了资源所有者信息泄漏给客户端,是功能最完整、流程最严密的授权类型,但是需要客户端必须能与资源所有者的代理(通常是Web浏览器)进行交互,和可从授权服务器中接受请求(重定向给予授权码),授权流程如下:
- 客户端引导资源所有者的用户代理到授权服务器的endpoint,一般通过重定向的方式。客户端提交的信息应包含客户端标识(clientidentifier)、请求范围(requested scope)、本地状态(localstate)和用于返回授权码的重定向地址(redirection URI)
- 授权服务器认证资源所有者(通过用户代理),并确认资源所有者允许还是拒绝客户端的访问请求
- 如果资源所有者授予客户端访问权限,授权服务器通过重定向用户代理的方式回调客户端提供的重定向地址,并在重定向地址中添加授权码和客户端先前提供的任何本地状态
- 客户端携带上一步获得的授权码向授权服务器请求访问令牌。在这一步中授权码和客户端都要被授权服务器进行认证。客户端需要提交用于获取授权码的重定向地址
- 授权服务器对客户端进行身份验证,和认证授权码,确保接收到的重定向地址与第三步中用于的获取授权码的重定向地址相匹配。如果有效,返回访问令牌,可能会有刷新令牌(RefreshToken)
快速入门
Spring-Securiy 配置
由于授权码模式需要登录用户给请求access_token的客户端授权,所以auth-server需要添加Spring-Security的相关配置用于引导用户进行登录。
在原来的基础上,进行Spring-Securiy相关配置,允许用户进行表单登录:
同时需要把ResourceServerConfig中的资源服务器中的对于登出端口的处理迁移到WebSecurityConfig中,注释掉ResourceServerConfig的HttpSecurity配置:
AuthenticationProvider
由于用户表单登录的认证过程可能有所不同,为此再添加一个CustomSecurityAuthenticationProvider,基本上与CustomAuthenticationProvider一致,只是忽略对client客户端的认证和处理。
在AuthenticationManagerConfig添加CustomSecurityAuthenticationProvider配置:
保证数据库中的请求客户端存在授权码的请求授权和具备回调地址,回调地址是用来接受授权码的。
测试使用
启动服务,浏览器访问地址http://localhost:9091/oauth/au ... mp%3Bscope=all&redirect_uri=http://localhost:8080。
重定向到登录界面,引导用户登录:
登录成功,授权客户端获取授权码。
授权之后,从回调地址中获取到授权码:
携带授权码获取对应的token:
源码详解
AuthorizationServerTokenServices是授权服务器中进行token操作的接口,提供了以下的三个接口:
请注意,生成的token都是与授权的用户进行绑定的。
AuthorizationServerTokenServices接口的默认实现是DefaultTokenServices,注意token通过TokenStore进行保存管理。
生成token:
需要注意到,在创建token的过程中,会根据该授权用户去查询是否存在未过期的access_token,有就直接返回,没有的话才会重新创建新的access_token,同时也应该注意到是先创建refresh_token,再去创建access_token,这是为了防止持有过期的access_token能够通过refresh_token重新获得access_token,因为前后创建access_token绑定了同一个refresh_token。
我向你们推荐一个交流学习群:575745314 里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多,以下的课程体系图也是在群里获取。
DefaultTokenServices中刷新token的refreshAccessToken()以及获取token的getAccessToken()方法就留给读者们自己去查看,在此不介绍。
小结
本文主要讲了授权码模式,在授权码模式需要用户登录之后进行授权才获取获取授权码,再携带授权码去向TokenEndpoint请求访问令牌,当然也可以在请求中设置response_token=token通过隐式类型直接获取到access_token。这里需要注意一个问题,在到达AuthorizationEndpoint端点时,并没有对客户端进行验证,但是必须要经过用户认证的请求才能被接受。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。