概念介绍
认证(Authentication) :验证当前用户的身份,证明“你是你自己”。比如用户密码登录、邮箱发送登录链接、手机号接收验证码等,只要你能收到邮件或验证码就默认你是主人。
授权(Authorization) :用户授予第三方应用访问该用户某些资源的权限就是授权。比如安装APP时,会询问是否允许授予访问地理位置、通讯录等权限,常见的授权方式有 cookie、session、token 和 jwt。
实现认证和授权的前提是需要一个 证书(Credentials) 来标记访问者的身份。
一、Cookie
二、Session
- session 存储在服务端:
session是另一种记录服务器和客户端会话状态的机制。 session是基于cookie实现的,sessionID会被存储到客户端的cookie中。
1. 认证过程
-
用户第一次请求服务器时,服务器会根据提交的信息创建对应的 Session,并将
SessionID放到响应中返回(此Session的唯一标识信息,放在响应头中)。 -
客户端接收到
sessionID后,会将它存入 cookie中(Set-Cookie)。 -
(1) 当用户再次访问服务器时,请求会携带该域名下对应的
cookie。(2) 然后服务端会从 cookie 中获取 SessionID,再根据 SessionID 查找对应的 Session 信息。如果能找到就通过验证、执行后续的操作,否则就中断。
2. cookie 和 session区别
- 存储位置:客户端;服务端。
- 安全性(由存储位置导致的):cookie 可以通过客户端修改,session 只能在服务端设置,所以 session 更安全,一般用于验证用户登录状态。
- 有效期:cookie 可以设置任意时间;session 时间短、和当前标签页生命周期相同。
- 大小和个数限制:cookie 大小不超过 4KB,也有个数限制(20~几百,针对一个网站最多存20个);session 没有大小和个数限制。
- 服务器压力:cookie 压力小;session 压力大,尤其当访问量过多时、会占用过多服务器资源。因此对于并发用户多的场景,适合用 cookie。
三、Token(令牌)
Token 是一串经过加密之后的字符串,相当于是用户的一种身份认证令牌。简单 token 的组成:uid(用户唯一的身份标识) + time(当前时间的时间戳) + sign(签名,是token的前几位以哈希算法压缩成的十六进制字符串)。
-
服务端无状态化:基于 token 的用户认证是一种服务端无状态化的认证方式。服务端不用存放 token 数据,用解析 token 的计算时间换取 session 的存储空间,以减轻服务器的压力。
-
token 可以跨域:前提是不要放在
cookie中。 -
支持移动端设备:因为移动端对cookie、session的支持不太好,所以
token可以有效兼容移动端设备。
(token 类似一张加密身份证,只要出示就知道是自己人;session 则是一种普通的身份证,每次都要根据 id 去查验)
免登录:有了 token 之后,用户就不需要每次访问网站都要先输入账号密码才能拿到数据了。而是只需要登录一次,以后拿着 token,服务器就知道你是哪一个用户了。
1. 身份认证流程
-
用户向服务端发送登录请求,服务端接收请求后会去验证账号、密码等信息。
-
验证成功后,服务端会生成一个 token 并发送给客户端,客户端会将它存储在本地(放在
cookie不支持跨域,所以更好的方法是在请求头中加Authorization: Bearer <token>)。 -
客户端后续向服务端发送请求时,都需要携带该 token(放在请求头中)。然后服务端进行解析校验,验证成功就返回请求数据。
2. token 和 session区别
- 存储位置:客户端;服务端。
- 安全性:token更加安全,因为每个请求都有签名,还能防止 CSRF 攻击。
- 服务端无状态化:token 使服务端无状态化,不会存储会话信息;session 则是一种记录服务端和客户端会话状态的机制,因此服务端是有状态的。
四、JWT
JSON Web Token(简称 JWT)是目前最流行的跨域认证解决方案,它也是一种认证授权机制。
传统方法例如 sessionID 存在缺点,例如当服务器是集群时无法做到单点登录。因为当在 A 服务器登录后生成的 sessionID 只能登录 A 服务器,访问 B 服务器时识别不了。而 JWT 可以做单点登录。
1. JWT 组成
- Header(头部)
- Payload(负载)
- Signature(签名):由 header 和 payload 通过 base64 算法得到签名数据
(1)Header 结构
{
"alg": "HS256", // 告知服务端使用的加密算法
"typ": "JWT" // 加密的类型,固定
}
(2)Payload 结构:可选项,还可以添加一些自定义字段。
(3)签名
base64编码header + ‘.’ + base64编码payload,密钥secret 实际用的是对称加密。
类似 md5 这种摘要算法是不可逆的,不存在密钥去加密解密。
2. JWT 认证流程
-
用户输入用户名/密码登录,服务端认证成功后,会返回给客户端一个 JWT;
-
客户端将 token 保存到本地(通常是 localStorage,也可以是 cookie);
-
当用户再次访问服务端时,需要在请求头的
Authorization字段中使用Bearer模式添加 JWT(也可以放在cookie中发送,但是这样不能跨域)。然后服务端会检查请求头Authorization中的 JWT 信息,如果合法,则允许用户的行为。
3. JWT 的一种实现方式
- 服务端生成 JWT
-
用户输入用户名/密码登录后,后台会在数据库中进行查找。如果能成功找到对应的一组数据,那么服务端可以使用 npm 的 jsonwebtoken 包生成
JWT; -
然后将
JWT(拷贝到ctx.body中)作为响应返回给客户端。
-
- 客户端存储 JWT
-
客户端将接收的 token 存入 storage 中(通常是
localStorage,也可以是cookie); -
之后向服务端发送请求时,需要在请求头中写入
Authorization字段的Bearer模式以携带 token(这是一种约定的格式规范)。Authorization: Bearer <token>
-
- 服务端检查 JWT:检查
Authorization的JWT信息是否合法,合法则允许用户的行为。
4. JWT 和 token异同
- 相同点:都使服务端无状态化。
- 不同点:token 需要查数据库验证 token 是否有效,而 JWT 不用查库,直接在服务端进行校验(能否使用密钥解密)。这是因为用户的信息、加密的数据和过期时间等都在 JWT 里。
- token:服务端验证客户端发来的
token时,还需要查询数据库获取用户信息,然后验证token是否有效。 - JWT:因为
JWT本身就包含了用户信息和加密的数据,因此服务端验证时只需要使用密钥解密即可,不需要查询数据库。
- token:服务端验证客户端发来的
五、比较
1. 注意点
- cookie
- 因为安全性低,尽量不要存储敏感数据,如密码、账户余额等;
- 移动端对
cookie的支持不是很好,而session又需要基于cookie实现,所以移动端常用的是token。
- token
- 因为不需要 cookie,所以可以避免 CSRF 攻击
2. session、cookie、token
- 区别
- 存储位置:session 在服务端,其他都在客户端。
- 安全性:token > session > cookie。
- 服务端有状态:token 无状态,其他都有状态。