正文开始之前,我们先要了解一个概念,就是什么是 登录态
。
主流Web应用比如浏览器是基于http协议的,而http协议是 无状态
的。什么是 无状态
?就是服务器不知道是谁发送了这个http请求,无法识别区分用户身份。
所以登录态就是服务端用来区分用户身份,同时对用户进行记录的技术方案。
那怎么实现用户的登录态呢?常见的实现流程如下:
流程有了,如何实现呢?
常见的方案有HTTP基本认证、Cookie和Session认证、Token认证、单点登录认证等,下面一一介绍。
HTTP基本认证是HTTP协议本身提供了一种服务端对客户端进行用户身份验证的方法。 流程如下:
sequenceDiagram
autonumber
客户端->>服务端:Get / HTTP/1.1 Host:www.qq.com
服务端->>客户端:HTTP/1.1 401 Unauthorised WWW-Authenticate: Basic realm="qq.com"
客户端->>客户端:弹出登录窗口
客户端->>服务端:Get / HTTP/1.1 Host:www.qq.com Authorization: Basic xxxxxx
服务端->>客户端:验证成功,返回用户数据
WWW-Authenticate: Basic realm="qq.com"
,弹出用户名和密码输入框要求用户进行验证。Base64
格式发送给服务端。这是一种比较简单的验证用户身份的方式,甚至不需要写代码,只要后端服务器配置一下即可。
优点:兼容性好,主流浏览器都支持
缺点:
先了解两个概念,Cookie和Session是什么呢? 上面说到HTTP是一种无状态协议
,而Cookie和Session可以弥补 HTTP 的无状态特性。
Cookie是客户端请求服务端时,由服务端创建并由客户端存储和管理的小文本文件。具体流程如下:
Session是客户端请求服务端时服务端会为这次请求创建一个数据结构,这个结构可以通过内存、文件、数据库等方式保存。具体流程如下:
Token又叫令牌,是服务端生成用来验证客户端身份的凭证,客户端每次请求都携带Token。 Token一般由以下数据组成:
uid(用户唯一的身份标识)
time(当前时间的时间戳)
sign(签名,由token的前几位+盐用哈希算法压缩成一定长的十六进制字符串)
3.3里说到为了避免被盗用Token一般有效期比较短。但是有效期太短会造成客户端不断重新登录,体验太差。有没有什么办法可以解决这个问题呢?
那就是再来一个Token,一个专门生成Token的Token,称为 Refresh Token
。
流程如下:
3.3、3.4里服务端校验客户端发过来的Token是否有效时,可能会查询数据库来验证。如果每次请求都要查询数据库,可能会带来额外性能消耗。
那这个有没有办法优化呢?
答案是有的,那就是JWT(JSON Web Token
)。JWT
是 Auth0
提出的通过 对JSON进行加密签名
来实现授权验证的方案。
JWT也是一种Token,由三部分组成: Header头部
、 Payload负载
和 Signature签名
。它是一个很长的字符串,中间用点( .
)分隔成三个部分,列如 :
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Header头部:
{
"alg": "Hash算法(HMAC、SHA256或RSA)",
"typ": "Token的类型(JWT)"
}
Payload负载:
{
"iss": "签发人(issuer)",
"exp": "过期时间(expiration time)",
"sub": "主题(subject)",
"aud": "受众(audience)",
"nbf": "生效时间(not before)",
"iat": "签发时间(issued at)",
"jti": "编号(JWT ID)",
"uid": "自定义字段(可以存储用户ID等)",
}
Signature 签名:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret //设置的密钥
)
JWT的流程和Token的基本一样,因为已经携带了客户端信息(如用户ID等),所以服务端校验Token时不需要查询数据库了。
上面说的都是同一个域名(或同一主域)下,通过Cookie或Token携带凭证实现登录态管理。但是如果有很多域名,如何实现用户在一个域名下登录后,访问另一个域名也能自动登录呢?
这就是单点登录问题(Single Sign On
)
要实现SSO,需要有一个CAS(Central Authentication Service)
中央授权服务(假设域名为cas.com)来提供统一的登录功能。
假如现在有域名http://abc.com和http://123.com要实现互相自动登录。流程如下:
先访问http://abc.com
再访问http://123.com
先访问http://abc.com
本文系作者在时代Java发表,未经许可,不得转载。
如有侵权,请联系nowjava@qq.com删除。