jwt自定义表签发
自定义表时,用模块实现签发
在models.py中
username必须为username
class MyUser(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=32)
email = models.CharField(max_length=32)
phone = models.IntegerField(max_length=32)
gender = models.IntegerField(choices=((1, '男'), (2, '女'), (0, '未知')))
在视图类中
from rest_framework.views import APIView
from .models import MyUser
from rest_framework.response import Response
from rest_framework_jwt.settings import api_settings
# 从rest_framework_jwt中
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
class UserView(APIView):
def post(self, request):
username = request.data.get('username')
password = request.data.get('password')
user = MyUser.objects.filter(username=username, password=password).first()
if user:
#1 通过user生成payload---》jwt 提供一个方法(username),传入user,返回payload
payload = jwt_payload_handler(user)
#2 生成token---》jwt提供了方法,把payload放入--》token
token = jwt_encode_handler(payload)
return Response({'code': 100, 'msg': '登录成功', 'token': token, 'username': user.username})
else:
return Response({'code': 101, 'msg': '用户密码错误'})
jwt 多方式登录
要求:
- 用户名+密码 邮箱+密码 手机号+密码 都可以登录
username+password
email+password
phone+password
无论是username,email,phone都以 username形式提交到后端
于是:从username字段中取出来的,可能是用户名,可能是邮箱,可能是密码—》都能登录成功
基于APIView用auth拓展表多登陆
class UserView(APIView):
def post(self, request):
username = request.data.get('username')
password = request.data.get('password')
# 电话号码+密码登录
if re.match(r'^1[3-9][0-9]{9}$', username):
user = User.objects.filter(phone=username).first()
# 邮箱+密码登录
elif re.match(r'^.+@.+$', username):
user = User.objects.filter(email=username).first()
# 用户名+密码
else:
user = User.objects.filter(username=username).first()
if user and user.check_password(password):
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
return Response({'code': 100, 'msg': '登录成功', 'token': token, 'username': user.username})
else:
return Response({'code': 101, 'msg': '用户密码错误'})
使用序列化类多方式登录
在视图类中
from rest_framework.viewsets import GenericViewSet
from rest_framework.response import Response
from rest_framework.decorators import action
from .serializer import UserSerializer
class UserView(GenericViewSet):
@action(methods=['POST'], detail=False)
def login(self, request):
ser = UserSerializer(data=request.data)
if ser.is_valid():
token = ser.context.get('token')
username = ser.context.get('username')
return Response({'code': 100, 'msg': '登录成功', 'token': token, 'username': username})
else:
return Response({'code': 101, 'msg': '用户密码错误'})
在序列化类中
from rest_framework import serializers
from .models import User, MyUser
import re
from rest_framework.exceptions import ValidationError
from rest_framework_jwt.settings import api_settings
# 从rest_framework_jwt中
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
class UserSerializer(serializers.ModelSerializer):
username = serializers.CharField()
class Meta:
model = MyUser
fields = ['username', 'password']
def _get_user(self, attrs):
username = attrs.get('username')
password = attrs.get('password')
# 电话号码+密码登录
if re.match(r'^1[3-9][0-9]{9}$', username):
user = User.objects.filter(phone=username).first()
# 邮箱+密码登录
elif re.match(r'^.+@.+$', username):
user = User.objects.filter(email=username).first()
# 用户名+密码
else:
user = User.objects.filter(username=username).first()
if user and user.check_password(password):
return user
else:
raise ValidationError('用户密码错误')
def _get_token(self, attrs):
payload = jwt_payload_handler(attrs)
token = jwt_encode_handler(payload)
return token
def validate(self, attrs):
user = self._get_user(attrs)
token = self._get_token(attrs)
self.context['token'] = token
self.context['username'] = user.username
return attrs
基于自定义表编写认证类
每次访问需要登录的接口,都会去查数据库
所以咱们可以做优化
- 自己生成一个user对象
- 直接返回user_id,以后用的时候,再查数据库
认证类
from rest_framework.authentication import BaseAuthentication
from rest_framework_jwt.settings import api_settings
from django.utils.translation import ugettext as _
from rest_framework.exceptions import AuthenticationFailed
from .models import MyUser
import jwt
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
class LoginAuth(BaseAuthentication):
def authenticate(self, request):
token = request.META.get('HTTP_TOKEN')
try:
payload = jwt_decode_handler(token)
user = MyUser.objects.filter(pk=payload.get('id'))
except jwt.ExpiredSignature:
msg = _('Signature has expired.')
raise AuthenticationFailed(msg)
except jwt.DecodeError:
msg = _('Error decoding signature.')
raise AuthenticationFailed(msg)
except jwt.InvalidTokenError:
raise AuthenticationFailed('未知错误,请联系管理员')
return user, token
视图类
from rest_framework.response import Response
from .models import Book
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from rest_framework.decorators import action
from .serializer import UserSerializer, BookSerializer
class UserView(GenericViewSet):
@action(methods=['POST'], detail=False)
def login(self, request):
ser = UserSerializer(data=request.data)
if ser.is_valid():
token = ser.context.get('token')
username = ser.context.get('username')
return Response({'code': 100, 'msg': '登录成功', 'token': token, 'username': username})
else:
return Response({'code': 101, 'msg': '用户密码错误'})
from .auth import LoginAuth
class BookView(ModelViewSet):
authentication_classes = [LoginAuth]
queryset = Book.objects.all()
serializer_class = BookSerializer