drf_jwt
Posted changwenjun-666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了drf_jwt相关的知识,希望对你有一定的参考价值。
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) 密钥是固定的字符串,保存在服务器
官网:https://github.com/jpadilla/django-rest-framework-jwt
安装:pip install djangorestframework-jwt
使用:一般是搭配xadmin去实现后台管理
获得token:
在user/url.py里: from django.urls import path from rest_framework_jwt.views import obtain_jwt_token urlpatterns = [ path(‘login/‘, obtain_jwt_token), ] 利用postman测试发射post请求: 接口:http://127.0.0.1:8000/user/login/ 数据: "username":"admin", "password":"admin"
可能存在一些问题: Unable to log in with provided credentials 原因是这种算法内部是需要使用auth_user表去获取用户的账号和密码数据的,而我们没有创建相关的数据,因此需要创建一些数据: python manage.py createsuperuser
再次尝试:得到token值:
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFkbWluIiwiZXh
wIjoxNTY5MjAyODc1LCJlbWFpbCI6IjEzMDYzNDczMzgwQDE2My5jb20ifQ.JgbSItmx0sa4JHuA5I4J58gcoeCgTLKZaPj0T-f5OwI"
虽说拿到了后端生成的token值,可怎么让其真正的实现认证功能呢:
在settinngs.py里配置jwt的相关数据 import datetime JWT_AUTH = # 过期时间 ‘JWT_EXPIRATION_DELTA‘: datetime.timedelta(days=1), # 自定义认证类 ‘JWT_RESPONSE_PAYLOAD_HANDLER‘: ‘user.utils.jwt_response_payload_handler‘,
序列化组件 user/serializers.py from rest_framework import serializers from .models import User class UserModelSerializer(serializers.ModelSerializer): """轮播图序列化器""" class Meta: model = User fields = ["username", "mobile"] 需要注意的是:User这张表继承的是 from django.contrib.auth.models import AbstractUser ,因为jwt内部走的是auth_user这张表。 同时还需要在配置里将 AUTH_USER_MODEL = ‘app的名字.User‘ 添加上,表示重写了auth的认证表 同时:因为重写了auth表,需要删除一些迁移记录文件:django/contrib/admin/migrations django/contrib/auth/migrations xadmin/migrations 如果使用xadmin作为后台管理使用 reversion/migrations 同上 user/migrations
在user/models.py下: from django.db import models # Create your models here. from django.contrib.auth.models import AbstractUser class User(AbstractUser): mobile = models.CharField(max_length=32,default=0) age = models.IntegerField(default=0)
自定义response的返回结果: user/utils.py from .serializers import UserModelSerializers def jwt_response_payload_handler(token, user=None, request=None): return ‘token‘: token, # 拿到的是一个序列化后的对象,多个对象加上many=True ‘user‘: UserModelSerializer(user).data # restful 规范 # return # ‘status‘: 0, # ‘msg‘: ‘OK‘, # ‘data‘: # ‘token‘: token, # ‘username‘: user.username # #
上述操作完成了jwt的自定义返回值,现在需要实现的是jwt全局认证,基于drf的认证组件实现
import jwt from rest_framework.exceptions import AuthenticationFailed from rest_framework_jwt.authentication import jwt_decode_handler from rest_framework_jwt.authentication import get_authorization_header from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication class JSONWebTokenAuthentication(BaseJSONWebTokenAuthentication): def authenticate(self, request): # 下面的 token获取,可以直接 request.META.get()去获取 token = get_authorization_header(request) # 可以在此处 对请求头的字段做出一些限制,实现反扒 if not token: raise AuthenticationFailed(‘Authorization字段是必须的‘) try: payload = jwt_decode_handler(token) except jwt.ExpiredSignature: raise AuthenticationFailed(‘签名过期‘) except jwt.DecodeError: raise AuthenticationFailed(‘错误的解码签名‘) except jwt.InvalidTokenError: raise AuthenticationFailed(‘非法用户‘) user = self.authenticate_credentials(payload) return (user, token)
当然了,需要在settings.py里完成相关配置:全局启用
EST_FRAMEWORK = # 认证模块 ‘DEFAULT_AUTHENTICATION_CLASSES‘: ( ‘user.authentications.JSONWebTokenAuthentication‘, ), 需要知道,drf_jwt是基于drf框架实现的
局部启用禁用:任何一个cbv类首行 # 局部禁用 authentication_classes = [] # 局部启用 from user.authentications import JSONWebTokenAuthentication authentication_classes = [JSONWebTokenAuthentication]
上述操作时针对于用户密码而言的,如果是多方式登陆如何利用jwt实现呢?
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]\d9$‘, 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.py AUTHENTICATION_BACKENDS = [‘user.utils.JWTModelBackend‘]
以上是关于drf_jwt的主要内容,如果未能解决你的问题,请参考以下文章