model
用户表包含了常用的基本信息
# 用户信息表
class User(models.Model):
id = models.AutoField(primary_key=True)
username = models.CharField(max_length=32, unique=True, verbose_name='姓名', default='')
# gender_choices = ((0,'女'), (1, '男'), (-1, '无'))
gender = models.CharField(max_length=16, verbose_name='性别', default='未知')
age = models.PositiveIntegerField()
phone_number = models.CharField(max_length=16, unique=True, verbose_name='手机号')
email = models.EmailField(unique=True, verbose_name='邮箱')
password = models.CharField(max_length=64, verbose_name='密码')
create_time = models.DateTimeField(auto_now_add=True)
update_time = models.DateTimeField(auto_now=True)
id_delete = models.BooleanField(default=False)
class meta:
db_table = 'user'
verbose_name = '用户'
verbose_name_plural = '用户'
def __str__(self):
return self.username
view
逻辑处理是根据用户登录名密码进行验证的
authentication_classes = [LoginAuth] # token验证,这个参数需要放到需要的视图里就可以实现token校验了
from django.shortcuts import render, HttpResponse, redirect
from django.views import View
from django.core.cache import cache
from rest_framework import viewsets, views
from rest_framework.response import Response
from .auth import LoginAuth
from .models import *
from .util import uuid4, pwd_hash, info, JwtToken
from .serializers import UserSerializer
class Login(views.APIView):
authentication_classes = [LoginAuth] # token验证
# post请求
def post(self, request):
try:
data = request.data # 获取接收的参数
password = data.pop('password') # 抽离出密码
data['password'] = pwd_hash(password) # Hash密码,不存储明文密码
user = User.objects.filter(**data,id_delete=False).values().first() # 查询 没有删除的用户
user_ser = UserSerializer(data=user) # 序列化数据
user_ser.is_valid() # 序列化返回值校验
# 判断是否存在该用户
if user:
# 生成token
jwt_token = JwtToken()
token = jwt_token.encode_token(dict(user_ser.data))
# 将数据转换成dict类型,并添加token到返回数据中
data = dict(user_ser.data)
data['token'] = token
# 返回数据
return info(data=data)
return info(status=0, message='用户名或密码错误')
except Exception as e:
return info(status=0, message='服务器内部错误')
serializers
from .models import *
from rest_framework import serializers, status
from .util import pwd_hash
import re
# 密码验证
def my_validate(val):
try:
re.search('[A-Z]+', val).group()
except:
raise serializers.ValidationError('密码应包含大写字母')
if len(val) < 8:
raise serializers.ValidationError('密码应大于8位')
# return Response('密码太短')
class UserSerializer(serializers.ModelSerializer):
def create(self, validated_data):
print(validated_data)
password = validated_data.pop('password')
validated_data['password'] = pwd_hash(password)
user_obj = User.objects.create(**validated_data)
return user_obj
class Meta:
model = User
fields = ['username', 'gender', 'age', 'phone_number', 'email']
extra_kwargs = {'password': {'write_only': True, "validators": [my_validate]}}
权限校验
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from django.utils.timezone import now
from django.core.cache import cache
from .util import JwtToken
import time
# jwt自定义验证
# 登录认证
class LoginAuth(BaseAuthentication):
def authenticate(self, request):
# print('auth--data', request.META.get('HTTP_AUTHORIZATION'))
try:
# 获取请求头里的token
token = request.META.get('HTTP_AUTHORIZATION', None)
# 解密解签token
jwt_token = JwtToken()
jwt_token.decode_token(data=token)
# token过期抛出异常
except jwt.exceptions.JWTDecodeError:
raise AuthenticationFailed({"code": 1020, "error": "token过期"})
# 遇到错误的token,或者未携带token,会抛出异常
except:
raise AuthenticationFailed({"code": 1020, "error": "错误的token或未携带token"})
urls
from django.urls import path
from .views import Login
urlpatterns = [
path('login', Login.as_view()),
]
使用的工具啥的,都在这个utils里边了
from uuid import uuid4
import hashlib
import time
import os
from rest_framework.response import Response
from jwt import JWT, jwk_from_dict, jwk_from_pem
from datetime import datetime, timedelta, timezone
from jwt.utils import get_int_from_datetime
#pub_key、pri_key使用下面这个网址生成,然后直接粘贴进来就ok了
#https://mkjwk.org/?spm=a2c4g.11186623.2.20.2aed167chumlVx
# 根据用户传递的值用私钥加密,签名,公钥解密、解签
class JwtToken:
pub_key = {
}
pri_key = {
}
def encode_token(self, data):
# with open("./pri.pem", 'rb') as f:
# jwk_from_pem(f.read())
signing_key = jwk_from_dict(self.pri_key)
instance = JWT()
print(signing_key.to_dict())
data['iat'] = get_int_from_datetime(datetime.now(timezone.utc))
data['exp'] = get_int_from_datetime(datetime.now(timezone.utc) + timedelta(hours=1))
# print(data)
return instance.encode(payload=data, key=signing_key, alg='RS256')
def decode_token(self, data):
verifying_key = jwk_from_dict(self.pub_key)
instance = JWT()
return instance.decode(data, verifying_key, do_time_check=True)
# 哈希密码
def pwd_hash(val):
slat = 'zheshiyan'
md5 = hashlib.md5()
# print(val, slat)
md5.update((val+slat).encode('utf-8'))
return md5.hexdigest()
#重写返回值格式
def info(data='', status=1, message='', headers=None):
res = Response()
res.data = {
'status': status,
'message': message,
'data': data
}
if headers:
for k, v in headers.items():
res[k] = v
return res