• 在授权码模式下,允许为空

可能有部分胖友是 Windows 电脑,可以参考 《windows(64位)下使用 curl 命令》 来安装一个 curl 命令。

当然,如果胖友使用 Postman ,可以参看如下两图:

  • 图 1

  • 图 2

⑥ 调用资源服务器的 API

curl -X GET http://localhost:8080/api/example/hello -H “authorization: Bearer e60e41f2-2ad0-4c79-97d5-49af38e5c2e8”

  • authorization: Bearer e60e41f2-2ad0-4c79-97d5-49af38e5c2e8 处,填写指定的访问令牌类型和访问令牌。例如此处分别为,“Bearer”、“e60e41f2-2ad0-4c79-97d5-49af38e5c2e8” 。

如果胖友使用 Postman ,可以参看如下图:

4.2 密码模式

Maven 项目结构如下:

Maven 项目结构

对应 GitHub 地址:

https://github.com/YunaiV/SpringBoot-Labs/tree/f8d701cbd9b2a4f2cee3a7f2186148bcdf859895/lab-02/resource-owner-password-credentials-server

① 配置授权服务器

// 授权服务器配置

@Configuration

@EnableAuthorizationServer

public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter {

// 用户认证

@Autowired

private AuthenticationManager authenticationManager;

@Override

public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

endpoints.authenticationManager(authenticationManager);

}

@Override

public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

clients.inMemory()

.withClient(“clientapp”).secret(“112233”) // Client 账号、密码。

.authorizedGrantTypes(“password”) // 密码模式

.scopes(“read_userinfo”, “read_contacts”) // 可授权的 Scope

// .and().withClient() // 可以继续配置新的 Client

;

}

}

  • 配置 Client 的方式,和【授权码模式】基本一致。差别在于:

  • 无需配置 `redirectUris` 属性,因为不需要回调地址。

  • 配置授权模式为【密码模式】。

  • 另外,需要引入 AuthenticationManager 来支持【密码模式】,否则会报 “Resolved [error=“unsupported_grant_type”, error_description=“Unsupported grant type: password”]” 异常。

② 配置登陆账号

和【授权码模式】一致

③ 启动项目

和【授权码模式】一致

④ 获取访问令牌

curl -X POST --user clientapp:112233 http://localhost:8080/oauth/token -H “accept: application/json” -H “content-type: application/x-www-form-urlencoded” -d “grant_type=password&username=yunai&password=1024&scope=read_userinfo”

  • 和【授权码模式】差异比较大。

  • 直接请求 oauth/token 接口,获得访问令牌。

  • 请求参数带上了 username 和 password ,就用户的登陆账号和密码。

  • 请求参数 grant_type 为 password ,表示【密码模式】。

返回结果示例如下:

{

“access_token”: “68de6eb9-5672-4e47-a3e6-110404285ba9”,

“token_type”: “bearer”,

“expires_in”: 43199,

“scope”: “read_userinfo”

}

  • 和【授权码模式】一致。

⑤ 调用资源服务器的 API

和【授权码模式】一致

4.3 简化模式

Maven 项目结构如下:

Maven 项目结构

对应 GitHub 地址:

https://github.com/YunaiV/SpringBoot-Labs/tree/f8d701cbd9b2a4f2cee3a7f2186148bcdf859895/lab-02/implicit-server

① 配置授权服务器

// 授权服务器配置

@Configuration

@EnableAuthorizationServer

public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter {

@Override

public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

clients.inMemory()

.withClient(“clientapp”).secret(“112233”) // Client 账号、密码。

.redirectUris(“http://localhost:9001/callback”) // 配置回调地址,选填。

.authorizedGrantTypes(“implicit”) // 授权码模式

.scopes(“read_userinfo”, “read_contacts”) // 可授权的 Scope

// .and().withClient() // 可以继续配置新的 Client

;

}

}

  • 和【授权码模式】基本一致。差别仅仅在于:配置授权模式为【简化模式】。

FROM 《理解 OAuth 2.0》

简化模式(implicit grant type)不通过第三方应用程序的服务器,直接在浏览器中向认证服务器申请令牌,跳过了"授权码"这个步骤,因此得名。所有步骤在浏览器中完成,令牌对访问者是可见的,且客户端不需要认证。

② 配置登陆账号

和【授权码模式】一致。

③ 启动项目

和【授权码模式】一致。

④ 获取授权码

4.1 浏览器打开

http://localhost:8080/oauth/authorize?client_id=clientapp&redirect_uri=http://localhost:9001/callback&response_type=implicit&scope=read_userinfo

  • 和【授权码模式】基本一致。差别仅仅在于:请求参数 response_type 为 “implicit” 简化模式。

4.2 浏览器打开后,效果如下:

浏览器

  • 和【授权码模式】基本一致,输入在 「② 配置登陆账号」 中配置的登陆账号 “yunai” / “1024” 。

4.3 登陆成功,直接授权完成,回调 redirect_uri 地址。如下图所示:

浏览器

  • 和【授权码模式】基本不一致的有两点

  • 登陆成功后,无需选择允许所有申请的 Scope ,直接授权完成。

  • 返回的不是授权码,而是访问令牌

总的来说,【简化模式】是【授权码模式】的简化模式。

⑤ 调用资源服务器的 API

和【授权码模式】一致。

4.4 客户端模式

Maven 项目结构如下:

Maven 项目结构

对应

【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】浏览器打开:qq.cn.hn/FTf 免费领取

GitHub 地址:

https://github.com/YunaiV/SpringBoot-Labs/tree/f8d701cbd9b2a4f2cee3a7f2186148bcdf859895/lab-02/client-credentials-server

① 配置授权服务器

和【密码模式】一致。

② 配置登陆账号

无需配置登陆账号。因为它没有用户的概念,直接与授权服务器交互,通过 Client 的编号( client_id )和密码( client_secret )来保证安全性。

③ 启动项目

和【密码模式】一致。

④ 获取访问令牌

curl -X POST “http://localhost:8080/oauth/token” --user clientapp:112233 -d “grant_type=client_credentials&scope=read_contacts”

  • 和【密码模式】基本一致,差别如下:

  • 请求参数无需带上了 `username` 和 `password` 。

  • 请求参数 `grant_type` 为 `client_credentials` ,表示【密码模式】。

返回结果示例如下:

{

“access_token”:“cb2bdfd8-18fa-4b8f-b525-10587bd672e8”,

“token_type”:“bearer”,

“expires_in”:43199,

“scope”:“read_contacts”

}

  • 和【密码模式】一致。

⑤ 调用资源服务器的 API

和【密码模式】一致

总的来说,【客户端模式】是【密码模式】的简化模式。

4.5 如何选择?

可能很多胖友,有跟笔者一样的困惑。下面笔者引用杨波老师的一张图,相信能解决我们的困扰。如下图所示:

FROM 《深度剖析 OAuth2 和微服务安全架构》

授权类型选择

当然,对于黄框部分,对于笔者还是比较困惑的。笔者认为,第三方的单页应用 SPA ,也是适合采用 Authorization Code Grant 授权模式的。例如,《微信网页授权》 :

具体而言,网页授权流程分为四步:

1、引导用户进入授权页面同意授权,获取code

2、通过code换取网页授权access_token(与基础支持中的access_token不同)

3、如果需要,开发者可以刷新网页授权access_token,避免过期

4、通过网页授权access_token和openid获取用户基本信息(支持UnionID机制)

所以,笔者猜测,之所以图中画的是 Implicit Grant 的原因是,受 Google 的 《OAuth 2.0 for Client-side Web Applications》 一文中,推荐使用了 Implicit Grant 。

当然,具体使用 Implicit Grant 还是 Authorization Code Grant 授权模式,没有定论。笔者,偏向于使用 Authorization Code Grant,对于第三方客户端的场景。

4.6 为什么有 Client 编号和密码

我们看到上述四种授权模式,无论是哪一种,最终调用授权服务器时,都会传递 Client 编号和密码,这是为什么呢?通过 Client 编号和密码,授权服务器可以知道调用的来源以及正确性。这样,即使“坏人”拿到 Access Token ,但是没有 Client 编号和密码,也不能和授权服务器发生有效的交互。

5. 刷新令牌

============

在 「4. 配置授权服务器」 中,我们一直没有看到我们期盼的刷新令牌( refresh token )的身影。这是为什么呢?因为我们在配置 Spring Security OAuth2 并未配置,获取访问令牌的同时,获取刷新令牌。

那么,怎么配置开启获取刷新令牌的功能呢?我们来看看 「5.1 获取刷新令牌」 。

5.1 获取刷新令牌

因为【密码模式】相对简单,我们直接在原有程序上做改造。对应 GitHub 地址:

https://github.com/YunaiV/SpringBoot-Labs/tree/master/lab-02/authorization-code-server-with-refresh-token 。

在步骤上,如果和原有【密码模式】保持一致的地方,下文会进行省略,并标注“和原有一致”。

① 配置授权服务器

// 授权服务器配置

@Configuration

@EnableAuthorizationServer

public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter {

// 用户认证

@Autowired

private AuthenticationManager authenticationManager;

@Override

public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

endpoints.authenticationManager(authenticationManager);

}

@Override

public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

clients.inMemory()

.withClient(“clientapp”).secret(“112233”) // Client 账号、密码。

.authorizedGrantTypes(“password”, “refresh_token”) // 密码模式 // <1>

.scopes(“read_userinfo”, “read_contacts”) // 可授权的 Scope

// .and().withClient() // 可以继续配置新的 Client

;

}

}

  • 在 <1> 处,我们很神奇的多配置了一个 “refresh_token” ,用于开启获取刷新令牌的功能。但是但是但是,OAuth2 的授权模式说好的是四种的么,怎么又出现了 “refresh_token” 这种授权模式?淡定,在 Spring Security OAtuh2 中,“refresh_token” 作为一种特殊的授权模式配置,用于开启获取刷新令牌的功能。所以,其它授权模式如果开启获取刷新令牌的功能,需要在 #authorizedGrantTypes(…) 设置时,多传入 “refresh_token” 方法参数。

② 配置登陆账号

和原有一致

③ 启动项目

和原有一致

④ 获取访问令牌

curl -X POST --user clientapp:112233 http://localhost:8080/oauth/token -H “accept: application/json” -H “content-type: application/x-www-form-urlencoded” -d “grant_type=password&username=yunai&password=1024&scope=read_userinfo”

  • 和原有一致

返回结果示例如下:

{

“access_token”:“092a2286-04e7-4e7d-8c20-19fbe25865ff”,

“token_type”:“bearer”,

“refresh_token”:“afeeb083-997f-4ea8-9334-aab6c1696cca”,

“expires_in”:43199,

“scope”:“read_userinfo”

}

  • 在原有的基础上,返回了 “refresh_token” 刷新令牌。美滋滋。

⑤ 调用资源服务器的 API

和原有一致

5.2 “刷新”访问令牌

因为访问访问令牌会自动过期,通过使用刷新令牌,可以获得新的访问令牌。注意,访问令牌获取到的是新的,不是老的哈。这也是为什么,在标题上,笔者对刷新加了双引号。

curl -i -X POST -u ‘clientapp:112233’ http://localhost:8080/oauth/token -H “accept: application/json” -d ‘grant_type=refresh_token&refresh_token=afeeb083-997f-4ea8-9334-aab6c1696cca’

  • 调用接口还是 “oauth/token” ,差别在于传入的请求参数 grant_type 为 “refresh_token”,使用刷新令牌。

  • 请求参数 refresh_token 为上面获取到的刷新令牌 “afeeb083-997f-4ea8-9334-aab6c1696cca” 。

返回结果示例如下:

{

“access_token”:“507eb761-4b25-4159-b927-ef3eff5e7eff”,

“token_type”:“bearer”,

“refresh_token”:“afeeb083-997f-4ea8-9334-aab6c1696cca”,

“expires_in”:43199,

“scope”:“read_userinfo”

}

  • 获得的访问令牌为 “507eb761-4b25-4159-b927-ef3eff5e7eff” ,是新的。并且,过期时间也变成新的

笔者在看 OAuth2.0 的刷新令牌时,一直有个疑惑:刷新令牌是否有过期时间?答案是,。但是,笔者不太确定,在 Spring Security OAuth2 中,如果不设置刷新令牌的过期时间,刷新时间是否无限长?当然,这个貌似也并不重要。因为,在实际使用中,我们肯定是需要显示( 主动 )设置刷新令牌的过期时间,使用 ClientBuilder#

refreshTokenValiditySeconds(int refreshTokenValiditySeconds) 方法,示例如下:

@Override

public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

clients.inMemory()

.withClient(“clientapp”).secret(“112233”) // Client 账号、密码。

.authorizedGrantTypes(“password”, “refresh_token”) // 密码模式

.scopes(“read_userinfo”, “read_contacts”) // 可授权的 Scope

.refreshTokenValiditySeconds(1200) // 1200 秒过期

// .and().withClient() // 可以继续配置新的 Client

;

}

刷新令牌过期时,返回结果示例如下:

{

“error”:“invalid_token”,

“error_description”:“Invalid refresh token (expired): 7139d075-c4ea-48f0-9dbb-6f65fa6dbeb0”

}

  • 如果胖友要测试这个效果,可以把刷新令牌过期时间设置为 1 秒。

5.3 为什么需要有刷新令牌

出于安全性的考虑,访问令牌的过期时间比较短,刷新令牌的过期时间比较长。这样,如果访问令牌即使被盗用走,那么在一定的时间后,访问令牌也能在较短的时间吼过期。当然,安全也是相对的,如果使用刷新令牌后,获取到新的访问令牌,访问令牌后续可能被盗用。

另外,刷新令牌是可选项,不一定会返回。

笔者整理了下,大家常用开放平台的令牌过期时间,让大家更好的理解:

  • 小米开放平台

  • 《Access Token 生命周期》

  • Access Token :90 天有效期

  • Refresh Token :10 年有效期

  • 微信开放平台

  • 《网站应用微信登录开发指南》

  • Access Token :2 小时有效期

  • Refresh Token :未知有效期

  • 腾讯开放平台

  • 《获取 Access_Token》

  • Access Token :90 天有效期

  • Refresh Token :未知有效期

6. 删除令牌

============

实际在 OAuth2 时,有删除访问令牌和刷新令牌的需求。例如:用户登出系统。虽然说,可以通过客户端本地删除令牌的方式实现。但是,考虑到真正的彻底的实现删除令牌,必然服务端自身需要删除令牌。

在 Spring Security OAuth2 中,并没有提供内置的接口,所以需要自己去实现。笔者参看 《Spring Security OAuth2 – Simple Token Revocation》 文档,实现删除令牌的 API 接口。

因为【密码模式】相对简单,我们直接在原有程序上做改造。对应 GitHub 地址: 。注意,如下仅仅是 Demo ,实际生产环境下需要做改造。

6.1 删除访问令牌

① 新增删除访问令牌的 API 接口

@Autowired

private ConsumerTokenServices tokenServices;

@RequestMapping(method = RequestMethod.POST, value = “api/access_token/revoke”)

public String revokeToken(@RequestParam(“token”) String token) {

tokenServices.revokeToken(token);

return token;

}

  • 使用 ConsumerTokenServices#revokeToken(String tokenValue) 方法,删除访问令牌。

注意,实际生产环境下,授权服务器和资源服务器是不在一起的,所以此处仅仅是示例。主要是为了介绍 ConsumerTokenServices#revokeToken(String tokenValue) 方法的使用。

② 访问删除访问令牌的 API 接口。

curl -X POST http://localhost:8080/api/access_token/revoke -H “authorization: Bearer 23874e0b-a1d8-4337-9551-7b9be1ebaebe” -d “token=23874e0b-a1d8-4337-9551-7b9be1ebaebe”

移除成功后,在使用当前访问令牌,就会报如下错误:

{

“error”:“invalid_token”,

“error_description”:“Invalid access token: 23874e0b-a1d8-4337-9551-7b9be1ebaebe”

}


另外,也可以参考

https://github.com/geektime-geekbang/oauth2lab/blob/master/lab05/oauth-server/src/main/java/io/spring2go/config/RevokeTokenEndpoint.java 的实现。

6.2 删除刷新令牌

① 新增删除访问令牌的 API 接口

@Autowired(required = false) // <1>

private TokenStore tokenStore;

@RequestMapping(method = RequestMethod.POST, value = “api/refresh_token/revoke”)

public String revokeRefreshToken(@RequestParam(“token”) String token) {

tokenStore.removeRefreshToken(new DefaultOAuth2RefreshToken(token));

return token;

}

  • <1> 处,使用了 required = false 的原因是,本示例并未显示声明 TokenStore Bean 对象交给 Spring 管理,所以无法注入。 所以 「6.2 删除刷新令牌」 是一个无法跑通的示例。

  • 重点在于,调用 TokenStore#removeRefreshToken(OAuth2RefreshToken token) 方法,删除刷新令牌。

② 访问删除刷新令牌的 API 接口。

curl -X POST http://localhost:8080/api/refresh_token/revoke -H “authorization: Bearer 52e85411-ac1d-4844-bf03-cf5633e4eecd” -d “token=ead4734a-ca5c-45bf-ac25-9a92291a9fe1”

移除成功后,在使用当前刷新令牌,就会报如下错误:

{

“error”:“invalid_token”,

“error_description”:“Invalid refresh token: ead4734a-ca5c-45bf-ac25-9a92291a9fe1”

}


另外,也可以参考

https://github.com/geektime-geekbang/oauth2lab/blob/master/lab05/oauth-server/src/main/java/io/spring2go/config/TokenController.java 的实现。

6.3 RFC7009 - OAuth2 Token Revocation

在 OAuth2 中,删除令牌,标准的说法为 OAuth2 Token 撤销,对应 RFC7009 。感兴趣的胖友,可以看看。

FROM 《OAuth2 Token 撤销(RFC7009 - OAuth2 Token Revocation)》

简单来说,这个协议规定了一个Authorization server提供一个怎样的API来供Client撤销access_token或者refresh_token。

比如Client发起一个如下的请求:

POST /revoke HTTP/1.1

Host: server.example.com

Content-Type: application/x-www-form-urlencoded

Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW

token=45ghiukldjahdnhzdauz&token_type_hint=refresh_token

其中各项含义如下:

  1. /revoke:是Authorization Server需要提供的API地址,Client使用Post方式请求这个地址。

  2. Content-Type: application/x-www-form-urlencoded:固定此格式。

  3. Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW:访问受保护资源的授权凭证。

  4. token:必选,可以是access_token或者refresh_token的内容。

  5. token_type_hint:可选,表示token的类型,值为”access_token“或者"refresh_token"。

如果撤销成功,则返回一个HTTP status code为200的响应就可以了。

7. 令牌元数据

Spring Security OAuth2 入门,linux操作系统学习相关推荐

  1. 芋道 Spring Security OAuth2 入门

    芋道 Spring Security OAuth2 入门 总阅读量:28123次 <Dubbo 实现原理与源码解析 -- 精品合集> <Netty 实现原理与源码解析 -- 精品合集 ...

  2. Spring Security OAuth2 入门

    1. 概述 2. 引入 Spring Security OAuth2 依赖 3. 配置资源服务器 4. 配置授权服务器 4.1 授权码模式 Spring Security Setting 4.2 密码 ...

  3. 芋道 spring security oauth2 入门_Spring官方宣布:新的Spring OAuth2.0授权服务器已经来了

    1. 前言 记不记得之前发过一篇文章Spring 官方发起Spring Authorization Server 项目.该项目是由Spring Security主导的一个社区驱动的.独立的孵化项目.由 ...

  4. Spring Security OAuth2 单点登录和登出

    文章目录 1. 单点登录 1.1 使用内存保存客户端和用户信息 1.1.1 认证中心 auth-server 1.1.2 子系统 service-1 1.1.3 测试 1.2 使用数据库保存客户端和用 ...

  5. Spring Security OAuth2 单点登录

    1. 概述 在前面的文章中,我们学习了 Spring Security OAuth 的简单使用. <Spring Security OAuth2 入门> <Spring Securi ...

  6. Linux操作系统学习笔记【入门必备】

    Linux操作系统学习笔记[入门必备] 文章目录 Linux操作系统学习笔记[入门必备] 1.Linux入门 2.Linux目录结构 3.远程登录 3.1 远程登录Linux-Xshell5 3.2 ...

  7. 还不了解Oauth2协议?这篇文章从入门到入土让你了解Oauth2以及Spring Security OAuth2 的使用

    SpringSecurityOAuth2学习和实战 1.OAuth2概述 1.1 什么是OAuth2 OAuth(Open Authorization)是一个关于授权(authorization)的开 ...

  8. Spring Boot Security OAuth2 入门

    1. 概述 本文,我们来入门 Spring Security OAuth2.0 的使用.通过本文,希望你对 OAuth2.0 有一次身临其境的感受. 另外,这是一篇入门的文章,所以实际场景下,需要做一 ...

  9. 004-云E办_学习Oathu2和Spring Security Oauth2

    这里写目录标题 一.Oauth2简介 1.简介 2.分析Oauth2认证的例子,网站使用微信认证的过程: 3.Oauth2.0认证流程如下: 1.角色: 2.常用术语: 3.令牌类型 4.特点 二.授 ...

最新文章

  1. linux进程间通信:消息队列实现双端通信
  2. 基于OpenCV的实时停车地点查找
  3. linux screen 命令详解(后台执行linux命令)
  4. [YTU]_2627 (职工工资统计)
  5. 那些不怕失业的程序员们,都有什么技能?
  6. 驰骋工作流程底层的API开发接口-重要的
  7. Tomcat的安装配置与JavaWeb入门教程
  8. 对象空指针_可选和对象:空指针救星!
  9. 我如何向团队解释依赖注入
  10. C# 格式化字符串 String.Format
  11. 组件注册_使用_命名规则_以及Nacos中给每个服务配置访问前缀---SpringCloud Alibaba_若依微服务框架改造---工作笔记004
  12. vue 按钮根据状态切换_一个vue实现的标尺插件 - vue-sketch-ruler
  13. MongoDB多条件分组聚合查询
  14. 友达5寸工控液晶屏G050VTN01.1 小尺寸液晶屏
  15. skd怎么接入_网易七鱼怎么接入? 网易七鱼三种接入方式介绍
  16. uniapp获取手机号流程
  17. 基于UDP的可靠传输——QUIC 协议
  18. 火狐浏览器书签工具栏图标_在Firefox书签工具栏中浓缩书签
  19. DFA确定化和最小化
  20. 【ACM 2020 - Text Recognition in the Wild:A Survey】OCR识别综述

热门文章

  1. 宝马刷隐藏编程设码E-Sys分享,psdzdata数据分享
  2. ES多种搜索方式总结
  3. 让颜色更加饱满和有冲击力:图像颜色校正
  4. 【日常】超简单的windows 10键位映射 key remap
  5. HTTP 中为什么会有 OPTIONS 请求?
  6. argparse用法总结
  7. 分布式一致性协议之Raft
  8. 哪个蓝牙耳机性价比最高、蓝牙耳机性价比高的品牌
  9. 新品评测:2021年iPad Pro与2020年、2018年iPad Pro对比
  10. 吴昊品游戏核心算法 Round 16 —— 吴昊教你玩口袋妖怪 第十弹 超能力系道馆