认证组件

简单实例

settings.py

INSTALLED_APPS = [
    'rest_framework',
]

urls.py

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/auth/',views.AuthView.as_view()),
]

models.py

from django.db import models

class UserInfo(models.Model):
    USER_TYPE = (
        (1,'普通用户'),
        (2,'VIP'),
        (3,'SVIP')
    )

    user_type = models.IntegerField(choices=USER_TYPE)
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=64)

class UserToken(models.Model):
    user = models.OneToOneField(UserInfo,on_delete=models.CASCADE)
    token = models.CharField(max_length=64)

views.py

from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
from rest_framework.views import APIView
from API import models
from rest_framework.request import Request
from rest_framework import exceptions
from rest_framework.authentication import BasicAuthentication

ORDER_DICT = {
    1:{
        'name':'apple',
        'price':15
    },
    2:{
        'name':'dog',
        'price':100
    }
}

def md5(user):
    import hashlib
    import time
    #当前时间,相当于生成一个随机的字符串
    ctime = str(time.time())
    m = hashlib.md5(bytes(user,encoding='utf-8'))
    m.update(bytes(ctime,encoding='utf-8'))
    return m.hexdigest()

class AuthView(object):
    '''用于用户登录验证'''
    def post(self,request,*args,**kwargs):
        ret = {'code':1000,'msg':None}
        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:
                ret['code'] = 1001
                ret['msg'] = '用户名或密码错误'
            #为用户创建token
            token = md5(user)
            #存在就更新,不存在就创建
            models.UserToken.objects.update_or_create(user=obj,defaults={'token':token})
            ret['token'] = token
        except Exception as e:
            ret['code'] = 1002
            ret['msg'] = '请求异常'
        return JsonResponse(ret)


class Authentication(APIView):
    '''认证'''
    def authenticate(self,request):
        token = request._request.GET.get('token')
        token_obj = models.UserToken.objects.filter(token=token).first()
        if not token_obj:
            raise exceptions.AuthenticationFailed('用户认证失败')
        #在rest framework内部会将这两个字段赋值给request,以供后续操作使用
        return (token_obj.user,token_obj)

    def authenticate_header(self, request):
        pass

class OrderView(APIView):
    '''订单相关业务'''

    authentication_classes = [Authentication,]    #添加认证
    def get(self,request,*args,**kwargs):
        #request.user
        #request.auth
        ret = {'code':1000,'msg':None,'data':None}
        try:
            ret['data'] = ORDER_DICT
        except Exception as e:
            pass
        return JsonResponse(ret)

总结:

	-写一个认证类(继承BaseAuthentication)
		-重写authenticate方法,把request对象传入
		-能从request对象中取出用户携带的token,根据token判断是否登录过
		-如果登录过,返回两个值 user对象,token对象
		-如果没有登录过抛异常
	-全局使用
		-在settings中配置
			REST_FRAMEWORK={
                "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",]
                }
	-局部使用
		-在视图类中配置:
			authentication_classes=[Authentication,]
	-局部禁用:
		-在视图类中配置:
			authentication_classes=[]

  

认证源码分析

-APIView中的dispatch  --->  self.initial(认证,频率,权限) --->   self.perform_authentication(认证)  --->   本质又调用了新的request对象的user方法
  -->  request.user内部执行了:self._authenticate(注意self是新的request对象)  --->   循环拿到一个个认证类的对象,执行对象的authenticate方法,传入request对象
--->   一个个认证类的对象是在reuqest对象实例化的时候传入的   --->   APIView中的get_authenticators,通过列表推导式生成一个个的认证类对象,然后传入request对象中

 

posted @ 2019-07-04 18:32  hengshan  阅读(196)  评论(0编辑  收藏  举报