文章目录
-
- 1. OAuth2介绍
- 2. OAuth2的四种授权模式
-
- ①:授权码模式
- ②:密码模式
- ③:简化(隐式)模式
- ④:客户端模式
- 3. token的携带方式
- 4. token的自动续期 refresh token
1. OAuth2介绍
OAuth2
并不是一个框架,而是一个关于授权(authorization)的开放网络标准,是一个授权协议!OAuth在全世界得到广泛应用,目前的版本是2.0版。OAuth2
的作用就是让 客户端(应用程序) 安全可控地获取"用户"的授权,与服务提供商(比如微信、微博)进行数据交互。
OAuth2的基本概念
- (1)
Third-party application
:第三方应用程序,又称"客户端"(client),即我们自己的应用,比如京东app。 - (2)
HTTP service
:HTTP服务提供商,简称"服务提供商",比如使用微信登录,那么微信就是服务提供商! - (3)
Resource Owner
:资源所有者,又称"用户"(user)。 - (4)U
ser Agent
:用户代理,比如浏览器。 - (5)
Authorization server
:授权服务器,即服务提供商专门用来处理认证授权的服务器。 - (6)
Resource server
:资源服务器,即服务提供商存放用户生成的资源的服务器。它与授权服务器,可以是同一台服务器,也可以是不同的服务器。
令牌token与密码的区别?
- 令牌token是短期的,到期会自动失效,用户自己无法修改。密码一般长期有效,用户不修改,就不会发生变化。
- 令牌token可以被数据所有者撤销,会立即失效。密码一般不允许被他人撤销。
- 令牌token有权限范围(scope)。对于网络服务来说,只读令牌就比读写令牌更安全。密码一般是完整权限。
用令牌既可以让第三方应用获得权限,同时又随时可控,不会危及系统安全,这就是OAuth 2.0
的优点。
2. OAuth2的四种授权模式
OAuth 2.0 对于如何颁发令牌的细节,规定得非常详细。具体来说,一共分成四种授权类型,即四种颁发令牌的方式,适用于不同的互联网场景。
- 授权码模式:authorization_code
- 密码模式:password
- 简化(隐式)模式:implicit
- 客户端模式:client_credentials
不管哪一种授权方式,第三方应用申请令牌之前,都必须先到系统备案,说明自己的身份,然后会拿到两个身份识别码:客户端 ID(client ID)和客户端密钥(client secret)。这是为了证明应用是可信的,防止令牌被滥用!没有备案过的第三方应用,是不会拿到令牌的。
以下几种授权模式,都是结合Spring Security OAuth2
这样一个安全框架来解释的,点击查看 Spring Security OAuth2 的配置和使用!!!!
①:授权码模式
授权码方式,指的是第三方应用先申请一个授权码,然后再用该码获取令牌。这种方式是最常用的流程,安全性也最高,它适用于那些有后端的 Web 应用。授权码通过前端传送,令牌则是储存在后端,而且所有与资源服务器的通信都在后端完成。这样的前后端分离,可以避免令牌泄漏。
授权码模式的步骤如下:
-
(1)用户 在
A
应用登录中选择微信登录,点击微信登录图标后会跳转到授权服务器B
,请求用户授权。
下面就是A
应用跳转 授权服务器B
的一个示意链接。http://localhost:8080/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://www.baidu.com&scope=all
Url参数释义如下:response_type
:表示授权类型,必选项,此处的值固定为"code",授权码模式client_id
:表示客户端的ID,必选项redirect_uri
:表示重定向URI,可选项scope
:表示申请的权限范围,可选项state
:表示客户端的当前状态,可以指定任意值,授权服务器会原封不动地返回这个值。
-
(2)上述
url
会返回一个二维码,会要求用户登录,然后询问是否同意给予A
网站授权。用户表示同意,这时授权服务器B
就会跳回redirect_uri
参数指定的网址。跳转时,会传回一个授权码code
,就像下面这样。注意:本测试是在IE浏览器上测试,chrome
浏览器可能无法返回! -
(3)
A
应用拿到授权码以后,就可以在回调地址的后端服务器中向 授权服务器B
请求token令牌(url
请求地址:http://localhost:8080/oauth/token?grant_type=authorization_code&client_id=client&client_secret=123123&redirect_uri=http://www.baidu.com&scope=all&code=taYiM4
)。 此行为在服务端发生,用户不可见,安全性好!
url请求地址各参数解释如下:client_id
=CLIENT_IDclient_secret
=CLIENT_SECRET # client_id和client_secret用来让 B 确认 A 的身份,client_secret参数是保密的,因此只能在后端发请求grant_type
=authorization_code # 采用的授权方式是授权码code
=AUTHORIZATION_CODE # 上一步拿到的授权码redirect_uri
=CALLBACK_URL # 令牌颁发后的回调网址
-
(4)此时请求携带token标识,就可正常访问其他接口
②:密码模式
密码模式也是比较常用的,在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分 或者自己微服务内部的系统。适用场景:自家公司搭建的授权服务器
-
(1)由于对
A
应用极度信任,所以A
应用就能知道账号、密码,请求时根据账号密码直接向授权服务器B
请求token。请求url:http://localhost:8080/oauth/token?username=fox&password=123456&grant_type=password&client_id=client&client_secret=123123&scope=all
注意这里的授权模式为密码模式:grant_type=password
-
(2)授权服务器
B
验证身份通过后,直接给出令牌。注意,这时不需要跳转,而是把令牌放在 JSON 数据里面,作为 HTTP 回应,A
应用因此拿到令牌。
③:简化(隐式)模式
简化(隐式)模式适用于纯前端应用,允许直接向前端颁发令牌,这种方式没有授权码这个中间步骤,所以称为(授权码)“隐藏式”(implicit
)
简化模式不通过第三方应用程序的服务器,直接在浏览器中向授权服务器申请令牌,跳过了"授权码"这个步骤,所有步骤在浏览器中完成,令牌对访问者是可见的,且客户端不需要认证。
这种方式把令牌直接传给前端,是很不安全的。因此,只能用于一些安全要求不高的场景,并且令牌的有效期必须非常短,通常就是会话期间(session)有效,浏览器关掉,令牌就失效了。
步骤如下:
-
(1)
A
应用请求授权服务器B
,返回一个授权二维码,等待用户授权。请求url:http://localhost:8080/oauth/authorize?client_id=client&response_type=token&scope=all&redirect_uri=http://www.baidu.com
url解析:response_type
=token #response_type
参数为token,表示要求直接返回令牌client_id
=CLIENT_ID # 应用idredirect_uri
=CALLBACK_URL # 重定向urlscope
=read # 只读模式
-
(2)用户点击授权,授权服务器
B
回调redirect_uri
并且把令牌作为 URL 参数,传给A
应用。注意连接符是#
//回调地址 https://a.com/callback#token=6743abeb-34db-4353-805f-5d6f71c68ca4
④:客户端模式
客户端模式(Client Credentials Grant)指客户端以自己的名义,而不是以用户的名义,向"服务提供商"进行授权。一般用来提供给我们完全信任的服务器端服务。
步骤如下:
- (1)客户端向授权服务器进行身份认证,并要求一个访问令牌 token。请求url:
http://localhost:8080/oauth/token?grant_type=client_credentials&scope=all&client_id=client&client_secret=123123
注意授权模式变更为:客户端模式grant_type=client_credentials
- (2)授权服务器验证
client_id
和client_secret
通过后,直接返回令牌。
3. token的携带方式
在拿到token
之后,就可以访问系统的资源了!只需要在请求时携带上token
即可!携带方式有两种
-
加在请求参数上:这种方式token是暴露的,不常用
-
加在请求头上,隐藏了
token
,是常用的方式。注意:这种方式需要带上token
类型
请求结果:
4. token的自动续期 refresh token
问题:为什么要有token
的刷新?
如果用户登录了网站,浏览到一半,token
过期了,这样用户还要重新再走一次授权、登录流程,在申请一个新的令牌,才能继续访问。这种体验显然是极差的,为了解决这个问题,OAuth 2.0
实现了token
的自动更新,或者说自动续期
具体方法是:授权服务器 B
颁发令牌的时候,一次性颁发两个令牌,一个用于获取token(access_token
),另一个用于刷新token(refresh token
)。token令牌到期前,使用 refresh token
发一个请求,去更新快要过期的token
,实现token
的自动续期。
刷新token的url
地址如下:http://localhost:8080/oauth/token?grant_type=refresh_token&client_id=client&client_secret=123123&refresh_token=c75dfe34-9f3c-46a3-b13d-8ffdd3785473
注意:授权类型为刷新token类型 grant_type=refresh_token
需要注意的是:
-
默认情况下,
refresh_token
只能使用一次,刷新一次后,refresh_token
失效 -
如果想要保持
refresh_token
一直有效,就是说一个refresh_token
可以刷新无数次,则需要把配置reuseRefreshTokens(true)
,保持其重复使用!@Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManagerBean) //使用密码模式需要配置 .tokenStore(tokenStore) //指定token存储到redis .reuseRefreshTokens(true) //为true,refresh_token可重复使用。默认为false .userDetailsService(userService) //刷新令牌授权包含对用户信息的检查 .allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST); //支持GET,POST请求 }