OAuth2源码解析之 认证服务器(Authorization server) 授权, 登陆,跳转首页流程

581 阅读2分钟

问题背景

回忆Oauth2获取access_token的流程,第一步是调用 Oauth2认证服务器 获取授权码接口

如: localhost:7777/oauth/authorize?client_id=cms&response_type=code

之后这个地址会跳转到Oauth2认证服务器登陆首页,进行账号密码输入,然后进入授权页

如图:

企业微信截图_5409c453-7d30-4bea-8a2f-2f5670f96948.png

企业微信截图_9c9e030d-39a2-46c9-8368-1267a9aa544d.png

抛出问题

1 在这个过程中,调用获取授权码接口后,是如何自动跳转到 Oauth2认证服务器登陆页(http://localhost:7777/login

2 Oauth2登陆页的地址(默认:http://localhost:7777/login) 是否可以手动可配置,例如配置成(http://localhost:7777/myIndex),配置如何生效的

源码解读(一)

1 启动配置application.yml 便于我们查看调试过程

设置日志打印级别 用于调试源码
logging:
level:
 root: debug
2 浏览器访问获取授权码请求地址 localhost:7777/oauth/authorize?client_id=cms&response_type=code 开始流程
关键类 ExceptionTranslationFilter
源码查看 继承了spring mvc 的拦截器 使得请求都进入到此拦截器中

企业微信截图_9e0db6d0-6d5a-4696-82e2-414a7be3c043.png

追踪 chain.doFilter(request, response) 底层通过springmvc 框架路由到/oauth/authorize controller上

企业微信截图_dcc3e15c-519e-446e-9cde-d5bc7a20a994.png

进入到授权 controller AuthorizationEndpoint中,发现发现未携带验证参数 (也就是未登录到 Oauth2认证中心 )
内部抛出了异常 throw new InsufficientAuthenticationException(
  "User must be authenticated with Spring Security before authorization can be completed.")

企业微信截图_e90f81e6-065c-44a3-8fb6-5f74fb0f2dd9.png

 回到上一个图中,此时这个方法请求处在ExceptionTranslationFilter的chain.doFilter(request, response) 中,此时方法抛出了异常,那么异常会被捕获,我们来看看异常捕获后做了什么处理,也就是
 handleSpringSecurityException(request, response, chain, ase)
 

企业微信截图_3f93aeed-5657-4655-b19c-5d74c986b762.png

继续追踪

企业微信截图_510e6d23-3418-44b3-8d82-b9136092bb6f.png

企业微信截图_118b6c93-f6c2-4535-b038-133da86f2895.png

LoginUrlAuthenticationEntryPoint 类中 请留意这个redirectUrl参数
会发现这个redirectUrl 就是即将跳转的登陆首页地址

企业微信截图_990bcb03-a1c8-4276-ae74-26fc64932b53.png

buildRedirectUrlToLoginPage(request, response, authException)拿到登陆首页地址之后,开始准备进行页面跳转

企业微信截图_6d1b2b42-77aa-4391-9dde-d39f53630e82.png

最终 response.sendRedirect("http://localhost:7777/login");
跳转至我们的首页

企业微信截图_613c83f9-38b8-4fe9-a616-56e05b03f267.png

源码解读(二)

刚才我们发现最终跳转的首页地址是 redirectUrl参数决定的
也就是 redirectUrl = buildRedirectUrlToLoginPage(request, response, authException);
那么我们来看这里面 这个参数是哪里来的 

企业微信截图_844ba309-0acf-4036-afdc-f966ff33f7ad.png

企业微信截图_c79dae3f-9f98-4aa1-9711-c845a7458f03.png

最终发现是LoginUrlAuthenticationEntryPoint类中的loginFormUrl参数
那么这个值又是怎么设置进去的的?
为什么默认会是/login 我们不妨程序启动的时候debug看一下 启动流程

企业微信截图_4bab8892-ff86-49c6-a15c-fc1e1825f659.png

企业微信截图_d8b2b28f-2e34-4fde-9fe0-145e76325c0f.png

这一步我们发现程序启动的时候 这里设置的默认值为/login了
现在问题来了,如何改变这个默认值?将首页地址改成 /myIndex
可以如下解决
public class SecurityConfiguration extends     WebSecurityConfigurerAdapter    {
  @Override
protected void configure(HttpSecurity http) throws Exception {
    // 配置登录页并允许访问
     http.formLogin()
            .loginPage("/myIndex")
            .permitAll()
            ..........
            
   }
   }

企业微信截图_0e795d92-db42-4524-8a62-7f467d39f96f.png

我们来看这一步做了什么setLoginPage(loginPage)

企业微信截图_ba5749c7-6c91-40be-8e42-c894b08dc04f.png

这里就发现了 将默认的loginFormUrl 更新成自己设置的myIndex了

企业微信截图_5043ea59-27e2-4ba1-9c09-405e8e61e01a.png

 最终效果展示:
 

企业微信截图_e882f8ae-fd12-40ee-b37d-269e826c440d.png

Over

更多访问杨少的gitHub / 源码demo下载