002---rest_framework认证组件

rest_framework认证组件

问题:有些API,需要用户登录才能访问,有些无需登录就能访问。

解决:

  • a. 创建两个模型类:UserInfo---OneToOne---UsetToken
  • b. 登录成功后保存在数据库的UserToken表中
            # urls.py
    
            from django.urls import path
            from api import views
    
            urlpatterns = [
                path('api/v1/auth/',views.AuthView.as_view()),
            ]
    
            # views.py
    
            import hashlib, time
            from rest_framework.views import APIView
            from rest_framework.response import Response
            from api import models
    
            def md5(username):
                """
                生成token
                :param username:
                :return:
                """
                m = hashlib.md5(username.encode('utf-8'))
                m.update(str(time.time()).encode('utf-8'))
                return m.hexdigest()
    
            class AuthView(APIView):
                """
                用户登录
                """
    
                def post(self, request, *args, **kwargs):
                    ret = {'code': 1000, 'msg': None}
                    username = request._request.POST.get('username')
                    password = request._request.POST.get('password')
    
                    user = models.UserInfo.objects.filter(username=username, password=password).first()
                    if not user:
                        ret['msg'] = '用户名或密码错误'
                        return Response(ret)
                    token = md5(username)
                    # 存在就更新,不存在就创建
                    models.UserToken.objects.update_or_create(user=user, defaults={'token': token})
                    ret['code'] = 2000
                    ret['msg'] = '登录成功'
                    ret['token'] = token
                    return Response(ret)
    
  • c. 创建自定义Auth认证类和订单,访问订单,判断是否携带token访问,不然不让访问

          # urls.py

          urlpatterns = [
              path('api/v1/auth/',views.AuthView.as_view()),
              path('api/v1/order/',views.OrderView.as_view()),
          ]

          # views.py

          ORDERS = [
              {
                  'id': '1',
                  'name': '华为MATE 20 Pro',
                  'price': 6999,
              },
              {
                  'id': '2',
                  'name': '一加6t',
                  'price': 3999,
              },
              {
                  'id': '3',
                  'name': '狗比亚',
                  'price': 2699,
              },
          ]

          class Authentication(object):
              """
              自定义认证类
              """

              def authenticate(self, request):
                  token = request._request.GET.get('token')
                  token_obj = models.UserToken.objects.filter(token=token).first()
                  if not token_obj:
                      raise AuthenticationFailed('用户认证失败')
                  # 返回一个元祖 一个是用户对象。一个是token对象
                  return token_obj.user, token_obj

              def authenticate_header(self, request):
                  pass

          class OrderView(APIView):
              """
              订单相关业务
              """
              authentication_classes = [Authentication]

              def get(self, request, *args, **kwargs):
                  ret = {'code': 2000, 'msg': '获取成功', 'data': ORDERS}
                  return Response(ret)
  • d. 测试接口:只测试了正确的用户名和密码,错误的自己测

            import requests
    
            auth_url = 'http://127.0.0.1:8000/api/v1/auth/'
            res = requests.post(auth_url, data={'username': 'alex', 'password': 'root1234'}).json()
    
            print(res)  # {'code': 2000, 'msg': '登录成功', 'token': '02fdedaa2c6c5773e00706b5890e289a'}
            token = res.get('token')
    
            order_url = 'http://127.0.0.1:8000/api/v1/order/'
            res = requests.get(order_url,params={'token':token}).json()
            print(res)  # {'code': 2000, 'msg': '获取成功', 'data': [{'id': '1', 'name': '华为MATE 20 Pro', 'price': 6999}, {'id': '2', 'name': '一加6t', 'price': 3999}, {'id': '3', 'name': '狗比亚', 'price': 2699}]}
    
  • e. 再写一个API用户获取用户信息(通过认证通过后注册的request.user对象和request.token对象)
    
            urlpatterns = [
                path('api/v1/auth/',views.AuthView.as_view()),
                path('api/v1/order/',views.OrderView.as_view()),
                path('api/v1/user_info/',views.UserInfoView.as_view()),
            ]
    
            class UserInfoView(APIView):
                """
                获取用户信息相关
                """
                authentication_classes = [Authentication]
    
                def get(self, request, *args, **kwargs):
                    data = {
                        'username': request.user.username,
                        'token': request.auth.token
                    }
                    ret = {'code': 2000, 'msg': '获取成功', 'data': data}
                    return Response(ret)
  • f. 测试认证成功之后返回元祖的两个对象
    
            import requests
    
            auth_url = 'http://127.0.0.1:8000/api/v1/auth/'
            res = requests.post(auth_url, data={'username': 'alex', 'password': 'root1234'}).json()
    
            print(res)  # {'code': 2000, 'msg': '登录成功', 'token': '05810e2756bc6cc27c1ce3af827aa45f'}
            token = res.get('token')
    
            order_url = 'http://127.0.0.1:8000/api/v1/user_info/'
            res = requests.get(order_url,params={'token':token}).json()
            print(res)  # {'code': 2000, 'msg': '获取成功', 'data': {'username': 'alex', 'token': '05810e2756bc6cc27c1ce3af827aa45f'}}

全局使用(再次看源码)

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

      authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES

      def reload_api_settings(*args, **kwargs):
          setting = kwargs['setting']
          if setting == 'REST_FRAMEWORK':
              api_settings.reload()
          # 所以通过配置api.settings可达到全局使用的效果
  • 全局使用
   # 在api应用下面创建utils\auth.py 把之前写的自定义类剪切过来
   # utils\auth.py
   from api import models
   from rest_framework.exceptions import AuthenticationFailed
   from rest_framework.authentication import BaseAuthentication

    class Authentication(BaseAuthentication):
        """
        自定义认证类
        """

        def authenticate(self, request):
            token = request._request.GET.get('token')
            token_obj = models.UserToken.objects.filter(token=token).first()
            if not token_obj:
                raise AuthenticationFailed('用户认证失败')
            # 返回一个元祖 一个是用户对象。一个是token对象
            return token_obj.user, token_obj

        def authenticate_header(self, request):
            pass
    # settings.py
    ##############rest_framework配置################
    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES':['api.utils.auth.Authentication']
    }
    # views.py
    import hashlib, time
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from api import models

    ORDERS = [
        {
            'id': '1',
            'name': '华为MATE 20 Pro',
            'price': 6999,
        },
        {
            'id': '2',
            'name': '一加6t',
            'price': 3999,
        },
        {
            'id': '3',
            'name': '狗比亚',
            'price': 2699,
        },
    ]

    def md5(username):
        """
        生成token
        :param username:
        :return:
        """
        m = hashlib.md5(username.encode('utf-8'))
        m.update(str(time.time()).encode('utf-8'))
        return m.hexdigest()

    class AuthView(APIView):
        """
        用户登录
        """
        # 不需要认证为空列表即可
        authentication_classes = []

        def post(self, request, *args, **kwargs):
            ret = {'code': 1000, 'msg': None}
            username = request._request.POST.get('username')
            password = request._request.POST.get('password')

            user = models.UserInfo.objects.filter(username=username, password=password).first()
            if not user:
                ret['msg'] = '用户名或密码错误'
                return Response(ret)
            token = md5(username)
            # 存在就更新,不存在就创建
            models.UserToken.objects.update_or_create(user=user, defaults={'token': token})
            ret['code'] = 2000
            ret['msg'] = '登录成功'
            ret['token'] = token
            return Response(ret)

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

        def get(self, request, *args, **kwargs):
            ret = {'code': 2000, 'msg': '获取成功', 'data': ORDERS}
            return Response(ret)

    class UserInfoView(APIView):
        """
        获取用户信息相关
        """

        def get(self, request, *args, **kwargs):
            data = {
                'username': request.user.username,
                'token': request.auth.token
            }
            ret = {'code': 2000, 'msg': '获取成功', 'data': data}
            return Response(ret)

梳理:

  • 全局使用:创建自定义认证类,继承BaseAuthentication,实现:authenticate()
  • 局部使用(使用自带的认证类):authentication_classes = [BasicAuthentication,]
  • 该方法有三种返回值
    1. None 当前认证类不做认证,交给下一个认证来来执行
    2. 抛出异常 raise AuthenticationFailed(‘用户认证失败‘)
    3. 元祖(元素1,元素2):元素1赋值给request.user;元素2赋值给request.token
  • 注意:当所有认证类都返回None时,此时是匿名用户,默认是AnonymousUser,可以通过配置文件来更改显示
    REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES":['api.utils.auth.FirstAuthtication','api.utils.auth.Authtication', ],
    #"UNAUTHENTICATED_USER":lambda :"匿名用户",
    "UNAUTHENTICATED_USER":None, # 匿名,request.user = None
    "UNAUTHENTICATED_TOKEN":None,# 匿名,request.auth = None
    }

源码流程

  1. dispath()-->initialize_request()
    - 封装request对象,获取认证类(全局&局部),通过列表生成式创建认证类对象
  2. initial-->perform_authentication()-->request.user
    - for循环每个认证类 return
  3. 认证成功基于反射根据method不同做不同处理

原文地址:https://www.cnblogs.com/xjmlove/p/10394850.html

时间: 2024-09-29 23:08:36

002---rest_framework认证组件的相关文章

Django之REST_FRAMEWORK 认证组件

Django之DRF之认证组件 # from rest_framework.views import APIView # APIView 中的 dispatch 中 执行的 self.initial(request,*args,**kwargs)中的 # APIView---->dispatch------>self.initial------>三个校验 # self.perform_authentication(request) # 认证校验 # self.check_permissi

Django中rest_framework的认证组件,权限组件,频率组件,序列化组件的最简化版接口

url urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^login/', views.Login.as_view()), # Book表 url(r'^books/$',views.BookHandle.as_view({ 'get':'list', 'post':'create' })), url(r'^books/(?P<pk>\d+)/',views.BookHandle.as_view({ 'get':'retrieve

rest-framework的认证组件

认证组件 1.登录认证(与组件无关): 首先要在model表内添加用户表和token表: from django.db import models # Create your models here. class User(models.Model): name=models.CharField(max_length=32) pwd=models.CharField(max_length=32) class Token(models.Model): user=models.OneToOneFie

RESTful-rest_framework认证组件、权限组件、频率组件-第五篇

认证组件格式: 1 写一个认证类 from rest_framework.authentication import BaseAuthentication class MyAuth(BaseAuthentication): def authenticate(self,request): # request 是封装后的 token = request.query_params.get('token') ret = models.UserToken.objects.filter(token=toke

DAY99 - Rest Framework(四)- 认证组件和权限组件

一.认证组件 1.使用 # 模型层 class User(models.Model): name = models.CharField(max_length=32) pwd = models.CharField(max_length=32) class UserToken(models.Model): user = models.OneToOneField(to='User') token = models.CharField(max_length=64) #myAuth.py from app

视图组件和认证组件

1.使用mixin和generics类编写视图 from rest_framework.mixins import CreateModelMixin, ListModelMixin, DestroyModelMixin, RetrieveModelMixin, UpdateModelMixin from rest_framework.generics import GenericAPIView class BooksView(CreateModelMixin, ListModelMixin, G

DjangoRestFramework学习三之认证组件、权限组件、频率组件、url注册器、响应器、分页组件

本节目录 一 认证组件 二 权限组件 三 频率组件 四 URL注册器 五 响应器 六 分页组件 七 xxx 八 xxx 一 认证组件 1. 局部认证组件 我们知道,我们不管路由怎么写的,对应的视图类怎么写的,都会走到dispatch方法,进行分发, 在咱们看的APIView类中的dispatch方法的源码中,有个self.initial(request, *args, **kwargs),那么认证.权限.频率这三个默认组件都在这个方法里面了,如果我们自己没有做这三个组件的配置,那么会使用源码中默

DjangoRestFramework之认证组件,权限组件,频率组件

一 . 认证组件 我们现在知道的认证机制有cookie, session,session比较安全,session的信息是存在服务器上的,如果用户量足够大的话,服务器的压力也就比较大,并且django的session存到了django_session表中,不是很好操作,现在生产中使用的一个叫做token机制的方式比较多.可以使用这个机制把token存到用户信息里,当用户登录成功的时候放里面,等他来的时候就要带着这个来,而且们每次来的时候都更新token,防止被拦截. 我们这里使用一下token,首

python_restframework(认证组件)

认证组件 1. APIview分发 继续apiview函数 进入到 dispatch方法中 def dispatch(self, request, *args, **kwargs): # 新的request请求, initialize_request request = self.initialize_request(request, *args, **kwargs) 2.初始化新的request def initialize_request(self, request, *args, **kw