1 cookie
Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。Cookie存储的数据量有限,且都是保存在客户端浏览器中。不同的浏览器有不同的存储大小,但一般不超过4KB。因此使用Cookie实际上只能存储一小段的文本信息。
例如:登录网站,今输入用户名密码登录了,第二天再打开很多情况下就直接打开了。这个时候用到的一个机制就是Cookie。
2 Session
Session是另一种记录客户状态的机制,它是在服务端保存的一个数据结构(主要存储的的SessionID和Session内容,同时也包含了很多自定义的内容如:用户基础信息、权限信息、用户机构信息、固定变量等),这个数据可以保存在集群、数据库、文件中,用于跟踪用户的状态。
客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。
用户第一次登录后,浏览器会将用户信息发送给服务器,服务器会为该用户创建一个SessionId,并在响应内容(Cookie)中将该SessionId一并返回给浏览器,浏览器将这些数据保存在本地。当用户再次发送请求时,浏览器会自动的把上次请求存储的Cookie数据自动的携带给服务器。
服务器接收到请求信息后,会通过浏览器请求的数据中的SessionId判断当前是哪个用户,然后根据SessionId在Session库中获取用户的Session数据返回给浏览器。
Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。为防止内存溢出,服务器会把长时间内没有活跃的Session从内存删除。这个时间就是Session的超时时间。如果超过了超时时间没访问过服务器,Session就自动失效了。
3 token
验证流程:
- 客户端使用用户名跟密码请求登录
- 服务端收到请求,去验证用户名与密码
- 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
- 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者数据库里
- 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
- 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据
3.1 JWT
JWT 算法主要分为 3 个部分:header(头信息),playload(消息体),signature(签名)。
- header 部分指定了该 JWT 使用的签名算法:
header = '{"alg":"HS256","typ":"JWT"}' // `HS256` 表示使用了 HMAC-SHA256 来生成签名。
- playload 部分表明了 JWT 的意图:
payload = '{"loggedInAs":"admin","iat":1422779638}' //iat 表示令牌生成的时间
- signature 部分为 JWT 的签名,主要为了让 JWT 不能被随意篡改,签名的方法分为两个步骤:
- 输入
base64url
编码的 header 部分、.
、base64url
编码的 playload 部分,输出 unsignedToken。 - 输入服务器端私钥、unsignedToken,输出 signature 签名。
const base64Header = encodeBase64(header)
const base64Payload = encodeBase64(payload)
const unsignedToken = `${base64Header}.${base64Payload}`
const key = '服务器私钥'
signature = HMAC(key, unsignedToken)
最后的 Token 计算如下:
const base64Header = encodeBase64(header)
const base64Payload = encodeBase64(payload)
const base64Signature = encodeBase64(signature)
token = `${base64Header}.${base64Payload}.${base64Signature}`
服务器在判断 Token 时:
const [base64Header, base64Payload, base64Signature] = token.split('.')
const signature1 = decodeBase64(base64Signature)
const unsignedToken = `${base64Header}.${base64Payload}`
const signature2 = HMAC('服务器私钥', unsignedToken)
if(signature1 === signature2) {
return '签名验证成功,token 没有被篡改'
}
const payload = decodeBase64(base64Payload)
if(new Date() - payload.iat < 'token 有效期'){
return 'token 有效'
}
4 SSO 单点登录
4.1 SSO 单点登录
- 用户访问网站
a.com
下的 pageA 页面。 - 由于没有登录,则会重定向到认证中心,并带上回调地址
www.sso.com?return_uri=a.com/pageA
,以便登录后直接进入对应页面。 - 用户在认证中心输入账号密码,提交登录。
- 认证中心验证账号密码有效,然后重定向
a.com?ticket=123
带上授权码 ticket,并将认证中心sso.com
的登录态写入 Cookie。 - 在
a.com
服务器中,拿着 ticket 向认证中心确认,授权码 ticket 真实有效。 - 验证成功后,服务器将登录信息写入 Cookie(此时客户端有 2 个 Cookie 分别存有
a.com
和sso.com
的登录态)。
如果认证中心登录完成之后,访问
b.com
下的页面:这个时候,由于认证中心存在之前登录过的 Cookie,所以也不用再次输入账号密码,直接返回第 4 步,下发 ticket 给
b.com
即可。
4.2 SSO 单点登录退出
当某个产品 c.com
退出登录时:
- 清空
c.com
中的登录态 Cookie。 - 请求认证中心
sso.com
中的退出 api。 - 认证中心遍历下发过 ticket 的所有产品,并调用对应的退出 api,完成退出。
5 OAuth 第三方登录
以微信开放平台的接入流程为例:
- 首先,
a.com
的运营者需要在微信开放平台注册账号,并向微信申请使用微信登录功能。 - 申请成功后,得到申请的 appid、appsecret。
- 用户在
a.com
上选择使用微信登录。 - 这时会跳转微信的 OAuth 授权登录,并带上
a.com
的回调地址。 - 用户输入微信账号和密码,登录成功后,需要选择具体的授权范围,如:授权用户的头像、昵称等。
- 授权之后,微信会根据拉起
a.com?code=123
,这时带上了一个临时票据 code。 - 获取 code 之后,
a.com
会拿着 code 、appid、appsecret,向微信服务器申请 token,验证成功后,微信会下发一个 token。 - 有了 token 之后,
a.com
就可以凭借 token 拿到对应的微信用户头像,用户昵称等信息了。 a.com
提示用户登录成功,并将登录状态写入 Cooke,以作为后续访问的凭证。