赞
踩
一 、主流趋势
在程序开发中,用户认证授权是一个绕不过的重难点。以前的开发模式下,cookie 和 session 认证是主流,
随着前后端分离的趋势,基于 Token 的认证方式成为主流,而 JWT 是基于 Token 认证方式的一种机制,是实现单点登录认证的一种有效方法。
二 、定义 及 全称
JSON Web Token(JWT)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519) 定义了一种简洁的,紧凑和自包含的方法用于通信双方之间以JSON对象的形式安全的传递信息。因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名。作为标准,它没有提供技术实现,但是大部分的语言平台都有按照它规定的内容提供了自己的技术实现,所以实际在用的时候,只要根据自己当前项目的技术平台,到官网上选用合适的实现库即可。
三 、jwt流程及 结构
1、流程
JWT验证流程
(1)浏览器端(客户端)post/user/login + username and password 浏览器在登录表单中输入用户名密码进行登录操作。
(2)服务器接收到了用户名密码后,利用secret加密方式生成一个JWT,
(3)将该JWT返回给浏览器browser
(4)浏览器接收到JWT之后,将JWT放在自己的请求头中,想服务器端请求数据
(5)服务器端检查JWT的签证,获取到JWT中的payload中的声明信息
(6)然后将请求的数据响应给浏览器
2、结构三部分 用 “.”拼接 三块 内容
1、header:
作用 :声明类型 jwt,声明 加密 算法 一般 用HMAC SHA256
{
"type":"JWT",
"alg": "HS256"
}
2、荷载 payload
作用 :存放 有效 信息 base64加密
{
"sub": "1234567890",
"name": "John Doe"
}
3、secreet-signatu 算法 加盐加密
signature=HMACSHA256(encodedString,
'secret'
)
三 、特点
四 、缺点
1、无法更新token有效期,用户登录状态刷新难以实现
2、无法销毁一个token,服务端不能对用户状态进行绝对控制
五 、应用场景
1、一次性验证:例如邮件激活账户,需要具备一下特性:标识用户,实效性(几个小时内 激活)
2、restful API 无状态认证:jwt 来做 restful api 的身份认证也是值得推崇的一种使用方案。客户端和服务端共享 secret;过期时间由服务端校验,客户端定时刷新
五 、存在的问题
1、token 注销 问题
方案一
1)适当减短token有效期,让token尽快失效
2)删除客户端cookie
3)服务端对失效token进行标记,形成黑名单,虽然有违无状态特性,但是因为token有效期短,因此标记 时间也比较短。服务器压力会比较小
方案 二
1)用户登录后,生成JWT
2)把JWT的id存入redis,只有redis中有id的JWT,才是有效的JWT
3)退出登录时,把ID从Redis删除即可
2、token 续签 的 问题
在验证用户登录状态的代码中,添加一段逻辑:判断cookie即将到期时,重新生成一个token。比如token有效期为30分钟,当用户请求我们时,我们可以判断如果用户的token有效期还剩下10分钟,那么就重新生成token。因此用户只要在操作我们的网站,就会续签toke
3、异地 登陆 的 问题
因此如果有类似需求, 就不应选择JWT作为登录方案,而是使用传统session登录方案。
但是,如果一定要用JWT实现类似要过,就需要在Redis中记录登录用户的JWT的token信息,这样就成了有状态的登录,还不如一开始就选择Session方案
4、cookie被盗用
5、cookie被篡改问题?
6、如何完成权限校验
六、生成 规则
两种 实现 方案 都可以 放在 User model 中
可逆方案 一 、
- from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
-
- data = {"id": 42, "user": "foobar"}
- max_age_s = 123
-
- s1 = Serializer('secret', expires_in=max_age_s)
- s1_dumped = s1.dumps(data)
- s1_loaded = s1.loads(s1_dumped)
-
- print(s1_dumped)
- print(s1_loaded)
可逆 方案 二
- dic = {
- 'exp': datetime.datetime.now() + datetime.timedelta(days=1), # 过期时间
- 'iat': datetime.datetime.now(), # 开始时间
- 'iss': 'vspn', # 签名
- 'data': { # 内容,一般存放该用户id和开始时间
- 'username': 'test1',
- 'b': 2,
- },
- }
-
- s = jwt.encode(dic, 'secret', algorithm='HS256') # 加密生成字符串
- print(s)
- print(type(s))
- s = jwt.decode(s, 'secret', issuer='vspn', algorithms=['HS256']) # 解密,校验签名
- print(s)
- print(type(s))
报错 :AttributeError: module 'jwt' has no attribute 'encode'
报错 原因 :同时安装了 jwt 和 pyjwt
解决 办法 :
pip3 uninstall jwt
pip3 uninstall pyjwt
pip3 install jwt
如果jwt报错 安装pyjwt
七、token 认证 装饰器
- from functools import wraps
- def login_required(view_func):
- @wraps(view_func)
- def verify_token(*args, **kwargs):
- try:
- # 在请求头上拿到token
- token = request.headers.get('token')
- except Exception:
- # 没接收的到token,给前端抛出错误
- # 这里的code推荐写一个文件统一管理。这里为了看着直观就先写死了。
- return jsonify(code=4103, msg='缺少有效token')
-
- try:
- dic = User.verify_auth_token(token)
- print(dic)
- if dic["exp"] < time.time():
- return jsonify(code=4101, msg="登录已过期")
- username = dic["data"]["username"]
- redis_token = redis_conn.handle_redis_token(key=username)
- if not redis_token or redis_token != token:
- return jsonify(code=4201, msg="登录已过期")
- except Exception :
- return jsonify(code=4301, msg="登录已过期")
- return view_func(*args, **kwargs)
- return verify_token
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。