OAuth2介绍与使用

余生长醉 提交于 2020-03-06 00:24:42

1.什么是OAuth2

OAuth(开放授权)是一个开放标准,允许用户授权第三方移动应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容,OAuth2.0是OAuth协议的延续版本,但不向后兼容OAuth 1.0即完全废止了OAuth1.0。

2.应用场景

第三方应用授权登录:在APP或者网页接入一些第三方应用时,时长会需要用户登录另一个合作平台,比如QQ,微博,微信的授权登录。

原生app授权:app登录请求后台接口,为了安全认证,所有请求都带token信息,如果登录验证、请求后台数据。

前后端分离单页面应用(spa):前后端分离框架,前端请求后台数据,需要进行oauth2安全认证,比如使用vue、react后者h5开发的app。

3.名词定义

(1) Third-party application:第三方应用程序,本文中又称"客户端"(client),比如打开知乎,使用第三方登录,选择qq登录,这时候知乎就是客户端。

(2)HTTP service:HTTP服务提供商,本文中简称"服务提供商",即上例的qq。

(3)Resource Owner:资源所有者,本文中又称"用户"(user),即登录用户。

(4)User Agent:用户代理,本文中就是指浏览器。

(5)Authorization server:认证服务器,即服务提供商专门用来处理认证的服务器。

(6)Resource server:资源服务器,即服务提供商存放用户生成的资源的服务器。它与认证服务器,可以是同一台服务器,也可以是不同的服务器。

4.运行流程

(A)用户打开客户端以后,客户端要求用户给予授权。

(B)用户同意给予客户端授权。

(C)客户端使用上一步获得的授权,向认证服务器申请令牌。

(D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。

(E)客户端使用令牌,向资源服务器申请获取资源。

(F)资源服务器确认令牌无误,同意向客户端开放资源。

5.四种授权模式

授权码模式(authorization code)

简化模式(implicit)

密码模式(resource owner password credentials)

客户端模式(client credentials)

6.授权码模式

授权码模式(authorization code)是功能最完整、流程最严密的授权模式。

流程
说明:【A服务客户端】需要用到【B服务资源服务】中的资源
第一步:【A服务客户端】将用户自动导航到【B服务认证服务】,这一步用户需要提供一个回调地址,以备
B服务认证服务】返回授权码使用。
第二步:用户点击授权按钮表示让【A服务客户端】使用【B服务资源服务】,这一步需要用户登录B服务,也
就是说用户要事先具有B服务的使用权限。
第三步:【B服务认证服务】生成授权码,授权码将通过第一步提供的回调地址,返回给【A服务客户端】。
注意这个授权码并非通行【B服务资源服务】的通行凭证。
第四步:【A服务认证服务】携带上一步得到的授权码向【B服务认证服务】发送请求,获取通行凭证token
第五步:【B服务认证服务】给【A服务认证服务】返回令牌token和更新令牌refresh token
使用场景
授权码模式是OAuth2中最安全最完善的一种模式,应用场景最广泛,可以实现服务之间的调用,常见的微
信,QQ等第三方登录也可采用这种方式实现

7.简化模式Implicit

说明:简化模式中没有【A服务认证服务】这一部分,全部有【A服务客户端】与B服务交互,整个过程不再有
授权码,token直接暴露在浏览器。
第一步:【A服务客户端】将用户自动导航到【B服务认证服务】,这一步用户需要提供一个回调地址,以备
B服务认证服务】返回token使用,还会携带一个【A服务客户端】的状态标识state
第二步:用户点击授权按钮表示让【A服务客户端】使用【B服务资源服务】,这一步需要用户登录B服务,也
就是说用户要事先具有B服务的使用权限。

第三步:【B服务认证服务】生成通行令牌tokentoken将通过第一步提供的回调地址,返回给【A服务客户端】。
使用场景
适用于A服务没有服务器的情况。比如:纯手机小程序,JavaScript语言实现的网页插件等

8.用户名密码 Resource Owner Credentials

流程
第一步:直接告诉【A服务客户端】自己的【B服务认证服务】的用户名和密码
第二步:【A服务客户端】携带【B服务认证服务】的用户名和密码向【B服务认证服务】发起请求获取
token
第三步:【B服务认证服务】给【A服务客户端】颁发token
使用场景
此种模式虽然简单,但是用户将B服务的用户名和密码暴露给了A服务,需要两个服务信任度非常高才能使用 

9.客户端凭证 Client Credentials

流程
说明:这种模式其实已经不太属于OAuth2的范畴了。A服务完全脱离用户,以自己的身份去向B服务索取
token。换言之,用户无需具备B服务的使用权也可以。完全是A服务与B服务内部的交互,与用户无关了。
第一步:A服务向B服务索取token
第二步:B服务返回tokenA服务。
使用场景
A服务本身需要B服务资源,与用户无关。

 
OAuth2.0中表结构说明
官方SQL地址:
https://github.com/spring-projects/spring-security-oauth/blob/master/spring-securityoauth2/src/test/resources/schema.sql
 
字段名 字段说明
client_id 主键,必须唯一,不能为空. 用于唯一标识每一个客户端(client); 在注册时必须填写(也可由服务
端自动生成). 对于不同的grant_type,该字段都是必须的. 在实际应用中的另一个名称叫
appKey,client_id是同一个概念.
resource_ids 客户端所能访问的资源id集合,多个资源时用逗号(,)分隔,: “unity-resource,mobile
resource”. 该字段的值必须来源于与security.xml中标签‹oauth2:resource-server的属性
resource-id值一致. security.xml配置有几个‹oauth2:resource-server标签, 则该字段可以
使用几个该值. 在实际应用中, 我们一般将资源进行分类,并分别配置对应
‹oauth2:resource-server,如订单资源配置一个‹oauth2:resource-server, 用户资源又配置
一个‹oauth2:resource-server. 当注册客户端时,根据实际需要可选择资源id,也可根据不同的
注册流程,赋予对应的资源id.
client_secret 用于指定客户端(client)的访问密匙; 在注册时必须填写(也可由服务端自动生成). 对于不同的
grant_type,该字段都是必须的. 在实际应用中的另一个名称叫appSecret,client_secret
同一个概念.
scope 指定客户端申请的权限范围,可选值包括read,write,trust;若有多个权限范围用逗号(,)分隔,:
“read,write”. scope的值与security.xml中配置的‹intercept-urlaccess属性有关系.
‹intercept-url的配置为‹intercept-url pattern="/m/**"
access=“ROLE_MOBILE,SCOPE_READ”/>则说明访问该URL时的客户端必须有read权限范
. write的配置值为SCOPE_WRITE, trust的配置值为SCOPE_TRUST. 在实际应该中, 该值一
般由服务端指定, 常用的值为read,write.
authorized_grant_types 指定客户端支持的grant_type,可选值包括
authorization_code,password,refresh_token,implicit,client_credentials, 若支持多个
grant_type用逗号(,)分隔,: “authorization_code,password”. 在实际应用中,当注册时,该字
段是一般由服务器端指定的,而不是由申请者去选择的,最常用的grant_type组合有:
“authorization_code,refresh_token”(针对通过浏览器访问的客户端);
“password,refresh_token”(针对移动设备的客户端). implicitclient_credentials在实际中
很少使用.
web_server_redirect_uri 客户端的重定向URI,可为空, grant_typeauthorization_codeimplicit, Oauth的流
程中会使用并检查与注册时填写的redirect_uri是否一致. 下面分别说明:
grant_type=authorization_code, 第一步 从 spring-oauth-server获取 'code’时客户端发
起请求时必须有redirect_uri参数, 该参数的值必须与 web_server_redirect_uri的值一致.
二步 用 ‘code’ 换取 ‘access_token’ 时客户也必须传递相同的redirect_uri. 在实际应用中,
web_server_redirect_uri在注册时是必须填写的, 一般用来处理服务器返回的code, 验证
state是否合法与通过code去换取access_token.spring-oauth-client项目中, 可具体参考
AuthorizationCodeController.java中的authorizationCodeCallback方法.
grant_type=implicit时通过redirect_urihash值来传递access_token.
:http://localhost:7777/spring-oauth-client/implicit#access_token=dc891f4a-ac88-
4ba6-8224-a2497e013865&token_type=bearer&expires_in=43199然后客户端通过JS等从
hash值中取到access_token.
authorities 指定客户端所拥有的Spring Security的权限值,可选, 若有多个权限值,用逗号(,)分隔, :
"ROLE_
字段名 字段说明
access_token_validity 设定客户端的access_token的有效时间值(单位:),可选, 若不设定值则使用默认的有效时间
(60 * 60 * 12, 12小时). 在服务端获取的access_token JSON数据中的expires_in字段的值
即为当前access_token的有效时间值. 在项目中, 可具体参考DefaultTokenServices.java中属
accessTokenValiditySeconds. 在实际应用中, 该值一般是由服务端处理的, 不需要客户端
自定义.refresh_token_validity 设定客户端的refresh_token的有效时间值(单位:),可选,
若不设定值则使用默认的有效时间值(60 * 60 * 24 * 30, 30). 若客户端的grant_type不包
refresh_token,则不用关心该字段 在项目中, 可具体参考DefaultTokenServices.java中属
refreshTokenValiditySeconds. 在实际应用中, 该值一般是由服务端处理的, 不需要客户端
自定义.
additional_information 这是一个预留的字段,Oauth的流程中没有实际的使用,可选,但若设置值,必须是JSON格式的
数据,:{“country”:“CN”,“country_code”:“086”}按照spring-security-oauth项目中对该字段
的描述 Additional information for this client, not need by the vanilla OAuth protocol
but might be useful, for example,for storing descriptive information. (详见
ClientDetails.javagetAdditionalInformation()方法的注释)在实际应用中, 可以用该字段来
存储关于客户端的一些其他信息,如客户端的国家,地区,注册时的IP地址等等.create_time
数据的创建时间,精确到秒,由数据库在插入数据时取当前系统时间自动生成(扩展字段)
archived 用于标识客户端是否已存档(即实现逻辑删除),默认值为’0’(即未存档). 对该字段的具体使用请
参考CustomJdbcClientDetailsService.java,在该类中,扩展了在查询client_detailsSQL加上
archived = 0条件 (扩展字段)
trusted 设置客户端是否为受信任的,默认为’0’(即不受信任的,1为受信任的). 该字段只适用于
grant_type="authorization_code"的情况,当用户登录成功后,若该值为0,则会跳转到让用户
Approve的页面让用户同意授权, 若该字段为1,则在登录后不需要再让用户Approve同意授权
(因为是受信任的). 对该字段的具体使用请参考OauthUserApprovalHandler.java. (扩展字
)
autoapprove 设置用户是否自动Approval操作, 默认值为 ‘false’, 可选值包括 ‘true’,‘false’, ‘read’,‘write’.
字段只适用于grant_type="authorization_code"的情况,当用户登录成功后,若该值为’true’
支持的scope,则会跳过用户Approve的页面, 直接授权. 该字段与 trusted 有类似的功能,
spring-security-oauth2 2.0 版本后添加的新属性. 在项目中,主要操作
oauth_client_details表的类是JdbcClientDetailsService.java, 更多的细节请参考该类. 也可
以根据实际的需要,去扩展或修改该类的实现.
 
 
oauth_client_token
字段名 字段说明
create_time 数据的创建时间,精确到秒,由数据库在插入数据时取当前系统时间自动生成(扩展字段)
token_id 从服务器端获取到的access_token的值.
token 这是一个二进制的字段, 存储的数据是OAuth2AccessToken.java对象序列化后的二进
制数据.
authentication_id 该字段具有唯一性, 是根据当前的username(如果有),client_idscope通过MD5加密
生成的. 具体实现请参考DefaultClientKeyGenerator.java.
user_name 登录时的用户名
client_id
该表用于在客户端系统中存储从服务端获取的token数据, spring-oauth-server项目中未使用到.
oauth_client_token表的主要操作在JdbcClientTokenServices.java类中, 更多的细节请参考该类.
oauth_access_token
 
字段名 字段说明
create_time 数据的创建时间,精确到秒,由数据库在插入数据时取当前系统时间自动生成(扩展字段)
token_id 该字段的值是将access_token的值通过MD5加密后存储的.
token 存储将OAuth2AccessToken.java对象序列化后的二进制数据, 是真实的AccessToken
的数据值.
authentication_id 该字段具有唯一性, 其值是根据当前的username(如果有),client_idscope通过MD5
加密生成的. 具体实现请参考DefaultAuthenticationKeyGenerator.java.
user_name 登录时的用户名, 若客户端没有用户名(grant_type=“client_credentials”),则该值等
client_id
client_id
authentication 存储将OAuth2Authentication.java对象序列化后的二进制数据.
refresh_token 该字段的值是将refresh_token的值通过MD5加密后存储的. 在项目中,主要操作
oauth_access_token表的对象是JdbcTokenStore.java. 更多的细节请参考该类
 
oauth_refresh_token
字段名 字段说明
create_time 数据的创建时间,精确到秒,由数据库在插入数据时取当前系统时间自动生成(扩展字段)
token_id 该字段的值是将refresh_token的值通过MD5加密后存储的.
token 存储将OAuth2RefreshToken.java对象序列化后的二进制数据.
authentication 存储将OAuth2Authentication.java对象序列化后的二进制数据.
在项目中,主要操作oauth_refresh_token表的对象是JdbcTokenStore.java. (与操作oauth_access_token表的对象
一样);更多的细节请参考该类. 如果客户端的grant_type不支持refresh_token,则不会使用该表.
oauth_code
字段名 字段说明
create_time 数据的创建时间,精确到秒,由数据库在插入数据时取当前系统时间自动生成(扩展字段)
code 存储服务端系统生成的code的值(未加密).
authentication 存储将AuthorizationRequestHolder.java对象序列化后的二进制数据.
在项目中,主要操作oauth_code表的对象是JdbcAuthorizationCodeServices.java. 更多的细节请参考该类。 只有当
grant_type"authorization_code",该表中才会有数据产生; 其他的grant_type没有使用该表。
 
 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!