rest-framework:认证组件

一 认证简介:

  只有认证通过的用户才能访问指定的url地址,比如:查询课程信息,需要登录之后才能查看,没有登录,就不能查看,这时候需要用到认证组件

二 局部使用

models.py

class User(models.Model):
    name=models.CharField(max_length=32)
    pwd=models.CharField(max_length=64)
    user_type=models.IntegerField(choices=((1,"超级管理员"),(2,"普通管理员"),(3,"2b用户")),default=3)
#跟User表做一对一关联
class Token(models.Model):
    user=models.OneToOneField(to='User')
    token = models.CharField(max_length=64)

 新建认证类(验证通过return两个参数)

rom rest_framework.authentication import BaseAuthentication
from app01 import models
from rest_framework.exceptions import AuthenticationFailed
from rest_framework.permissions import BasePermission
class MyAuth(BaseAuthentication):
    def authenticate(self,request):
        #写一些认证的逻辑
        # print('我是认证类中的方法,只要配置了,一定会走我')
        token=request.GET.get('token')
        token_obj=models.Token.objects.filter(token=token).first()
        if token_obj:
            #有值表示登录了
            #token_obj.user 当前登录的user对象
            return token_obj.user,token_obj
        else:
            #没有值,表示没有登录,抛异常
            raise AuthenticationFailed('您没有登录')
class MyPermision(BasePermission):
message = '不是超级用户,查看不了'
def has_permission(self,request,view):
if request.user.user_type==1:
return True
else:
return False

 view层:

from django.shortcuts import render,HttpResponse

# Create your views here.

from rest_framework.views import  APIView
from rest_framework.response import Response
from rest_framework.request import Request
from django.core.exceptions import ObjectDoesNotExist
from app01 import  models
from rest_framework.exceptions import AuthenticationFailed
import uuid
from rest_framework.authentication import BaseAuthentication

from app01.MyAuths import MyAuth,MyPermision

#用户必须登录之后才能访问获取所有图书接口
class Books(APIView):
    #可以写多个认证类
    # authentication_classes=[MyAuth,]
    #只有超级用户才能访问该接口
    permission_classes=[MyPermision,]
    def get(self,request):
        #request.user 就是当前登录用户
        print(request.user.name)
        return Response('返回了所有图书')

class Publish(APIView):
    # authentication_classes = [MyAuth, ]
    permission_classes=[]
    def get(self,request):
        print(request.user.name)
        return Response('返回了所有出版社信息')
class Login(APIView):
    authentication_classes = []
    def post(self,request):
        response={'code':100,'msg':'登录成功'}
        name=request.data.get('name')
        pwd=request.data.get('pwd')
        try:
            #get 有且只有一条才不报错,其他都抛异常
            user=models.User.objects.filter(name=name,pwd=pwd).get()
            #登录成功,需要去token表中存数据
            #生成一个唯一的idhg
            token=uuid.uuid4()
            models.Token.objects.update_or_create(user=user,defaults={'token':token})
            response['token']=token
        except ObjectDoesNotExist as e:
            response['code']=101
            response['msg']='用户名或密码错误'
        except Exception as e:
            response['code'] = 102
            # response['msg'] = '未知错误'
            response['msg'] = str(e)
        return Response(response)

附:不存数据库的token验证:

def get_token(id,salt='123'):
    import hashlib
    md=hashlib.md5()
    md.update(bytes(str(id),encoding='utf-8'))
    md.update(bytes(salt,encoding='utf-8'))

    return md.hexdigest()+'|'+str(id)

def check_token(token,salt='123'):
    ll=token.split('|')
    import hashlib
    md=hashlib.md5()
    md.update(bytes(ll[-1],encoding='utf-8'))
    md.update(bytes(salt,encoding='utf-8'))
    if ll[0]==md.hexdigest():
        return True
    else:
        return False

class TokenAuth():
    def authenticate(self, request):
        token = request.GET.get('token')
        success=check_token(token)
        if success:
            return
        else:
            raise AuthenticationFailed('认证失败')
    def authenticate_header(self,request):
        pass
class Login(APIView):
    def post(self,reuquest):
        back_msg={'status':1001,'msg':None}
        try:
            name=reuquest.data.get('name')
            pwd=reuquest.data.get('pwd')
            user=models.User.objects.filter(username=name,password=pwd).first()
            if user:
                token=get_token(user.pk)
                # models.UserToken.objects.update_or_create(user=user,defaults={'token':token})
                back_msg['status']='1000'
                back_msg['msg']='登录成功'
                back_msg['token']=token
            else:
                back_msg['msg'] = '用户名或密码错误'
        except Exception as e:
            back_msg['msg']=str(e)
        return Response(back_msg)
from rest_framework.authentication import BaseAuthentication
class TokenAuth():
    def authenticate(self, request):
        token = request.GET.get('token')
        token_obj = models.UserToken.objects.filter(token=token).first()
        if token_obj:
            return
        else:
            raise AuthenticationFailed('认证失败')
    def authenticate_header(self,request):
        pass

class Course(APIView):
    authentication_classes = [TokenAuth, ]

    def get(self, request):
        return HttpResponse('get')

    def post(self, request):
        return HttpResponse('post')

总结:局部使用,只需要在视图类里加入:

authentication_classes = [TokenAuth, ]

三 全局使用:

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",]
}

四 源码分析:

#Request对象的user方法
@property
def user(self):
the authentication classes provided to the request.
        if not hasattr(self, '_user'):
            with wrap_attributeerrors():
                self._authenticate()
        return self._user

def _authenticate(self):
        for authenticator in self.authenticators:
            try:
                user_auth_tuple = authenticator.authenticate(self)
            except exceptions.APIException:
                self._not_authenticated()
                raise
            #认证成功,可以返回一个元组,但必须是最后一个验证类才能返回
            if user_auth_tuple is not None:
                self._authenticator = authenticator
                self.user, self.auth = user_auth_tuple
                return

        self._not_authenticated()

self.authenticators

  def get_authenticators(self):
        return [auth() for auth in self.authentication_classes]

认证类使用顺序:先用视图类中的验证类,再用settings里配置的验证类,最后用默认的验证类

猜你喜欢

转载自www.cnblogs.com/HUIWANG/p/11129664.html