一、学习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")