Django rest framework 之认证

一、基于token进行用户认证

1、url

from django.conf.urls import url
from api.apiview import apiview
urlpatterns = [    

  url(r'^(?P<version>[v1|v2]+)/login_api/$', apiview.Login.as_view()),
]
复制代码

2、models

创建两张表,一个存用户信息,一个存用户登录后的token

from django.db import models

class user_info(models.Model):
  username = models.CharField(max_length=32,unique=True,verbose_name='用户名')
  password = models.CharField(max_length=32,verbose_name='密码')
  nickname = models.CharField(max_length=32,verbose_name='昵称')

class UserToken(models.Model):
    time = models.DateTimeField(auto_now=True)
    user = models.OneToOneField(to='user_info',on_delete=None)
    token = models.CharField(max_length=64)

 

3、views

apiview.py

from django.shortcuts import HttpResponse
from utils.response import BaseResponsefrom api import models
import json
import time

class Login(object):
    def post(self,request,*args,**kwargs):
        response = BaseResponse()
        try:
            user = request._request.POST.get('username')
            pwd = request._request.POST.get('password')
            obj = models.UserInfo.objects.filter(username=user,password=pwd).first()
            
            if not obj:
                response.code = 400000
                response.error = {
            'username':'用户名或密码错误'

          }
          response.message = '参数错误'
        return HttpResponse(json.dumps(response.__dict__)) token_obj = Token() token = token_obj.CreateToken(user) models.UserToken.objects.update_or_create(user=user,defaults={'token':token,'time':time.time()}) response.data = { 'token':token, 'username':user, 'password':pwd } except Exception as e: response.error = str(e) response.code = 400001 response.message = '请求异常' return HttpResponse(json.dumps(response.__dict__))

token.py

from web import models
import time
from datetime import datetime
import hashlib

class Token(object):
    def CreateToken(self,user):
        '''
        创建token username + 时间戳 转换为md5
        :param user:
        :return:
        '''
        ctime = str(time.time())
        token = hashlib.md5(bytes(user, encoding='utf-8'))
        token.update(bytes(ctime, encoding='utf-8'))
        return token.hexdigest()

response.py

class BaseResponse(object):
    def __init__(self):
        self.message = 'OK!'
        self.data = None
        self.error = None
        self.code = 200

 

使用postman进行测试

如果用户名和密码正确,会生成token,下次登录时,token的值会更新

 

 

当用户名密码错误时,抛出异常

 二、使用 Django rest framework认证组件

1.settings

先将rest_framework添加到settings的app里

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'api',   #我自己注册的APP
    'rest_framework',   #添加restframework
]

2.url

from django.conf.urls import url
from api.apiview import apiview

urlpatterns = [    

  url(r'^(?P<version>[v1|v2]+)/login_api/$', apiview.Login.as_view()),
  url(r
'^(?P<version>[v1|v2]+)/userinfo/$', apiview.UserInfo.as_view()), ]

3.views

apiviews.py

from django.shortcuts import HttpResponse
from utils.response import BaseResponse
from api import models
from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
from rest_framework.views import APIView
import json
import time

class MyAuthenticate(BaseAuthentication):
    # 添加自己的认证逻辑,基类BaseAuthentication中有两个必须要重写的接口

    def authenticate(self, request):
        token = request._request.GET.get('token')  # 获取token参数
        token_obj = models.UserToken.objects.filter(token=token).first()  # 在UserToken表中找到对应的对象
        
        if not token_obj:  #如果没有,抛出异常
            raise exceptions.AuthenticationFailed('用户认证失败')
        
        return (token_obj.user, token_obj)  # 将这两个对象分别给request.user,request.auth
  
    def authenticate_header(self, request):  # 返回相应头信息
          pass



class UserInfo(APIView):

    authentication_classes = [MyAuthenticate] #添加局部验证
    
    def get(self, request, *args, **kwargs):
        response = BaseResponse()
        try:
            value_list = ['username','password','nickname']
            users = models.user_info.objects.values(*value_list)
            result = list(users)
            response.data = {
                'users':result
            }            
         except Exception as e:
            response.error = str(e)
            response.code = 400001
            response.message = '请求异常'
            
        return HttpResponse(json.dumps(response.__dict__))

使用Postman进行测试

 

 三、认证组件源码分析

1.当请求进入路由时,进行的一系列操作

(1)路由匹配时,执行类的as_view方法

 

 (2)然后找到APIView中的as_view方法,然后发现他执行了父类的as_view方法

 

 (3)接着找到View中的as_view方法,发现他执行dispatch方法,接着去子类APIView中找到dispatch方法

 

 

 (4)在dispatch方法中,首先对request进行封装、认证还有通过反射执行不同的方法

 

 2.封装request

(1)我们进入initialize_request(),发现对原生request和认证类等进行封装

(2)进入get_authenticators后,发现是一个列表生成式

 

 

(3)进入authentication_classes,可以看到authentication_classes字段,这个字段默认去配置文件中获取

 

posted on 2020-02-25 16:38  syyw  阅读(240)  评论(0)    收藏  举报