zoukankan      html  css  js  c++  java
  • django rest framework权限和认证

    一.Authentication用户认证配置

      1.四种验证及官网描述: 

                 BasicAuthentication

                                      此身份验证方案使用HTTP基本身份验证,根据用户的用户名和密码进行签名。基本身份验证通常仅适用于测试。

                                      如果成功通过身份验证,请BasicAuthentication提供以下凭据。

                 .request.user将是一个Django User实例。   

                 .request.auth会的None

                                     拒绝许可的未经身份验证的响应将导致HTTP 401 Unauthorized使用适当的WWW-Authenticate标头进行响应。例如:

                                       WWW-Authenticate: Basic realm="api"

                                     注意:如果您BasicAuthentication在生产中使用,则必须确保您的API仅可用于https。您还应该确保您的API客户端始终在登录时重新请求用户名和密码,并且永远不会将这些详细信息存储到持久存储中。

           

                 TokenAuthentication

                                  此身份验证方案使用基于令牌的简单HTTP身份验证方案。令牌认证适用于客户端 - 服务器设置,例如本机桌面和移动客户端。

            要使用该TokenAuthentication方案,您需要配置要包含的身份验证类TokenAuthentication,并rest_framework.authtoken在您的INSTALLED_APPS设置中另外包含

            INSTALLED_APPS = (
                    ...
                  'rest_framework.authtoken'
                  )

            注意:确保manage.py migrate在更改设置后运行rest_framework.authtoken应用程序提供Django数据库迁移。

               SessionAuthentication

            此身份验证方案使用Django的默认会话后端进行身份验证。会话身份验证适用于与您的网站在同一会话上下文中运行的AJAX客户端。

            如果成功通过身份验证,请SessionAuthentication提供以下凭据。

            • request.user将是一个Django User实例。
            • request.auth会的None

            未经许可的未经身份验证的响应将导致HTTP 403 Forbidden响应。

            如果您使用的是AJAX风格的API与SessionAuthentication,你需要确保你有一个有效的CSRF令牌任何“不安全”的HTTP方法调用,如PUTPATCHPOSTDELETE请求。有关更多详细信息,请参阅Django CSRF文档

            警告:创建登录页面时始终使用Django的标准登录视图。这将确保您的登录视图得到适当保护。

            REST框架中的CSRF验证与标准Django的工作方式略有不同,因为需要同时支持基于会话和非会话的身份验证。这意味着只有经过身份验证的请求才需要CSRF令牌,并且可以在没有CSRF令牌的情况下发送匿名请求。此行为不适用于登录视图,登录视图应始终应用CSRF验证。

               RemoteUserAuthentication

                             此身份验证方案允许您将身份验证委派给Web服务器,该服务器设置REMOTE_USER 环境变量。

                             要使用它,您必须django.contrib.auth.backends.RemoteUserBackend在您的AUTHENTICATION_BACKENDS设置中拥有(或子类) 默认情况下,为尚不存在的用户名RemoteUserBackend创建User对象。要更改此行为和其他行为,请参阅 Django文档

             如果成功通过身份验证,请RemoteUserAuthentication提供以下凭据:

            • request.user将是一个Django User实例。
            • request.auth会的None

           有关配置身份验证方法的信息,请参阅Web服务器的文档,例如:

           自定义验证

          要实现自定义身份验证方案,请子类化BaseAuthentication并覆盖该.authenticate(self, request)方法。(user, auth)如果身份验证成功,则该方法应返回两元组None否则返回。

          在某些情况下None,您可能希望AuthenticationFailed从该.authenticate()方法引发异常而不是返回

          通常,您应采取的方法是:

            • 如果未尝试验证,请返回None还将检查还在使用的任何其他身份验证方案。
            • 如果尝试进行身份验证但失败,则引发AuthenticationFailed异常。无论是否进行任何权限检查,都将立即返回错误响应,并且不会检查任何其他身份验证方案。

          您可以覆盖该.authenticate_header(self, request)方法。如果实现,它应返回一个字符串,该字符串将用作响应WWW-Authenticate中标头的值HTTP 401 Unauthorized

          如果.authenticate_header()未覆盖方法,则在HTTP 403 Forbidden拒绝未经身份验证的请求访问时,身份验证方案将返回响应。

          注意:当请求对象.user.auth属性调用您的自定义身份验证器时,您可能会看到AttributeError重新提升为WrappedAttributeError这是防止外部属性访问抑制原始异常所必需的。Python不会识别AttributeError来自自定义身份验证器orginates,而是假设请求对象没有.user.auth属性。这些错误应由您的验证者修复或以其他方式处理。

      2.Token验证:

           2.1setting.py中的install-app添加app:

     #Token验证,会生成表
    'rest_framework.authtoken',
    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': (
            'rest_framework.authentication.BasicAuthentication',
            'rest_framework.authentication.SessionAuthentication',
            'rest_framework.authentication.TokenAuthentication',
            #添加Token验证,如果Token过期,不需要登录的界面也不能访问,最好配置在具体的页面
    
    
    ),

    生成token表,用户登录后会创建对应的key

    2.2使用时TokenAuthentication,您可能希望为客户端提供一种机制,以获取给定用户名和密码的令牌。REST框架提供了一个内置视图来提供此行为。要使用它,请将obtain_auth_token视图添加到URLconf:

    from rest_framework.authtoken import views
    #配置url
    urlpatterns += [
        url(r'^api-token-auth/', views.obtain_auth_token)
    ]

           2.3Django请求到响应全过程:http://www.projectsedu.com/

          2.4TokenAuthentication源码:

    def get_authorization_header(request):
        """
        Return request's 'Authorization:' header, as a bytestring.
    
        Hide some test client ickyness where the header can be unicode.
        """
        auth = request.META.get('HTTP_AUTHORIZATION', b'')
        if isinstance(auth, text_type):
            # Work around django test client oddness
            auth = auth.encode(HTTP_HEADER_ENCODING)
        return auth

    通过该函数获取Token并返回

        def authenticate(self, request):
            auth = get_authorization_header(request).split()
    
            if not auth or auth[0].lower() != self.keyword.lower().encode():
                return None
    
            if len(auth) == 1:
                msg = _('Invalid token header. No credentials provided.')
                raise exceptions.AuthenticationFailed(msg)
            elif len(auth) > 2:
                msg = _('Invalid token header. Token string should not contain spaces.')
                raise exceptions.AuthenticationFailed(msg)
    
            try:
                token = auth[1].decode()
            except UnicodeError:
                msg = _('Invalid token header. Token string should not contain invalid characters.')
                raise exceptions.AuthenticationFailed(msg)
    
            return self.authenticate_credentials(token)

    然后通过authenticate判断token是否合法

     def authenticate_credentials(self, key):
            model = self.get_model()
            try:
                token = model.objects.select_related('user').get(key=key)
            except model.DoesNotExist:
                raise exceptions.AuthenticationFailed(_('Invalid token.'))
    
            if not token.user.is_active:
                raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))
    
            return (token.user, token)

    到token表中查找是否对应token

    二.动态设置permission,Authentication

      1.permission权限api(这里列举几个,更多可以参考官网http://www.django-rest-framework.org/api-guide/permissions/):

        IsAuthenticated:该IsAuthenticated许可类将拒绝允许任何未认证用户,并允许许可,否则。如果您希望您的API仅供注册用户访问,则此权限适用。

        IsAdminUser:所述IsAdminUser许可类将拒绝许可给任何用户,除非user.is_staffTrue在这种情况下的许可将被允许。如果您希望只有可信管理员的子集可以访问您的API,则此权限是合适的。

        IsAuthenticatedOrReadOnly:IsAuthenticatedOrReadOnly将允许经过身份验证的用户执行任何请求。只有在请求方法是“安全”方法之一时,才允许对未经授权的用户提出请求; GETHEADOPTIONS。如果您希望API允许匿名用户具有读取权限,并且仅允许对经过身份验证的用户具有写入权限,则此权限是合适的。

      2.自定义权限:

        例子:

        以下是根据黑名单检查传入请求的IP地址的权限类的示例,如果IP已被列入黑名单,则拒绝该请求。

    from rest_framework import permissions
    
    class BlacklistPermission(permissions.BasePermission):
        """
        Global permission check for blacklisted IPs.
        """
    
        def has_permission(self, request, view):
            ip_addr = request.META['REMOTE_ADDR']
            blacklisted = Blacklist.objects.filter(ip_addr=ip_addr).exists()
            return not blacklisted

        除了针对所有传入请求运行的全局权限之外,您还可以创建对象级权限,这些权限仅针对影响特定对象实例的操作运行。例如:

    class IsOwnerOrReadOnly(permissions.BasePermission):
        """
        Object-level permission to only allow owners of an object to edit it.
        Assumes the model instance has an `owner` attribute.
        """
    
        def has_object_permission(self, request, view, obj):
            # Read permissions are allowed to any request,
            # so we'll always allow GET, HEAD or OPTIONS requests.
            if request.method in permissions.SAFE_METHODS:
                return True
    
            # Instance must have an attribute named `owner`.
            return obj.owner == request.user

        自定义验证(可以新建一个文件):

    from rest_framework import permissions
    
    
    class IsOwnerOrReadOnly(permissions.BasePermission):
        def has_object_permission(self, request, view, obj):
            # Read permissions are allowed to any request,
            # so we'll always allow GET, HEAD or OPTIONS requests.
            if request.method in permissions.SAFE_METHODS:
                return True
    
            # Instance must have an attribute named `owner`.
            return obj.user == request.user

      views中使用验证:

    ......
    from utils.permissions import IsOwnerOrReadOnly
    
    
    # Create your views here.
    class UserFavViewset(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin,
                         mixins.DestroyModelMixin, viewsets.GenericViewSet):
        '''
        list:
            获取用户收藏列表
        retrieve:
            判断某个商品是否收藏
        create:
            收藏商品
        '''
        # queryset = UserFav.objects.all()
        permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
    ......

       3.动态判断:

    from rest_framework import permissions
    from rest_framework import authentication
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
    ......
    class UserViewset(mixins.CreateModelMixin,mixins.UpdateModelMixin,mixins.RetrieveModelMixin,viewsets.GenericViewSet):
        '''
        用户
        '''
        serializer_class = UserRegSerializer
        queryset = User.objects.all()
        authentication_classes = (JSONWebTokenAuthentication,authentication.SessionAuthentication)
        #更新,添加用户信息放在一起,是否登录应该动态,注册不用登录IsAuthenticated,该方法不行
        # permission_classes = (permissions.IsAuthenticated)
    
        def create(self, request, *args, **kwargs):
            serializer = self.get_serializer(data=request.data)
            serializer.is_valid(raise_exception=True)
            user=self.perform_create(serializer)
            re_dict=serializer.data
            payload=jwt_payload_handler(user)
            re_dict['token']=jwt_encode_handler(payload)
            re_dict['name']=user.name if user.name else user.username
            headers = self.get_success_headers(serializer.data)
            return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers)
    
        def get_serializer_class(self):
            '''
            重载GenericAPIView中的get_serializer_class函数,调用不同的序列化类,如果是create,
            就调用UserRegSerializer序列化,否则UserDetailSerializer序列化
            :return: 
            '''
            if self.action == 'retrieve':
                return UserDetailSerializer
            elif self.action == 'create':
                return UserRegSerializer
            return UserDetailSerializer
    
        def get_permissions(self):
            '''
            重载APIview中的get_perimissions函数,如果是新增用户则不用登录,否则必须登录
            :return: 
            '''
            if self.action == 'retrieve':
                return [permissions.IsAuthenticated()]
            elif self.action == 'create':
                return []
            return []
    
        def get_object(self):
            '''
            返回当前用户
            :return: 
            '''
            return self.request.user
    
        def perform_create(self, serializer):
            return serializer.save()

      

  • 相关阅读:
    再度学习MYSQL-----(1.基础)
    GIL解释器锁(进程与线程的应用场景)
    Django学习三有关表的创建查询类
    Django学习二模板
    Django学习一
    JQuery学习一
    前端基础学习之css二
    前端基础之css一
    mysql----单表多表查询
    MySQL-----表操作
  • 原文地址:https://www.cnblogs.com/lyq-biu/p/9625917.html
Copyright © 2011-2022 走看看