JWT
"""
1、组成:
header.payload.signature 头.载荷.签名
2、距离:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6Im93ZW4iLCJleHAiOjE1NTgzMDM1NDR9.4j5QypLwufjpqoScwUB9LYiuhYcTw1y4dPrvnv7DUyo
3:介绍:
header:一般存放如何处理token的方式:加密的算法、是否有签名等
payload:数据的主体部分:用户信息、发行者、过期时间等
signature:签名:将header、payload再结合密码盐整体处理一下
"""
工作原理
"""
1) jwt = base64(头部).base64(载荷).hash256(base64(头部).base(载荷).密钥)
2) base64是可逆的算法、hash256是不可逆的算法
3) 密钥是固定的字符串,保存在服务器
"""
drf-jwt
官网
https://github.com/jpadilla/django-rest-framework-jwt
安装子:虚拟环境
pip install djangorestframework-jwt
使用:user/urls.py
from django.urls import path
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
path('login/', obtain_jwt_token),
]
测试接口:post请求
"""
postman发生post请求
接口:http://api.luffy.cn:8000/user/login/
数据:
{
"username":"admin",
"password":"admin"
}
"""
drf-jwt开发
配置信息:JWT_AUTH到dev.py中
import datetime
JWT_AUTH = {
# 过期时间
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
# 自定义认证结果:见下方序列化user和自定义response
'JWT_RESPONSE_PAYLOAD_HANDLER': 'user.utils.jwt_response_payload_handler',
}
序列化user:user/serializers.py(自己创建)
from rest_framework import serializers
from .models import User
class UserModelSerializer(serializers.ModelSerializer):
"""轮播图序列化器"""
class Meta:
model = User
fields = ["username", "mobile"]
自定义response:user/utils.py
from .serializers import UserModelSerializers
def jwt_response_payload_handler(token, user=None, request=None):
return {
'token': token,
'user': UserModelSerializer(user).data
}
# restful 规范
# return {
# 'status': 0,
# 'msg': 'OK',
# 'data': {
# 'token': token,
# 'username': user.username
# }
# }
基于drf-jwt的全局认证:user/authentications.py(自己创建)
import jwt
from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication
from rest_framework.authentication import get_authorization_header
from rest_framework_jwt.settings import api_settings
from rest_framework.exceptions import AuthenticationFailed
from rest_framework_jwt.authentication import jwt_decode_handler
class JSONWebTokenAuthentication(BaseJSONWebTokenAuthentication):
def authenticate(self, request):
# 利用drf获取认证的token,来自请求头的Authorization字段
jwt_value = get_authorization_header(request)
# 自定义从请求头的某个字段得到认证的token
# jwt_value = request.META.get('HTTP_TOKEN', b'')
# 反扒策略
jwt_value_list = jwt_value.split()
if len(jwt_value_list) != 2:
raise AuthenticationFailed('太长或太短,认证失败')
if jwt_value_list[0].lower().decode() != api_settings.JWT_AUTH_HEADER_PREFIX.lower():
raise AuthenticationFailed('没头,认证失败')
jwt_value = jwt_value_list[1]
try:
payload = jwt_decode_handler(jwt_value)
except jwt.ExpiredSignature:
raise AuthenticationFailed('过期了,认证失败')
except jwt.InvalidTokenError:
raise AuthenticationFailed('非法用户,认证失败')
user = self.authenticate_credentials(payload)
return (user, jwt_value)
全局启用:settings/dev.py
REST_FRAMEWORK = {
# 认证模块
'DEFAULT_AUTHENTICATION_CLASSES': (
'user.authentications.JSONWebTokenAuthentication',
),
}
局部启用禁用:任何一个cbv类首行
# 局部禁用
authentication_classes = []
# 局部启用
from user.authentications import JSONWebTokenAuthentication
authentication_classes = [JSONWebTokenAuthentication]
多方式登录:user/utils.py
from django.contrib.auth.backends import ModelBackend
from .models import User
import re
class JWTModelBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
"""
:param request:
:param username: 前台传入的用户名
:param password: 前台传入的密码
:param kwargs:
:return:
"""
try:
if re.match(r'^1[3-9]d{9}$', username):
user = User.objects.get(mobile=username)
elif re.match(r'.*@.*', username):
user = User.objects.get(email=username)
else:
user = User.objects.get(username=username)
except User.DoesNotExist:
return None # 认证失败就返回None即可,jwt就无法删除token
# 用户存在,密码校验通过,是活着的用户 is_active字段为1
if user and user.check_password(password) and self.user_can_authenticate(user):
return user # 认证通过返回用户,交给jwt生成token
配置多方式登录:settings/dev.py
AUTHENTICATION_BACKENDS = ['user.utils.JWTModelBackend']
手动签发JWT:了解 - 可以拥有原生登录基于Model类user对象签发JWT
from rest_framework_jwt.settings import api_settings
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
# 了解,原生视图
# 原生APIView可以实现手动签发 jwt
class LoginAPIView(APIView):
def post(self):
# 完成手动签发
pass