1. 一些概念
-
单点登陆:
- 一套公用的用户体系,登陆后,能够访问所有的系统。
- 这只是一类解决方案的统称,在具体的实施方面,有两种策略 SAML,OAuth
-
OpenID:
- 比如,允许使用微信/支付宝或者其他账号 登陆 其他网站
- 只用于身份认证,允许你以同一个账号在多个网站登陆。
- 登陆后 ,该站点无法访问你在 微信 上的数据。
- Authentication:身份鉴别,也就是 认证(鉴别是否为合法用户)
- Authorisation:授权(鉴别访问权限)
- SMAL 2.0: https://zhuanlan.zhihu.com/p/...
-
OAuth :
- 用于授权,允许被授权方访问授权方的用户数据
- https://zhuanlan.zhihu.com/p/...
1. token 的典型流程:
- 用户登录的时候,服务端生成一个token(通过登录信息做数字签名,加密之后得到的字符串)返回给客户端
- 客户端后续的请求都带上这个token
- 服务端解析token(做解密和签名认证,判断其有效性)获取用户信息,并响应用户的请求。
- token会有过期时间,客户端登出的时候也会废弃token,但是服务端不需要任何操作
2. session 和 token 的区别:
- session, 要求服务端存储信息,并根据id能够检索,而 token 不需要。
- 服务端 要 通过 token 来解析 用户身份,也需要定义好相应的协议。
- session 一般使用cookie 来交互。token,可以是 cookie,也可以是 其他heaser,甚至可以放在请求的内容中。不使用cookie可以带来跨域的便利性
- 很多情况下,sessin 和 token 可以一起使用。
- token 技术 对应的标准,就是JWT
3.JWT(JSON Web Tokens)
-
组成:
-
Header(头部)(是一个JSON 对象)
{ "alg": "HS256", // 表示签名的算法,默认是 HMAC SHA256(写成 HS256) "typ": "JWT" // 表示Token的类型,JWT 令牌统一写为JWT }
- Payload(负载)(也是一个JSON 对象-- 用来存放实际需要传递的数据)
{ // 7个官方字段 "iss": "a.com", // issuer:签发人 "exp": "1d", // expiration time:(必须设置) "sub": "test", // subject: 主题 "aud": "xxx", // audience: 受众 "nbf": "xxx", // Not Before:生效时间 "iat": "xxx", // Issued At: 签发时间 "jti": "1111", // JWT ID:编号 // 可以定义私有字段 "name": "John Doe", "admin": true }
-
Signature(签名)
- 对前两部分的签名,防止数据被篡改。
- 需要指定一个密钥(secret)。
-
采用的公式:
- header 中的签名算法(base64UrlEncode(header) + '.' + base64UrlEncode(payload), secret)
-
- JWT = Base64(Header) + "." + Base64(Payload) + "." + $Signature
-
特点:
- JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。
- 发送 JWT, 要使用 https,不实用HTTPS的时候,JWT里面不要写入秘密数据。
- 在使用过程中无法废除 某个 token,或者更改 token 的权限,也就是一旦签发就会始终有效。
-
使用方法:
- 客户端,得到 token 后,可以存储在 cookie里,或者localstorage 中
- 以后的http 请求都要带着 这个token
- 发送的时候:可以放在cookie 中,也可以放在 HTTP 请求头 信息 Authorization 字段中,还可以在 post 请求的时候放在请求数据体里。
-
分类:
-
access token:
- 有效期短
- 以上的都是针对 该种 token
-
refresh token:
- 有效期长。
- 自身以及过期时间是 存储在服务器的数据库中的。
- 只有在申请新的 access token 的以后才会验证,不会对业务接口响应时间造成影响,也不会一直保存在内存中以应对大量的请求。
-
-
为什么要有 refresh token?
- 目的:职能分离。refresh token 负责身份认证,access token 负责请求资源。
-
流程:
- client -> server: username && password
- server: 得到token
- server -> client: access token 、 refresh token
- client:将 token保存在本地
- client -> server: access token
- server: access token 没有过期
- server -> client: 返回数据
- client -> server: access token
- server: access token 过期
- server -> client: 返回错误
- client -> server: refresh token
- server: 判断 refresh token 是否过期
- server -> client: 没过期,则返回新 的 access token和 refresh token。如果过期了,需要重新登陆
4. token 和 session 的区别:
-
session:
- 为无状态的HTTP提供持久机制。
- 如果需要实现有状态的会话,可以增加Session来在服务端保存一些状态。
- 只提供一种简单的认证,数据只保存在站点,不应该共享给其他网站或者第三方APP
-
token:
- 就是一个令牌。
- 作为身份认证安全性更好。
- 如果你的用户数据可能需要和第三方共享,或者允许第三方调用API接口,用Token。
5. bearer token:
-
定义:
- 用于 OAuth 2.0 授权访问资源
- 任何 持有 bearer 的都可以访问资源,而无需证明持有加密 key。
- 一个 bearer 代表授权范围、有效期,以及其他授权事项。
- 传输时,要防止泄露。
- 有效期不能过长,过期后,可使用 refresh token 申请 更新。
-
资源请求:
- bearer 实现资源请求移动有 3种方式,以下的优先级依次递减。
- Authorization Header:
Authorization: Bearer mF_9.B5f-4.1JqM
-
Form-Encoded Body Parameter:
- 使用:
Content-Type: application/x-www-form-urlencoded access_token=mF_9.B5f-4.1JqM
-
使用条件:
- 头部必须包含"Content-Type: application/x-www-form-urlencoded"
- entity-body必须遵循application/x-www-form-urlencoded编码(RFC 6749)
- 如果entity-body除了access_token之外,还包含其他参数,须以"&"分隔开
- entity-body只包含ASCII字符
- 要使用request-body已经定义的请求方法,不能使用GET
-
URI Query Parameter:
GET /resource?access_token=mF_9.B5f-4.1JqM HTTP/1.1 Cache-Control: no-store
- 服务端应在响应中使用 Cache-Control: private
-
WWW-Authenticate 头:
- 在客户端未发送有效Bearer的情况下,即错误发生时,资源服务器须发送WWW-Authenticate头
- 例:
WWW-Authenticate: Bearer realm="example", error="invalid_token", error_description="The access token expired"
-
字段用法:
- Bearer:Beare作为一种认证类型(基于OAuth 2.0),使用"Bearer"关键词进行定义
- realm:与Basic、Digest一样,Bearer也使用相同含义的域定义reaml
- scope:授权范围,可选的,大小写敏感的,空格分隔的列表(%x21 / %x23-5B / %x5D-7E),可以是授权服务器定义的任何值,不应展示给终端用户。OAuth 2.0还规定客户端发送scope请求参数以指定授权访问范围,而在实际授权范围与客户端请求授权范围不一致时,授权服务器可发送scope响应参数以告知客户端下发的token实际的授权范围。下为两个scope用法实例:
scope="urn:example:channel=HBO&urn:example:rating=G,PG-13"``` - error:描述访问请求被拒绝的原因,字符%x20-21 / %x23-5B / %x5D-7E之内 - error_description:向开发者提供一个可读的解释,字符%x20-21 / %x23-5B / %x5D-7E之内 - error_uri:absolute URI,标识人工可读解释错误的页面,字符%x21 / %x23-5B / %x5D-7E之内.当错误发生时,资源服务器将发送的HTTP Status Code(通常是400, 401, 403, 或405)及Error Code如下: - invalid_request:请求丢失参数,或包含无效参数、值,参数重复,多种方法发送access token,畸形等。资源服务器将发送HTTP 400 (Bad Request) - invalid_token:access token过期、废除、畸形,或存在其他无效理由的情况。资源服务器将发送HTTP 401 (Unauthorized),而客户端则需要申请一个新的access token,然后才能重新发送该资源请求
bearer token response:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"mF_9.B5f-4.1JqM",
"token_type":"Bearer",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA"
}
```
-
安全威胁:
- token 伪造/修改: 攻击者伪造/修改 已有的 token,导致资源服务器授权 通过非法访问的客户端,因此需要对 token 使用数字签名或者消息认证码来保证完整性。
- token 泄漏:本身包含认证、有效期等敏感信息,所以需要加密。
- token 改寄:攻击者用一个访问A资源服务器的token去请求B资源服务器的资源。因此通常 token 中可以包含代表资源服务器的标识 来防止这种情况的发生。
- token 重放:攻击者企图使用曾经使用过的token来请求资源。因此token需包含有效期(比如少于1小时)
5. 使用token需要考虑的问题
- 如果你认为用数据库来存储 token 会导致查询时间太长,可以选择放在内存当中。比如 redis 很适合你对 token 查询的需求。
- token 完全由应用管理,所以它可以避开同源策略
- token 可以避免 CSRF 攻击(因为不需要 cookie 了)
- 移动端对 cookie 的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。