django DRF认证组件示例


一、学习DRF的认证类; 设计:LoginView不登录就可以访问,UserView和OrderView需要通过认证后才能访问;

1、urls.py

urlpatterns = [
    path('login/', views.LoginView.as_view()),
    path('user/', views.UserView.as_view()),
    path('order/', views.OrderView.as_view()),

]

2、views.py

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed # 认证失败抛出异常使用

class MyAuthentication(BaseAuthentication):
    def authenticate(self, request):
        '''
        重写这个方法,去做认证,
        1、读取用户请求传递的token;
        2、校验合法性;
        3、返回值:
            - 返回一个元组(),认证成功:必须有2个元素,request.user  request.auth
            - 认证失败,抛出异常,返回错误信息;
            - 返回None,在有多个认证类的时候,会依次认证;  都没有认证成功的话,默认为匿名用户;
        '''
        token = request.query_params.get("token")
        if token:
            return ("wupeiqi","123456")
        else:
            raise AuthenticationFailed("认证失败")


class LoginView(APIView):
    def get(self,request):
        return Response("LoginView")

class UserView(APIView):

    authentication_classes = [MyAuthentication,]
    def get(self,request):
        return Response("UserView")

class OrderView(APIView):

    authentication_classes = [MyAuthentication,]
    def get(self,request):
        return Response("OrderView")

二、简单的实例

上面快速应用,需要在每个视图中都加  authentication_classes 的设置,如果有100个都需要加,按照上面的方法就太繁琐了,所以DRF支持全局配置 authentication_classes ;

还有一个需要注意的地方:全局设置 authentication_classes 的时候,自定义认证类不能在views.py中,要单独放到一个文件中,不然会引起反复调用,报错的问题。

1、urls.py

urlpatterns = [
    path('login/', views.LoginView.as_view()),
    path('user/', views.UserView.as_view()),
    path('order/', views.OrderView.as_view()),

]

2、views.py

class LoginView(APIView):
    # 排除页面设置为空就可以了;
    # 如果全局和局部都设置了,以局部为准;
    authentication_classes = []
    def get(self,request):
        return Response("LoginView")

class UserView(APIView):
    def get(self,request):
        return Response("UserView")

class OrderView(APIView):
    def get(self,request):
        return Response("OrderView")

4、auth.py,在项目下新建一个文件夹,名字为ext,在该文件夹下建立auth.py文件,作为自定义认证类的存放地址

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed # 认证失败抛出异常使用

class MyAuthentication(BaseAuthentication):
    def authenticate(self, request):
        '''
        重写这个方法,去做认证,
        1、读取用户请求传递的token;
        2、校验合法性;
        3、返回值:
            - 返回一个元组(),认证成功:必须有2个元素,request.user  request.auth
            - 认证失败,抛出异常,返回错误信息;
            - 返回None,在有多个认证类的时候,会依次认证;  都没有认证成功的话,默认为匿名用户;
        '''
        token = request.query_params.get("token")
        if token:
            return ("wupeiqi","123456")
        else:
            raise AuthenticationFailed("认证失败")

    # 解决抛出异常,状态码一致的问题;
    def authenticate_header(self, request):
        return "API"

3、settings.py

REST_FRAMEWORK = {
    # 自定义认证组件的全局配置
    "DEFAULT_AUTHENTICATION_CLASSES":['ext.auth.MyAuthentication',]
}

三、多个认证类的执行流程

如果有多个认证类,执行流程是依次执行,直到最后。如果通过,后面不再执行。如果执行到最后都没有通过会返回None,匿名访问。 

四、实例应用

1、urls.py

urlpatterns = [
    path('login/', views.LoginView.as_view()),
    path('user/', views.UserView.as_view()),
    path('order/', views.OrderView.as_view()),

]

2、auth.py

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed # 认证失败抛出异常使用

from api import models

# 在url中寻找token
class QueryParamsAuthentication(BaseAuthentication):
    def authenticate(self, request):
        '''
        重写这个方法,去做认证,
        1、读取用户请求传递的token;
        2、校验合法性;
        3、返回值:
            - 返回一个元组(),认证成功:必须有2个元素,request.user  request.auth
            - 认证失败,抛出异常,返回错误信息;
            - 返回None,在有多个认证类的时候,会依次认证;  都没有认证成功的话,默认为匿名用户;
        '''
        token = request.query_params.get("token")
        # 如果没有token 返回None
        if not token:
            return

        user_object = models.UserInfo.objects.filter(token=token).first()
        if user_object:
            return user_object,token  # 这样 request.user= 用户对象,request.auth= token ;
        # 没有认证成功,返回none,继续去别的认证类中认证
        return
    # 解决抛出异常,状态码一致的问题;
    def authenticate_header(self, request):
        return "API"

# 在请求头中寻找token
class HeaderParamsAuthentication(BaseAuthentication):
    def authenticate(self, request):
        token = request.META.get("HTTP_AUTHORIZATION")
        # 如果没有token 返回None
        if not token:
            return
        user_object = models.UserInfo.objects.filter(token=token).first()
        if user_object:
            return user_object,token  # 这样 request.user= 用户对象,request.auth= token ;
        # 没有认证成功,返回none,继续去别的认证类中认证
        return
    # 解决抛出异常,状态码一致的问题;
    def authenticate_header(self, request):
        return "API"

# 都没找到token,抛出失败
class NoAuthentication(BaseAuthentication):
    def authenticate(self, request):
        raise AuthenticationFailed({"code":1001,"msg":"认证失败"})
    # 解决抛出异常,状态码一致的问题;
    def authenticate_header(self, request):
        return "API"

3、settings.py

REST_FRAMEWORK = {
    "UNAUTHENTICATED_USER": None,
    "UNAUTHENTICATED_TOKEN": None,
    # 自定义认证组件的全局配置
    "DEFAULT_AUTHENTICATION_CLASSES":[
        'ext.auth.QueryParamsAuthentication',
        'ext.auth.HeaderParamsAuthentication',
        'ext.auth.NoAuthentication',

    ]
}

4、models.py

class UserInfo(models.Model):
    '''用户表'''
    username = models.CharField(verbose_name="用户名",max_length=32)
    password = models.CharField(verbose_name="密码",max_length=64)
    # 临时测试方法,token可以存放到很多地方,例如radis jwt等
    token = models.CharField(verbose_name="TOKEN",max_length=64,null=True,blank=True)

5、views.py


from rest_framework.response import Response
from rest_framework.views import APIView

from api import models
import uuid # 用于生成token


class LoginView(APIView):
    # login页面不需要认证就可以登录,所以单独设置为空;
    authentication_classes = []

    def post(self,request):
        # 1、接收用户提交的用户名和密码;
        user = request.data.get("username")
        pwd = request.data.get("password")
        # 2、数据库校验;
        user_object = models.UserInfo.objects.filter(username=user,password=pwd).first()
        if not user_object:
            return Response({"status":False,"msg":"用户名或者密码错误"})
        # 用户名密码正确为用户生产token
        token = str(uuid.uuid4())
        user_object.token = token
        user_object.save()
        return Response({"status":True,"msg":"登录成功!","token":token})

class UserView(APIView):
    def get(self,request):
        print(request.user,request.auth)
        return Response("UserView")

class OrderView(APIView):
    def get(self,request):
        return Response("OrderView")

 

 

你可能感兴趣的:(Django,django,数据库,python)