django JWT认证
介绍
项目为前后端分离,采用JWT认证;业务需求采用自定义user
版本:
django-restframework-jwt: 1.11.*
settings.py配置
REST_FRAMEWORK = {
'DEFFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',),
'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework_jwt.authentication.JSONWebTokenAuthentication',),
}
import datetime
JWT_AUTH = {
# 配置jwt过期时间
'JWT_EXPIRATION_DELTA': datetime.timedelta(hours=12)
# 自定义返回内容,需要在user/utils/jwt_respone/目录下新建jwt_response_payload_handler.py
'JWT_RESPONSE_PAYLOAD_HANDLER': 'user.utils.jwt_respone.jwt_response_payload_handler',
}
自定义User模型
django自带user模型不适合项目,所以自定义了
models.py
from django.db import models
from django.contrib.auth.hashers import check_password, make_password
class User(models.Model):
real_name = models.CharField(verbose_name='姓名', max_length=64,)
username = models.CharField(verbose_name='用户名', max_length=32, unique=True)
password = models.CharField(verbose_name='密码', max_length=256)
class Meta:
verbose_name = '用户'
verbose_name_plural = verbose_name
# 加密密码
def set_password(self, raw_password):
self.password = make_password(raw_password)
self._password = raw_password
# 检验密码
def check_password(self, raw_password):
def setter(raw_password):
self.set_passsword(raw_password)
self._password = None
self.save(update_fields=["password"])
return check_password(raw_password, self.password, setter)
@property
def is_authenticated(self):
return True
创建认证链接(urls.py)
from user.views.jwt_token import JWT
urlpatterns = [
path('jwt-token-auth/',JWT.as_view())
]
自定义认证视图(JWT)
jwt_token.py
from rest_framework_jwt.views import JSONWebTokenAPIView
# 重写原序列化类
from user.serializers.jwt_token import JSONWebTokenSerializer
class JWT(JSONWebTokenAPIView):
serializer_class = JSONWebTokenSerializer
重新认证序列化(JSONWebTokenSerializer)
这里主要重写了原JSONWebTokenSerializer类中的 authenticate函数(可以看下源码,很简单),我这里是直接替换自己的authenticate函数
from user.utils.username_auth_backend import authenticate
小技巧:
如果前端需要传入更多的信息,建议在JSONWebTokenSerializer中 init()函数下添加字段,validate()函数中同样添加
自定义authenticate函数
这里使用自定义User model验证
from user.models import User
def authenticate(username=None, password=None):
try:
user = User.objects.get(username=username)
if user.check_password(password):
return user
except Exception as e:
rasie e
自定义返回内容(jwt_response_payload_handler)
认证成功后返回内容(用户基本信息,权限等)
from user.models import User
def jwt_response_payload_handler(token,user=None,request=None):
obj = User.objects.get(username=user)
return {
'token': token,
'real_name': user.real_name,
'status': 'ok',
}
用户创建更新
from rest_framework import viewsets
from rest_framework.mixins import CreateModelMixin,UpdateModelMixin,RetrieveModelMixin,ListModelMixin,GenericViewSet
from rest_framework import permissions
from user.utils.authentication import JSONWebTokenAuthentication
from user.serializers.user import UserSerializer
from user.models import User
class UserViewSet(CreateModelMixin,UpdateModelMixin,RetrieveModelMixin,ListModelMixin,GenericViewSet)
serializer_class = UserSerializer
queryset = User.objects.all()
authentication_class = (JSONWebTokenAuthentication,)
def get_permissions(self):
"""
那些请求验证token
"""
if sel.action != 'create':
return [permissions.IsAuthenticated()]
else:
return []
创建User序列化
UserSerializer.py
from rest_framework import serializers
from rest_framework_jwt.settings import api_settings
from user.models import User
class UserSerializer(serializers.ModelSerializer):
token = serializers.CharField(label='登录后TOKEN',read_only=True)
password = serializers.CharField(label='密码',write_only=True)
class Meta:
model=User
fields = ('id','username','token')
def create(self,validated_data):
user = super().create(validated_data)
# 调用django的加密密码
user.set_password(validated_data['password'])
user.save()
# 生成token
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)
user.token = token
return user
def update(self,instance,validated_data):
serializers.raise_errors_on_nested_writes('update',self,validated_data)
instance.set_password(validated_data['password'])
instance.save()
return instance
重写JSONWebTokenAuthentication
基本功能都和原生一样,由于JWT默认使用django 自带user模型,这里只需要修改user为自定义user.
authentication.py
1.重写了原来BaseJSONWebTokenAuthentication类中authenticate、authenticate_credentials函数中user
2.JSONWebTokenAuthentication类和原码功能一样,只是继承了新的BaseJSONWebTokenAuthentication类