登录方案调研
登录方式总结
Cookie + Session 方式
cookie + session 是最传统的登录方式,利用浏览器默认行为,每次请求将登录后设置好的 cookie 发送给服务端, 服务端通过 cookie 中的信息( session_id),获取用户的登录信息。整体流程如下:
- 用户输入用户名密码进行登录
- 服务端验证用户名密码,成功后,生成唯一的 session_id 储存起来(可以是内存、数据库等,通常使用 redis )。
- 通过设置 set-cookie,将 session_id 返回给前端并储存在浏览器 cookie 中。
- cookie 过期前,对该系统的每次请求都将会带上 cookie(浏览器默认行为),后端通过 cookie 中的信息,获取用户的 session_id 信息。 并在后端( redis )查询出对应用户的信息。
优缺点
- 原理简单、实现方便
- 服务器端需维护大量 session_id,有一定负担。(目前通常将 session_id 放在 redis中,也解决了服务器集群下 session_id 同步问题)
- 无法阻止 CSRF 攻击。
JWT 登录
JWT( JSON-WEB-TOKEN ) 是比较新的一种登录方式,他利用时间换空间的方式,服务端将用户的信息相关信息进行加密并返回到客户端,即签发了 一个"令牌",在令牌的有效期内,客户端可以通过传递令牌的方式与服务端通信。JWT 登录整体流程如下:
- 用户输入用户名密码进行登录
- 服务端验证用户名密码,成功后,将用户的相关信息(通常是 user_id)及一些附加信息通过 JWT 方式进行加密,并返回给客户端。
- 客户端可以用任意方式储存服务器返回的 JWT ,之后只需在每次请求时,将 JWT 通过某种方式传递给后端。JWT默认的传递方式为:
"headers": {
'Authorization': 'Bearer ' + token // JWT 规定的的表示形式
}
- 服务器收到请求后,获取并验证 JWT,从而获取用户的信息(通常是 user_id 及一些附加信息),即服务器不需要储存每个用户的状态(即 session), 只需要在每次请求时获取并解析 JWT,即可完成用户身份校验和用户基本信息的获取。
优缺点
- 服务器不需要维护登录状态,服务器复杂度和压力都相对较小
- JWT 的 Token 可以由前端自定义储存、使用,而不用依赖使用浏览器默认行为的 cookie,所以可以在某种程度上提升一些安全性。
- 后端每次接口请求都需要进行 JWT 的加解密,计算压力增大
- JWT 本身不支持"吊销"操作,即签发了的 Token 不能通过服务器使之失效,只能等其自然过期。目前也有一些针对此的解决方案,大家有兴趣可以 寻找。
JWT 基础
JSON Web Token ( JWT ) is an open standard ( RFC 7519 ) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.
JWT 由 Header、Payload、Signature 三部分组成,用 .
分割,即 xxxxx.yyyyy.zzzzz
形式。
具体的 JWT 介绍,可以看 这里 。
OAuth 登录(本质上是一种授权模式)
SSO 单点登录(本质还是 cookie-session 登录)
JWT 简介
JSON Web Token ( JWT ) is an open standard ( RFC 7519 ) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.
JWT 由 Header、Payload、Signature 三部分组成,用 .
分割,即 xxxxx.yyyyy.zzzzz
形式。
Header
JWT 的 header 通常由两部分组成:token 的类型( 即 "JWT" ),和使用的签名算法, 例如 HMAC SHA256 或 RSA。
{
"alg": "HS256",
"typ": "JWT"
}
将 header json 进行 base64Url 编码后,就组成了 JWT 的第一部分
Payload
payload 是 JWT 的第二个组成部分,它包含了所有的 声明 (claim)。 Claim 是针对一个 实体(通常是一个用户)及一些附加属性的一份声明。JWT 有三种类型的 Claim。
- Registered claims (已注册声明): Registered claims 是一系列预先声明好的 claim。它并不是 强制的,但是推荐使用。因为这些预先声明的 claim 是有用的、可交互的。常见的 Registered claims 有 iss (issuer)、 exp (expiration time)、sub (subject)、aud (audience)、 and others 。
Notice that the claim names are only three characters long as JWT is meant to be compact.
- Public claims (公共声明): Public claims 是 可以被使用者随意使用的 claim 。但是为了避免冲突,它们应该在 IANA JSON Web Token Registry 中进行定义,亦或定义为 url 的格式,且 url 需要通过命名空间来避免碰撞。
- Private claims (私有声明): Private claims 是使用 JWT 的多方为了传递信息而自定义的 claim,它既不是 Registered claims,也不是 Public claims 。
下面是 payload 的示例:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
将 payload json 进行 base64Url 编码后,就组成了 JWT 的第二部分。
Do note that for signed tokens this information, though protected against tampering, is readable by anyone. Do not put secret information in the payload or header elements of a JWT unless it is encrypted.
大意是说,签名的 token 虽然防止了篡改,但是对任何人来说,其( header, payload )都是可读的,所以不要将隐私的信息放在 JWT 的 header 或 payload 中,除非是加密过的信息。
Signature
要想生成 JWT 中的 signature 部分,我们需要先有 编码后的 header 和 payload ,一个秘钥,以及一个 在 header 中填写的算法。然后我们要做的就是,给它们签名!
举个例子,如果我们要用 HMAC SHA256 算法来进行 jWT 签名,那么签名过程如下:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
签名是为了保证 JWT 中的信息在整个生命周期中不会发生改变。如果签名的秘钥是私钥的话,JWT 还可以用来 确认发送者的身份(因为只有对应的公钥可以正确的验证这个签名)。
生成 JWT 吧!
当我们完成了上面步骤后,就可以生成 JWT 了。最终输出的 JWT 是 一个由 .
分割的、三个独立的、Base64-URL格式的 字符串。通过这种格式,JWT 可以轻易地在 HTML 和 HTTP 环境中使用,且相对于一些基于 XML 标准的格式例如 SAML, 这种格式更为的健壮。
JWT 的使用
在认证方面,当用户成功登录系统后,系统应该返回一个 JWT 。需要注意的是,因为 JWT 将作为这个用户凭证, 所以在处理 JWT 的过程中,请务必小心,不要出现安全性问题。通常情况下, token 的有效期不应该超过它应该 存活的时间。
You also should not store sensitive session data in browser storage due to lack of security.
不要储存敏感信息在浏览器储存中,因为它也是不够安全的
每当用户想要访问受保护的路由或者资源时,对应的 UA 应该将 JWT 发送给对方。使用的方法通常为, 将 JWT 放在 http 请求 的 Authorization header 中, 且为Bearer 模式。即:
Authorization: Bearer <token>
使用 JWT 可以实现一种无状态的认证机制。服务端受保护的 url 会校验传递过来的 header 中 是否包含 合法的 JWT ,如果存在,则允许用户进行操作。如果 JWT 中包含一些必要的信息,也可以省略从对应的数据源中获取 用户信息的步骤,当然,这不并不适用于所有情况。
请注意,如果您通过 HTTP 标头发送 JWT 令牌,则应尽量防止它们变得太大。某些服务器不接受超过 8 KB 的 header。 如果您尝试在 JWT 令牌中嵌入太多信息,例如通过包含所有用户的权限,您可能需要其他解决方案, 例如 Auth0 Fine-Grained Authorization 。