3-OAuth2登录流程分析
在上一篇胖哥和大家共同体验了OAuth2登录流程,直观感受了OAuth2,本篇我们来共同分析一下OAuth2登录的流程,本次分析将严重依赖trace日志。
流程分析
①访问被拒绝
/foo/hello发起请求后会经过一系列过滤器链的过滤触发访问被拒绝,核心的日志如下:

- 进入HTTP资源安全处理过滤器
FilterSecurityInterceptor。 - 发现本次
/foo/hello请求是一个匿名请求。 - 而实际上
/foo/hello需要非匿名认证。 - 访问决策投票器
WebExpressionVoter做出了拒绝授权投票(Voted to deny authorization)。 - 在基于肯定(AffirmativeBased)的访问策略下本次请求授权失败,抛出
AccessDeniedException异常。 - 异常响应过滤器
ExceptionTranslationFilter对步骤⑤抛出的异常进行处理。
②访问拒绝处理
ExceptionTranslationFilter接收到AccessDeniedException异常后会交给handleAccessDeniedException方法处理,该方法的逻辑如图所示:

我们所涉及的逻辑只会有到步骤④,其逻辑为:

上面的逻辑会跳转到登录入口(如果有两个provider的话):
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NmnERpOg-1647437855521)(.\img\1644545563269.png)]](https://images2.imgbox.com/5a/9a/xW4LG0nk_o.png)
③发起OAuth2登录请求
我们点击gitee选项会向我们的后端服务器发起/oauth2/authorization/gitee请求:
GET /oauth2/authorization/gitee HTTP/1.1
Host: localhost:8082
对应的日志为:

从日志上看请求被OAuth2AuthorizationRequestRedirectFilter拦截,重定向到了Gitee授权服务器登录页面。
重定向的请求为:
GET /oauth/authorize?response_type=code&client_id=40f6a4018837&scope=user_info&state=j_y78k1M4A&redirect_uri=http://localhost:8082/login/oauth2/code/gitee HTTP/1.1
Host: gitee.com
涉及的参数有:response_type、client_id、scope、state、redirect_uri,我们先不管这些参数是干嘛的,有个印象就好。
另外这个请求端点正好是配置中的authorization-uri配置项:
spring:
security:
oauth2:
client:
provider:
gitee:
authorization-uri: https://gitee.com/oauth/authorize
OAuth2AuthorizationRequestRedirectFilter的作用就很清晰了:
- 拦截
/oauth2/authorization/{registrationId},这里registrationId=gitee。 - 组装
registrationId对应provider的authorization-uri并发起重定向。
关于
OAuth2AuthorizationRequestRedirectFilter的细节会在后面进行专门分析。
④用户授权
跳转到Gitee登录页面之后,后面的流程可以从浏览器记录中分析出来。

- ① 点击login页面的gitee按钮,客户端服务器
302重定向到授权服务器发起授权请求。 - ② 授权服务器同意授权后,又
302重定向到了配置中的redirect_uri并附带一个code和state参数。 - ③
redirect_uri发起了请求。
安全起见,
redirect_uri应当在授权服务器对应的客户端信息中注册,否则将被视为非法URI。
redirect_uri请求我简化成HTTP脚本以方便加深印象:
GET /login/oauth2/code/gitee?code=a6e4cac6a7e&state=cR4FABTHbHj4ILZ HTTP/1.1
Host: localhost:8082
Referer: https://gitee.com/login
以下是授权服务器(gitee)302重定向/login/oauth2/code/gitee后的日志:

大致步骤为:
redirect_uri请求被过滤器OAuth2LoginAuthenticationFilter拦截处理。- 向gitee发出
/oauth/token请求,该端点对应配置文件中的token-uri。 /oauth/token请求的响应被封装为OAuth2AccessTokenResponse对象实例。- 向gitee发出
/v5/user请求,该端点对应配置文件中的user-info-uri。 /v5/user请求的响应被封装为Map<String,Object>。- 根据某些策略对Session会话进行了处理(先了解即可)
- 将
OAuth2AuthenticationToken存储到SecurityContextHolder中。 - 最后重定向到
/foo/hello。
须知
这个流程并不是标准的OAuth2流程,OAuth2中并不涉及用户登录认证,该登录认证是建立在信任Gitee用户的基础上做的认证,这一点要明白。
关于授权码的详细规范请参阅4.1 Authorization Code Grant,如果遇到疑难杂症,请联系我。