oauth2.0认证的应用
前言
本片文章叙述oautho2.0的认证流程、以及三种认证方式应用
一、oauth2.0是做什么的?
1、OAuth
OAuth(Open Authorization)是一个关于授权(authorization)的开放网络标准,允许用户授权第三 方应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容。
- Third-party application:第三方应用程序,又称"客户端"(client)
- HTTP service:HTTP服务提供商,简称"服务提供商"
- Resource Owner:资源所有者,又称"用户"(user)
- User Agent:用户代理,比如浏览器。
- Authorization server:授权服务器,即服务提供商专门用来处理授权的服务器。
- Resource server:资源服务器,即服务提供商存放用户生成的资源的服务器。它与认证服务器, 可以是同一台服务器,也可以是不同的服务器。
OAuth的作用就是让"客户端"安全可控地获取"用户"的授权,与"服务商提供商"进行交互。
文档:https://oauth.net/2/ https://datatracker.ietf.org/doc/html/rfc6749
2、使用场景
- 原生app授权:app登录请求后台接口,为了安全认证,所有请求都带token信息,如果登录验证、请求后台数据;
- 前后端分离单页面应用:前后端分离框架,前端请求后台数据,需要进行oauth2安全认证。
- 第三方应用授权登录,比如Github,钉钉,微信,支付宝,淘宝等第三方账号授权登录。
二、oauth2.0认证方式(4种)
运行流程
(A)用户打开客户端以后,客户端要求用户给予授权。
(B)用户同意给予客户端授权。
(C)客户端使用上一步获得的授权,向授权服务器申请令牌。
(D)授权服务器对客户端进行认证以后,确认无误,同意发放令牌。
(E)客户端使用令牌,向资源服务器申请获取资源。
(F)资源服务器确认令牌无误,同意向客户端开放资源。
令牌(token)与密码(password)的作用是一样的,都可以进入系统,但是有三点差异。
(1)令牌是短期的,到期会自动失效,用户自己无法修改。密码一般长期有效,用户不修改,就不会发生变化。
(2)令牌可以被数据所有者撤销,会立即失效。
(3)令牌有权限范围(scope)。对于网络服务来说,只读令牌就比读写令牌更安全。密码一般是完整权限。
1、授权码模式(Authorization Code)
授权代码授权类型用于获得这两种访问令牌和刷新令牌,并为机密客户优化。因为这是一个基于重定向的流,所以客户端必须能够与资源所有者的用户代理(通常是web)交互浏览器),并且能够接收传入的请求(通过重定向)从授权服务器。
(A)客户端通过指示资源所有者的来启动流到授权端点的用户代理。客户端包括它的客户端标识符、请求的范围、本地状态和重定向URI,授权服务器将向其发送一旦允许(或拒绝)访问,将返回用户代理。
(B)授权服务器验证资源所有者(通过用户代理)并建立是否为资源所有者授予或拒绝客户端的访问请求。
©假设资源所有者授予访问权,即授权服务器将用户代理重定向回客户端重定向之前(在请求中或过程中)提供的URI客户端注册。
(D)客户端向授权请求一个访问令牌服务器的令牌端点,包括授权代码在上一步收到。当提出请求时,使用客户端与授权服务器进行身份验证。客户端包括用于获取授权的重定向URI代码验证。
(E)授权服务器验证客户端,验证授权代码,并确保URI重定向received匹配用于重定向客户端的URI步骤©。如果有效,授权服务器返回一个访问令牌和一个可选的刷新令牌。
2、密码模式(Password)
中的资源所有者密码凭据授予类型适合资源所有者与客户端,例如设备操作系统或高度特权的应用程序。授权服务器应该特别注意启用此授予类型,并仅在其他流不允许时才允许它可行的。
此授予类型适用于能够获得资源所有者的凭据(用户名和密码,通常使用一个互动的形式)。它还用于迁移现有客户端使用直接认证方案,如HTTP基本或摘要通过将存储的凭据转换为访问令牌。
(A)资源所有者向客户端提供其用户名和密码。
(B)客户端从授权请求一个访问令牌服务器的令牌端点,包括接收到的凭据来自资源所有者。当发出请求时,客户端使用授权服务器进行身份验证。
©授权服务器对客户端进行认证和验证资源所有者凭据,如果有效,则发出访问权限令牌。
3、客户端模式(Client)
客户端只能使用其客户端请求访问令牌时使用凭据(或其他受支持的身份验证方法)客户端请求访问其下的受保护资源控制,或者其他资源所有者先前的控制与授权服务器一起安排(其方法超出本规范的范围)。客户凭据授予类型必须仅用于机密客户。
(A)客户端与授权服务器进行身份验证从令牌端点请求访问令牌。
(B)授权服务器验证客户端,如果有效,发出访问令牌。
4、简单模式(Implicit)
隐式授权类型用于获取访问令牌(并非如此支持发布刷新令牌),并针对公共优化已知操作特定重定向URI的客户端。这些客户通常在浏览器中使用脚本语言实现比如JavaScript。
因为这是一个基于重定向的流,所以客户端必须能够与资源所有者的用户代理(通常是web)交互浏览器),并且能够接收传入的请求(通过重定向)从授权服务器。
与授权代码授予类型不同,在这种类型中,客户端进行将授权请求和访问令牌请求分开客户端接收访问令牌作为授权的结果请求。
隐式授权类型不包括客户端身份验证和依赖于资源所有者的存在和的注册重定向的URI。因为访问令牌被编码到重定向URI时,它可能被公开给资源所有者和其他驻留在同一设备上的应用程序。
(A)客户端通过指示资源所有者的来启动流到授权端点的用户代理。客户端包括它的客户端标识符、请求的范围、本地状态和重定向URI,授权服务器将向其发送一旦允许(或拒绝)访问,将返回用户代理。
(B)授权服务器验证资源所有者(通过用户代理)并建立是否为资源所有者授予或拒绝客户端的访问请求。
©假设资源所有者授予访问权,即授权服务器将用户代理重定向回客户端重定向前面提供的URI。重定向URI包括URI片段中的访问令牌。
(D)用户代理遵循重定向指令请求web托管的客户端资源(不包括每个[RFC2616]片段)。用户代理保留片段在本地信息。
(E) web托管的客户端资源返回一个网页(通常是一个HTML文档中嵌入的脚本)能够访问的完整重定向URI,包括保留的片段用户代理,并提取访问令牌(和其他参数)包含在片段中。
(F)用户代理执行由网络托管提供的脚本本地客户端资源,它提取访问令牌。
(G)用户代理将访问令牌传递给客户端。
三、oauth_client_details字段说明
字段名 | 说明 |
---|---|
client_id | 主键,必须唯一,不能为空; 用于唯一标识每一个客户端(client); 在注册时必须填写(也可由服务端自动生成); 对于不同的grant_type,该字段都是必须的. 在实际应用中的另一个名称叫appKey,与client_id是同一个概念; |
resource_ids | 客户端所能访问的资源id集合,多个资源时用逗号(,)分隔,如: “unity-resource,mobile-resource”。 我们有Resource Server资源服务器。资源服务器可以有多个,我们可以为每一个Resource Server(一个微服务实例)设置一个resourceid。 Authorization Server给client第三方客户端授权的时候,可以设置这个client可以访问哪一些Resource Server资源服务,如果没设置,就是对所有的Resource Server都有访问权限。 |
client_secret | 用于指定客户端(client)的访问密匙; 在注册时必须填写(也可由服务端自动生成).对于不同的grant_type,该字段都是必须的。 在实际应用中的另一个名称叫appSecret,与client_secret是同一个概念. |
scope | 指定客户端申请的权限范围,可选值包括read,write,trust; 若有多个权限范围用逗号(,)分隔,如: “read,write”。 @EnableGlobalMethodSecurity(prePostEnabled = true)启用方法级权限控制。 然后在方法上注解标识@PreAuthorize(“#oauth2.hasScope(‘read’)”) |
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”(针对移动设备的客户端)。 implicit与client_credentials在实际中很少使用,可以根据自己的需要,在OAuth2.0 提供的地方进行扩展自定义的授权 |
web_server_redirect_uri | 客户端的重定向URI,可为空, 当grant_type为authorization_code或implicit时, 在Oauth的流程中会使用并检查与注册时填写的redirect_uri是否一致. 下面分别说明:
|
authorities | @PreAuthorize(“hasAuthority(‘admin’)”)可以在方法上标志 用户或者说client 需要说明样的权限 指定客户端所拥有的Spring Security的权限值,可选, 若有多个权限值,用逗号(,)分隔, 如: “ROLE_UNITY,ROLE_USER”。 对于是否要设置该字段的值,要根据不同的grant_type来判断, 若客户端在Oauth流程中需要用户的用户名(username)与密码(password)的(authorization_code,password)。 则该字段可以不需要设置值,因为服务端将根据用户在服务端所拥有的权限来判断是否有权限访问对应的API。 但如果客户端在Oauth流程中不需要用户信息的(implicit,client_credentials),则该字段必须要设置对应的权限值, 因为服务端将根据该字段值的权限来判断是否有权限访问对应的API。 (请在spring-oauth-client项目中来测试不同grant_type时authorities的变化) |
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.java的getAdditionalInformation()方法的注释) 在实际应用中, 可以用该字段来存储关于客户端的一些其他信息,如客户端的国家,地区,注册时的IP地址等等 |
autoapprove | 设置用户是否自动Approval操作, 默认值为 ‘false’, 可选值包括 ‘true’,‘false’, ‘read’,‘write’。 该字段只适用于grant_type="authorization_code"的情况,当用户登录成功后,若该值为’true’或支持的scope值,则会跳过用户Approve的页面, 直接授权. |
四、使用
1、授权码认证:
首先登录获取到授权码code
POST 服务地址/oauth/token
请求头添加 {Authorization:Basic base64加密的客户端id和密码(client_id:client_secret)}
form-data内容:
{
grant_type:authorization_code,
redirect_uri:重定向地址,
code:授权码
}
2、密码模式:
POST 服务地址/oauth/token
请求头添加 {Authorization:Basic base64加密的客户端id和密码(client_id:client_secret)}
params内容:
{
username:用户名,
password:密码,
grant_type:password,
scope:客户端权限范围,
}
3、客户端模式:
POST 服务地址/oauth/token
请求头添加 {Authorization:Basic base64加密的客户端id和密码(client_id:client_secret)}
params内容:
{
grant_type:client_credentials,
}
4、刷新token
POST 服务地址/oauth/token
请求头添加 {Authorization:Basic base64加密的客户端id和密码(client_id:client_secret)}
form-data内容:
{
grant_type:refresh_token,
refresh_token:上一次获取到的令牌中的refresh_token,
}
简单模式
我们一般不使用
总结
oauth2.0是优秀的认证框架,在开发中继承WebSecurityConfigurerAdapter、AuthorizationServerConfigurerAdapter这两个类来自定义安全配置,实现UserDetailsService接口来自定义登录逻辑,实现AccessDecisionManager接口来自定义做出最终的访问控制(授权)决策。