OAuth2 简化模式
4. 简化模式
简化模式,不通过第三方应用程序的服务器,直接在浏览器中向授权服务器申请令牌,跳过了“授权码”这个步骤,因此得名。所有步骤在浏览器中完成,令牌对访问者是可见的,且客户端不需要授权。
- (A)用户访问客户端,后者将前者跳转到到授权服务器。
- (B)用户选择是否给予客户端授权。
- (C)假设用户给予授权,授权服务器将用户导向客户端指定的"重定向URI",并在 URI 的 Hash 部分包含了访问令牌。
- (D)浏览器向资源服务器发出请求,其中不包括上一步收到的 Hash 值。
- (E)资源服务器返回一个网页,其中包含的代码可以获取 Hash 值中的令牌。
- (F)浏览器执行上一步获得的脚本,提取出令牌。
- (G)浏览器将令牌发给客户端。
4.1 搭建授权服务器
复制出 lab-68-demo02-authorization-server-with-implicit
项目,修改搭建授权服务器。改动点如下图所示:
@Configuration @EnableAuthorizationServer public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { /** * 用户认证 Manager */ @Autowired private AuthenticationManager authenticationManager; //配置使用的 AuthenticationManager 实现用户认证的功能 @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager); } //设置 /oauth/check_token 端点,通过认证后可访问。 //这里的认证,指的是使用 client-id + client-secret 进行的客户端认证,不要和用户认证混淆。 //其中,/oauth/check_token 端点对应 CheckTokenEndpoint 类,用于校验访问令牌的有效性。 //在客户端访问资源服务器时,会在请求中带上访问令牌。 //在资源服务器收到客户端的请求时,会使用请求中的访问令牌,找授权服务器确认该访问令牌的有效性。 @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { oauthServer.checkTokenAccess("isAuthenticated()"); } //进行 Client 客户端的配置。 //设置使用基于内存的 Client 存储器。实际情况下,最好放入数据库中,方便管理。 /* * * 创建一个 Client 配置。如果要继续添加另外的 Client 配置,可以在 <4.3> 处使用 #and() 方法继续拼接。 * 注意,这里的 .withClient("clientapp").secret("112233") 代码段,就是 client-id 和 client-secret。 *补充知识:可能会有胖友会问,为什么要创建 Client 的 client-id 和 client-secret 呢? *通过 client-id 编号和 client-secret,授权服务器可以知道调用的来源以及正确性。这样, *即使“坏人”拿到 Access Token ,但是没有 client-id 编号和 client-secret,也不能和授权服务器发生有效的交互。 */ @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() // <4.1> .withClient("clientapp").secret("112233") // <4.2> Client 账号、密码。 .authorizedGrantTypes("implicit") // <4.2> 简化模式 .redirectUris("http://127.0.0.1:9090/callback02") .scopes("read_userinfo", "read_contacts") // <4.2> 可授权的 Scope // .and().withClient() // <4.3> 可以继续配置新的 Client ; } }
仅仅需要修改 OAuth2AuthorizationServerConfig 类,设置使用 "implicit"
简化模式,并设置回调地址。
🙂 注意,这里设置的回调地址,稍后我们会在「4.2 搭建资源服务器」中实现。
4.2 搭建资源服务器
复制lab-68-demo02-resource-server
项目,主要是提供回调地址。如下图所示:
@Configuration @EnableResourceServer public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() // 设置 /login 无需权限访问 .antMatchers("/login").permitAll() //设置/callback 无需权限访问 .antMatchers("/callback").permitAll() //设置/callback 无需权限访问 .antMatchers("/callback02").permitAll() // 设置其它请求,需要认证后访问 .anyRequest().authenticated() ; } }
@RestController @RequestMapping("/") public class Callback02Controller { @GetMapping("/callback02") public String login() { return "假装这里有一个页面"; } }
① 新建 Callback02Controller 类,提供 /callback02
回调地址。代码如下:
@RestController @RequestMapping("/") public class Callback02Controller { @GetMapping("/callback02") public String login() { return "假装这里有一个页面"; } }
友情提示:考虑到暂时不想做页面,所以这里先假装一下,嘿嘿。
② 在 OAuth2ResourceServerConfig 配置类中,设置 /callback02
回调地址无需权限验证,不然回调都跳转不过来哈。
4.3 简单测试
执行 AuthorizationServerApplication 启动授权服务器。
执行 ResourceServerApplication 启动资源服务器。
① 使用浏览器,访问 http://127.0.0.1:8080/oauth/authorize?client_id=clientapp&redirect_uri=http://127.0.0.1:9090/callback02&response_type=token&scope=read_userinfo 地址,获取授权。请求参数说明如下:
client_id
参数,必传,为我们在 OAuth2AuthorizationServer 中配置的 Client 的编号。
redirect_uri
参数,可选,回调地址。当然,如果client_id
对应的 Client 未配置redirectUris
属性,会报错。
response_type
参数,必传,返回结果为token
访问令牌。
scope
参数,可选,申请授权的 Scope 。如果多个,使用逗号分隔。
state
参数,可选,表示客户端的当前状态,可以指定任意值,授权服务器会原封不动地返回这个值。
友情提示:state
参数,未在上述 URL 中体现出来。
因为我们并未登录授权服务器,所以被拦截跳转到登录界面。如下图所示:
② 输入用户的账号密码「yunai/1024」进行登录。登录完成后,进入授权界面。如下图所示:
旁白君:和我们日常使用的腾讯 QQ、微信、微博等等三方登录,是一模一样的,除了丑了点,嘿嘿~
③ 选择 scope.read_userinfo
为 Approve 允许,点击「Authorize」按钮,完成授权操作。浏览器自动重定向到 Redirection URI 地址,并且在 URI 上的 Hash 部分可以看到 access_token
访问令牌。如下图所示:
后续,可以通过编写 Javascript 脚本的代码,获取 URI 上的 Hash 部分的访问令牌。