Spring Security OAuth2 入门,linux操作系统学习
- 在授权码模式下,允许为空。
可能有部分胖友是 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
其中各项含义如下:
/revoke:是Authorization Server需要提供的API地址,Client使用Post方式请求这个地址。
Content-Type: application/x-www-form-urlencoded:固定此格式。
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW:访问受保护资源的授权凭证。
token:必选,可以是access_token或者refresh_token的内容。
token_type_hint:可选,表示token的类型,值为”access_token“或者"refresh_token"。
如果撤销成功,则返回一个HTTP status code为200的响应就可以了。
7. 令牌元数据
Spring Security OAuth2 入门,linux操作系统学习相关推荐
- 芋道 Spring Security OAuth2 入门
芋道 Spring Security OAuth2 入门 总阅读量:28123次 <Dubbo 实现原理与源码解析 -- 精品合集> <Netty 实现原理与源码解析 -- 精品合集 ...
- Spring Security OAuth2 入门
1. 概述 2. 引入 Spring Security OAuth2 依赖 3. 配置资源服务器 4. 配置授权服务器 4.1 授权码模式 Spring Security Setting 4.2 密码 ...
- 芋道 spring security oauth2 入门_Spring官方宣布:新的Spring OAuth2.0授权服务器已经来了
1. 前言 记不记得之前发过一篇文章Spring 官方发起Spring Authorization Server 项目.该项目是由Spring Security主导的一个社区驱动的.独立的孵化项目.由 ...
- Spring Security OAuth2 单点登录和登出
文章目录 1. 单点登录 1.1 使用内存保存客户端和用户信息 1.1.1 认证中心 auth-server 1.1.2 子系统 service-1 1.1.3 测试 1.2 使用数据库保存客户端和用 ...
- Spring Security OAuth2 单点登录
1. 概述 在前面的文章中,我们学习了 Spring Security OAuth 的简单使用. <Spring Security OAuth2 入门> <Spring Securi ...
- Linux操作系统学习笔记【入门必备】
Linux操作系统学习笔记[入门必备] 文章目录 Linux操作系统学习笔记[入门必备] 1.Linux入门 2.Linux目录结构 3.远程登录 3.1 远程登录Linux-Xshell5 3.2 ...
- 还不了解Oauth2协议?这篇文章从入门到入土让你了解Oauth2以及Spring Security OAuth2 的使用
SpringSecurityOAuth2学习和实战 1.OAuth2概述 1.1 什么是OAuth2 OAuth(Open Authorization)是一个关于授权(authorization)的开 ...
- Spring Boot Security OAuth2 入门
1. 概述 本文,我们来入门 Spring Security OAuth2.0 的使用.通过本文,希望你对 OAuth2.0 有一次身临其境的感受. 另外,这是一篇入门的文章,所以实际场景下,需要做一 ...
- 004-云E办_学习Oathu2和Spring Security Oauth2
这里写目录标题 一.Oauth2简介 1.简介 2.分析Oauth2认证的例子,网站使用微信认证的过程: 3.Oauth2.0认证流程如下: 1.角色: 2.常用术语: 3.令牌类型 4.特点 二.授 ...
最新文章
- linux进程间通信:消息队列实现双端通信
- 基于OpenCV的实时停车地点查找
- linux screen 命令详解(后台执行linux命令)
- [YTU]_2627 (职工工资统计)
- 那些不怕失业的程序员们,都有什么技能?
- 驰骋工作流程底层的API开发接口-重要的
- Tomcat的安装配置与JavaWeb入门教程
- 对象空指针_可选和对象:空指针救星!
- 我如何向团队解释依赖注入
- C# 格式化字符串 String.Format
- 组件注册_使用_命名规则_以及Nacos中给每个服务配置访问前缀---SpringCloud Alibaba_若依微服务框架改造---工作笔记004
- vue 按钮根据状态切换_一个vue实现的标尺插件 - vue-sketch-ruler
- MongoDB多条件分组聚合查询
- 友达5寸工控液晶屏G050VTN01.1 小尺寸液晶屏
- skd怎么接入_网易七鱼怎么接入? 网易七鱼三种接入方式介绍
- uniapp获取手机号流程
- 基于UDP的可靠传输——QUIC 协议
- 火狐浏览器书签工具栏图标_在Firefox书签工具栏中浓缩书签
- DFA确定化和最小化
- 【ACM 2020 - Text Recognition in the Wild:A Survey】OCR识别综述