rest-framework 自定义用户登录认证

之前的文章有写过通过jwt认证的文章,今天这一篇是通过自定义用户认证的;

使用场景:有些API需要用户登录成功之后,才能访问;有些无需登录就能访问

解决方法:创建两张表,一张用户表,一张token表,保存用户登录成功后生产的token;
         然后需要认证的视图,前台每次请求需要在请求头中携带token,后端然后对token进行验证

缺点:每个用户登录一次就需要生成一条token记录保存在数据库里,当用户量大的时候,就会增加后台服务器压力!

 

模型类 

from django.contrib.auth.hashers import make_password, check_password
from django.db import models


# Create your models here.
class User(models.Model):
    """
    用户模型类
    """
    username = models.CharField(max_length=32,verbose_name='用户名')
    password = models.CharField(max_length=64,verbose_name='密码')
    mobile = models.CharField(max_length=11,unique=True,verbose_name='手机号')

    class Meta:
        db_table = 'user'
        verbose_name = "用户信息表"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.username

    def set_password(self,password):
        self.password = make_password(password)
        return None

    def check_pwd(self,password):
        return check_password(self.password,password)


class UserToken(models.Model):
    """用户token表"""
    user = models.OneToOneField(User)  # 与用户一对一关系
    token = models.CharField(max_length=64,verbose_name='token')

    class Meta:
        db_table = 'token'
        verbose_name = 'token表'
        verbose_name_plural = verbose_name

 

 

一 views  views.py 视图

from django.shortcuts import render

# Create your views here.
from rest_framework.generics import  CreateAPIView, ListAPIView
from rest_framework.response import Response
from rest_framework.views import APIView

from .utils import md5
from . import models
from . import ser

class UserLogin(APIView):
    '用户登录视图类'
    authentication_classes = []
    # 登录不需要认证
    def post(self,request):
        username = request.POST.get('username').strip()
        pwd = request.POST.get('password').strip()
        if not all([username,pwd]):
            return Response({'info':'参数不完整','code':400})
        user = models.User.objects.get(username=username)
        user.check_pwd(pwd)
        # 登录成功后生成token
        token =md5(username)
        models.UserToken.objects.update_or_create(user=user,defaults={'token':token})
        res = {'info':'success','token':token,'code':200}
        res['data'] = ser.UserInfoSer(user).data
        return Response(res)


class UserRegister(CreateAPIView):
    """用户注册视图"""
    authentication_classes = []
    # 用户注册不需要认证
    serializer_class = ser.CreateUserSer


class UserInfoList(ListAPIView):
    """用户详情页视图"""
    serializer_class = ser.UserInfoSer
    queryset = models.User.objects.all()



        


 

二.序列化器  新建ser.py文件

from rest_framework import serializers

from . import  models

class CreateUserSer(serializers.ModelSerializer):
    """新增用户序列化器"""
    password2 = serializers.CharField(max_length=64,write_only=True)
    mobile = serializers.CharField(max_length=11,min_length=11,write_only=True)

    def validate(self, attrs):
        password = attrs['password']
        password2 = attrs['password2']
        if password != password2:
            raise serializers.ValidationError('两次密码不一致,请重新输入!')
        return attrs

    def validate_mobile(self,value):
        import re
        if not re.match(r'1[3-9]\d{9}',value):
            raise serializers.ValidationError('手机号格式不正确请重新输入!')
        return value

    def create(self, validated_data):
        del validated_data['password2']
        user = super().create(validated_data)
        user.set_password(validated_data['password'])
        user.save()
        return user

    class Meta:
        model = models.User
        fields = '__all__'


class UserInfoSer(serializers.ModelSerializer):
    """用户详情信息序列化器"""
    class Meta:
        model = models.User
        fields = ('id','username','mobile')

三  新建utils 文件,定义MD5加密方法

import hashlib
import time

def md5(user):
    """md5 加密token"""

    ctime = str(time.time())
    m = hashlib.md5(bytes(user, encoding='utf-8'))
    m.update(bytes(ctime, encoding='utf-8'))
    return m.hexdigest()

四  新建auth文件   重写认证类 自定义认证方法

from rest_framework import exceptions
from rest_framework.authentication import BaseAuthentication

from .import models


class Authtication(BaseAuthentication):

    def authenticate(self, request):
        try:
            token = request.META.get('HTTP_AUTHORIZATION',None)
        except:
            raise exceptions.AuthenticationFailed('用户认证失败')
        token = token.split(' ')[1]
        print(token)
        token_query = models.UserToken.objects.filter(token = token)
        if not token_query:
            raise exceptions.AuthenticationFailed('无效的token')
        # 返回(当前登录对象,token)
        return (token_query.first().user,token_query.first())

    def authenticate_header(self, request):
        return 'Basic realm="user"'

五 settings 配置文件

REST_FRAMEWORK = {
    # 全局使用的认证类
    "DEFAULT_AUTHENTICATION_CLASSES": ['users.auth.Authtication', ],
    "UNAUTHENTICATED_USER": None,
    "UNAUTHENTICATED_TOKEN": None,
    "DEFAULT_RENDERER_CLASSES": [
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
    ]
}

总路由:

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^users/', include('users.urls')),
]

分路由:

from django.conf.urls import include, url
from django.contrib import admin

from . import views
urlpatterns = [
    url(r'^register/$',views.UserRegister.as_view()),
    url(r'^login/$',views.UserLogin.as_view()),
    url(r'^list/$',views.UserInfoList.as_view()),
]

用户注册 测试:

 

 

用户登录测试:

 

用户详情页测试:

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值