关于登录授权的小分享
一 前言
在开始之前,对登录、授权的概念进行简单的说明:
登录:
- 通过用户名、密码进行身份认证过程,证明
你是你,确认身份信息。
授权:
- 使用身份信息或持有的令牌确认享有某些权限(如获取用户信息)
授权登录:
- 在不使用户名和密码的情况下,通过授权流程获取到系统令牌,使得第三方应用可以安全的登录系统,获取用户信息。
令牌与密码的区别
使用令牌(Token)和密码(Password)都能通过系统的身份认证,进入系统并获取相应数据,两者之间主要有以下差异:
- 令牌是有有效期的,到期会自动失效,失效后无法通过系统身份认证,密码是长期有效的。
- 令牌是系统生成的,无法进行修改,而密码用户可以自主进行修改
- 令牌可以被数据所有者撤销,撤销后会立即失效
- 令牌可以进行权限配置,限定访问范围,如访问数据模块限制,读写权限限制。
基于以上令牌的特性,使得令牌既可以让第三方应用获取权限,又随时可控,在系统安全性上有一定的保障。需要注意的是令牌和密码一样必须高度保密,一旦令牌被泄露那和密码被泄露的后果是一样的,只要被不法分子获取到了令牌,就能进入系统而系统不会对令牌进行二次身份确认。
二 授权方式
HTTP 中确认授权识别身份信息的方式主要有两种:
- Cookie
- Authorization
Cookie 用在 Web 端之间识别身份使用较多,桌面端以及移动端和 Web 端之间的身份识别主要通过 Authorization。
2.1 Authorization
Authorization 是 HTPP 的请求头( header ) 之一,用于提供身份凭据,通过服务器对用户身份代理进行身份验证,从而允许访问受保护的资源。
HTTP 请求报文:
//请求行
GET /users HTTP/1.1
//Headers
Host:api.github.com
Content-Type:text/plain
Content-Length:243
Authorization:Basic YWxhZGRpbjpvcGVuc2VzYW1l
//Body
bodybodybodybodybodybodybodybodybodybodybodybodybody
Authorization 的 value 为身份验证的凭证信息,在 HTTP 中 Authorization 有以下几种标准认证方案:
- Basic 基础认证
- Bearer 认证
- Digest 摘要认证3
- SSL Client 认证
其中 Basic 和 Bearer 是目前主流的两种验证方案。
2.1 Basic 认证
Basic 认证是将用户名和密码进行 Base64 编码,再将 Base64 编码之后的值用于 Authorization 凭证。
Basic 认证格式:
Authorization: Basic <username:password(Base64ed)>
凭证生成步骤:
- 将用户名和密码通过冒号进行拼接
- 将第一步拼接后的结果进行 Base64 编码
示例:
Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l
需要注意的是 Base64 编码本身并不是一种加密或 Hash 方法,是可逆向解码的。所以 HTTP 在进行传输时,使用 Basic 验证等同于明文传输用户名和密码 ,安全性非常低。所以 Basic 验证一般需和 HTTPS 协议配合使用以保证安全性。
2.2 Bearer 认证
Bearer 认证中 Authorization 的凭证一般称为 Access_token 或 Bearer_token。Bearer 验证凭证的生成和验证由应用程序开发人员设计和实现,比较灵活方便。
Bearer 认证格式:
Authorization: Bearer <bearer token>
凭证生成方式:
目前生成 Bearer 凭证最主流的编码协议是JWT( Json Web Token), JWT 是一种基于 JSON 的开放标准,关于 JWT 的详细介绍可参考 HTTP Bearer 认证及 JWT 的使用。
示例:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOiJBZG1pbiIsIkV4cGlyZSI6IjIwMjAtMDctMTEgMTY6NDc6MTYifQ.9ev6IGc1K3xvYaEfmMYeyFz5oHCM57fRGOvSZ-jvArw
Bearer 认证流程:
三 授权登录
授权登录即我们经常用到的第三方登录、三方授权。系统/客户端通过委托第三方可以在不使用户名和密码的情况下,通过授权流程来对特定的用户进行身份鉴定从而获取到系统令牌/身份凭证,使得第三方应用可以安全的登录系统,获取用户信息。
简单来说,系统/客户端本身不做任何用户身份识别、凭证授权,这些工作交给第三方来完成,系统/客户端只需维护通过授权获取到的系统令牌/身份凭证,获取用户信息。
3.1 应用场景
一般来说想要获取某个系统的指定数据,需要进行账号密码登录,身份认证通过后才能获取相应数据。而账号密码一般掌握在数据所有者也就是具体用户手中,一般不会对外公开。如果用户需要指定三方应用在一定时间内也能获取相应数据,而又不泄露自身的账号密码,此时可通过授权机制使得三方应用在短期内获得获取指定数据的权限。
3.2 授权机制
前面说到的通过授权流程来进行身份验证、获取身份凭证,那么这个流程究竟是怎么工作的?怎样才能保证整个授权流程的安全性?
这就需要用到 OAuth(Open Authorization) 授权协议了。OAuth 是一个验证授权的开放标准,主要有 OAuth 1.0 和 OAuth 2.0 两个版本,但两个版本完全不同、完全不兼容,OAuth 2.0 是目前最流行,使用最广泛的版本,一般提到 OAuth 协议指的就是 OAuth 2.0。
3.2.1 OAuth2
OAuth2 是一种三方授权协议,主要用于向第三方应用颁发授权令牌(Token)。OAuth2 在 OAuth1 的基础上简化了授权流程,取消所有 Token 加密过程,强制使用 HTTPS 协议,安全性更高。
3.2.1.1 授权类型
OAuth2 标准 规定了四种授权类型:
- 授权码(Authorization-Code)
- 隐藏式(Implicit)
- 密码式(Password)
- 客户端凭证(Client Credentials)
授权前置步骤:
以上四种授权方式,第三方应用在申请授权获取令牌之前,都必须先向授权方申请第三方授权合作,进行身份信息备案,获取到 client_id(客户端 ID) 和 client_secret(客户端秘钥)。如在授权方对应的开发者平台创建应用信息获取 client_id(客户端 ID) 和 client_secret(客户端秘钥)。此步骤一定程度上保证了整个授权流程的安全性,授权方只向备案过的第三方颁发令牌,避免令牌被滥用带来安全事件。
3.2.1.2 授权码
授权码方式授权是目前最常用的授权类型,安全性最高。三方应用需要先向授权方申请一个授权码后使用该码获取令牌。
1.适用场景:
此方式适用于前后端分离的应用,通过前端/客户端获取到授权码后上传至服务端,由服务端负责令牌的获取以及存储,后续与资源服务器的通信也都在服务端进行,有效避免通信路径中令牌泄露风险。
2.授权流程:
- 用户使用三方应用时,点击【通过 XX(如 GitHub)登录/授权】按钮,三方应用跳转至授权方授权页面,并传入 client_id;
- 授权方根据 clent_id 在授权页面展示第三方应用的信息以及申请的权限并询问用户释放同意授权;
- 用户点击【同意授权】后授权方服务器返回 Authorization Code 即授权码给三方应用;
- 三方应用将 Authorization Code 上传至自身服务器;
- 服务器将 Authorization Code 、client_secret 一并发送给授权方服务器;
- 授权方服务器验证通过后向三方应用服务器颁发授权令牌,完成 OAuth 流程。实际上返回给三方应用服务器的是如下格式的一段 JSON 字符串,其中的
access_token字段就是授权令牌。至此 OAuth 授权流程结束。
{
"access_token":"ACCESS_TOKEN",
"token_type":"bearer",
"expires_in":2592000,
"refresh_token":"REFRESH_TOKEN",
"scope":"read",
"uid":100101,
"info":{...}
}
3.access_token:
授权令牌是由授权服务器下发给三方应用的一个授权凭证,三方应用可以通过 access_token去向授权方获取用户信息,授权服务器验证通过后返回用户信息。access_token主要在时间范围和权限范围两个维度进行访问控制,分别由返回 JSON 字符串中的expires_in 字段和 scope字段控制,expires_in字段为过期时间,过期后 access_token 即不可用,scope为权限范围控制字段,用于控制access_token的可访问范围,如只允许访问用户基本信息名称、头像等。
4.refresh_token:
refresh_token 刷新令牌主要用于更新 access_token,一般来说 access_token的时效性很短,而refresh_token具有很长的时效性,当 access_token 失效时可以通过refresh_token调用刷新令牌的接口去授权服务器获取新的 access_token。
使用 access_token 和 refresh_token 的目的出于安全方面考虑,当access_token 泄露时,由于其时效性,使其被用于做坏事的时间有限,最小限度保证损失。而且refresh_token 只存在于三方服务器,没有泄露风险。
3.2.1.3 隐藏式
1.适用场景:
适用于没有后端的纯前端 Web 应用。
由于没有后端,获取的令牌就必须在前端进行存储,所以 OAuth2 标准规定了允许直接向前端颁发令牌,没有获取授权码中间步骤,称之为隐藏式。
由于此授权方式直接把令牌颁发给前端,安全性很低,只适用于安全性要求不高的场景,且令牌的有效期必须非常短,一般情况就是当前会话结束、关闭浏览器即失效。
2.授权流程:
-
用户在适用第三方 Web 网站时需要登录,点击【通过 XX(如 GitHub)登录/授权】按钮,跳转跳转至授权方授权页面,并传入 client_id;
https://github.com/oauth/authorize? response_type=token& client_id=CLIENT_ID& redirect_uri=CALLBACK_URL& scope=read第三方网站通过以上链接参数格式向授权方服务器请求颁发令牌,其中
response_type参数为token表示请求授权令牌,redirect_uri参数为授权后第三方网站指定跳转的网址。 -
授权方根据 clent_id 在授权页面展示第三方应用的信息以及申请的权限并询问用户释放同意授权;
-
用户点击【同意授权】后授权方服务器通过
redirect_uri以 URL 参数的形式将授权令牌传给第三方网站。https://a.com/callback#token=ACCESS_TOKEN
3.2.1.4 密码式
1.适用场景:
HMSHMSHMS密码式授权适用于高度信任的三方应用,在此前提下 OAuth2 标准 允许用户直接使用授权方网站的用户名密码去授权服务器申请令牌。
此方式直接泄露了授权方的用户名密码,风险非常高,必须在其他授权方式都无法使用且必须是用户高度信任的应用场景下才可使用。
2.授权流程:
-
第三方应用要求授权方网站提供用户名和密码,然后使用用户名和密码向授权方服务器请求授权令牌。
https://oauth.b.com/token? grant_type=password&HMS username=USERNAME& password=PASSWORD& client_id=CLIENT_IDgrant_type参数值为password表示请求授权方式为密码式,username和password为授权方网站用户名和密码。 -
授权方服务器验证用户名和密码通过后直接通过 HTTP 响应报文返回授权令牌给第三方网站。
3.2.1.5 客户端凭证
1.适用场景:
凭证式授权适用于没有前端 UI 的纯命令行应用,在命令行下请求授权令牌。
2.授权流程:
-
第三方应用在命令行直接使用
client_id和client_secret向授权方服务器发出授权请求。https://oauth.b.com/token? grant_type=client_credentials& client_id=CLIENT_ID& client_secret=CLIENT_SECRETgrant_type参数值为client_credentials表示请求授权方式为凭证式。 -
授权方服务器通过
client_id和client_secret进行身份验证通过后,直接通过 HTTP 响应报文返回授权令牌。
3.3 令牌使用
第三方应用获取到授权令牌后,就可以使用令牌向授权服务器发出请求。具体的使用方式就是通过 HTPP 的 Bearer 认证的方式,将令牌放在 HTTP 请求报文请求头 Authorization的值中:
Authorization: Bearer <bearer token>
HTTP Bearer 认证的方式也正式因为 OAtuth 协议的流行而成为目前使用最广泛的认证方式。
四 参考资料
www.ruanyifeng.com/blog/2019/0…