Django实现微信商城小程序后端-token登录验证

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
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值