常用的前后台分类认证 - jwt(json web token)
一、jwt认证规则
- 全称:json web token
- 解释:加密字符串的原始数据是json,后台产生,通过web传输给前台存储
- 格式:三段式
- 头(Header)、载荷(Payload)、签名(Signature)、
- 头和载荷采用的是base64可逆加密,签名才有md5不可逆加密
- 内容:
- 头(基础信息,也可以为空):加密方式、公司信息、项目组信息、...
- 载荷(核心信息):用户信息、过期时间、...
- 签名(安全保障):头加密结果+载荷加密结果+服务器秘钥 的md5加密结果
- 认证规则:
- 后台一定要保障 服务器秘钥 的安全性(它是jwt的唯一安全保障)
- 后台签发token -> 前台存储 -> 发送需要认证的请求带着token -> 后台校验得到合法的用户
1.1 为什么要有jwt认证
1) 后台不需要存储token,只需要存储签发与校验token的算法,效率远远大于后台存储和取出token完成校验
2) jwt算法认证,更适合服务器集群部署
二、jwt模块
-
安装:
pip install djangorestframework-jwt
-
模块包名:rest_framework_jwt
三、jwt模块使用
- 有了drf-jwt框架后,后期任务只需要重写登录即可:
- 为什么要重写登录:drf-jwt只完成了账号密码登录,我们还需要手机登录,邮箱登录
- 为什么不需要重写认证类:因为认证规则已经完成且固定不变,变得只有认证字符串的前缀,前缀可以在配置文件中配置
使用提供好的 jwt视图类三个接口:
-
签发token接口、校验token、刷新token
注:jwt视图类签发token的接口会帮你完成登陆并签发token,但drf-jwt只完成了账号密码登录,我们还需要手机登录,邮箱登录,就需要去重写jwt序列化类签发token实现多方式登录
'''urls.py''' # 使用JWT认证组件实现好的视图 from rest_framework_jwt.views import ObtainJSONWebToken,obtain_jwt_token urlpatterns = [ # 使用JWT认证组件实现好的视图类来实现登陆认证 # url(r"jwt_login/$",ObtainJSONWebToken.as_view()) # jwt提供的简写形式 url(r"jwt_login/$",obtain_jwt_token), url(r"jwt_refresh/$",refresh_jwt_token), url(r"jwt_verify/$",verify_jwt_token), ]
drf全局配置jwt认证组件
# drf的配置
REST_FRAMEWORK = {
# 认证组件的全局配置
'DEFAULT_AUTHENTICATION_CLASSES':[
# jwt认证类
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
],
}
drf-jwt配置
# drf-jwt配置
import datetime
JWT_AUTH = {
# token过期时间
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),
# 允许刷新
# 'JWT_ALLOW_REFRESH': True,
# # 刷新后的最大过期时间
# 'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),
# 认证前缀
'JWT_AUTH_HEADER_PREFIX': 'JWT',
}
重写jwt序列化类签发token实现多方式登录
'''serializers.py'''
# 导入JWT认证
from rest_framework_jwt.serializers import jwt_payload_handler, jwt_encode_handler
import re
class LoginJWTModelSerializer(serializers.ModelSerializer):
username = serializers.CharField(write_only=True)
password = serializers.CharField(write_only=True)
class Meta:
model = models.UserInfo
fields = ('username', 'password')
# 在全局钩子中签发token
def validate(self, attrs):
# user = authenticate(**attrs)
# 账号密码登录 => 多方式登录
user = self._many_method_login(**attrs)
# 签发token,并将user和token存放到序列化对象中
payload = jwt_payload_handler(user) # 使用jwt认证模块,根据当前用户得到载荷
token = jwt_encode_handler(payload) # 使用jwt认证模块,得到token
self.user = user
self.token = token
return attrs
# 多方式登录
def _many_method_login(self, **attrs):
username = attrs.get('username')
password = attrs.get('password')
if re.match(r'.*@.*', username):
user = models.UserInfo.objects.filter(email=username).first()
elif re.match(r'^1[3-9][0-9]{9}$', username):
user = models.UserInfo.objects.filter(mobile=username).first()
else:
user = models.UserInfo.objects.filter(username=username).first()
if not user:
raise serializers.ValidationError({'username': '账号有误'})
if not user.check_password(password):
raise serializers.ValidationError({'password': '密码有误'})
return user
'''views.py'''
'''
jwt 模块实现 签发token
重写jwt序列化类签发token实现多方式登录
'''
class JWTLoginAPIView(APIView):
# 登陆 禁用认证和权限校验
authentication_classes = []
permission_classes = []
def post(self, request, *args, **kwargs):
ser_obj = serializers.LoginJWTModelSerializer(data=request.data)
ser_obj.is_valid(raise_exception=True)
return common.APIResponse(results={
"username": ser_obj.user.username,
"token" : ser_obj.token,
})
四、前后台分离模式下信息交互规则
"""
1)任何人都能直接访问的接口:
请求不管是get、还是post等,不需要做任何校验
2)必须登录后才能访问的接口:
任何请求方式都可能做该方式的限制,请求必须在请求头中携带认证信息 - authorization
3)前台的认证信息获取只能通过登录接口:
前台提供账号密码等信息,去后台换认证信息token
4)前台如何完成登录注销:
前台登录成功一般在cookie中保存认证信息token,分离注销就是前台主动清除保存的token信息
"""