http是无状态的,即请求之间是相互独立的;即提供用户名/密码验证后,下次还需要再次提供
而cookie就是解决这个问题的
cookies
服务器验证通过后,在响应头中设置set-cookies,浏览器就会把cookies写入本地
客户端之后请求时,就会自动带上cookies,服务器端验证即可
缺点:
但cookies中的信息都是暴露的,不安全
session
服务器验证通过后,在浏览器上写入的是sid,这个sid在服务器的数据库中对应着这此用户的信息
sid是无意义的字符串,浏览器只保存着sid
缺点:
session保存在服务器端,通常在内存中,认证用户增多后会对服务器造成压力
在分布式系统中,用户在哪台服务器登陆的,以后就必须一直在这台服务器上验证,这就限制了负载均衡
jwt(json web token)
保存在浏览器端
过程:
1.用户登录请求,根据user模型,将user_id/username/expire作为载荷(django中),产生jwt-token
2.浏览器将token保存(可以保存在cookie中,也可以保存在本地存储中)
本地存储提供两种方式:localStorage,长期有效;sessionStorage,关闭浏览器失效
3.之后客户端发起请求时,在请求头中带上token供服务器端验证
jwt-token的构成,分为三部分
1.头部header,申明了类型即jwt和后面要用的加密方式;定义时为字典,后用base64编码形成第一部分
{ 'typ': 'JWT', 'alg': 'HS256' }
base64编码:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
2.载荷payload,主要存放用户信息;定义时为字典,后用base64编码形成第二部分
{ "sub": "1234567890", "name": "John Doe", "admin": true }
base64编码:
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
3.签名signature,将前两部分用 . 连接,用头部申明的加密方式和secret组合加密,产生第三部分
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload); var signature = HMACSHA256(encodedString, 'secret');TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
4.将这三部分用 .
连接成一个完整的字符串,构成了最终的jwt
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
secret是保存在服务器端的,是用来签名和验签的,所以secret_key至关重要,相当于服务器的私钥,客户端要是拿到了secret_key就可以给自我签发jwt了(基本只要拿到简单的信息就可以模拟别人登录);所以绝对不能泄露出去
优点:
保存在客户端,减轻服务器压力,不影响负载均衡
可以在payload中放一些不敏感的数据