Django REST framework - 认证

认证

(我是谁?)api

身份认证是将传入请求与一组标识凭据相关联的机制,而后,权限和限制策略可使用这些凭据来肯定是否应该容许该请求.服务器

REST框架提供了许多开箱即用的身份验证方案,还容许您实现自定义方案。
身份验证始终在视图的最开始,在发生权限和限制检查以前,以及容许任何其余代码继续以前运行。app

request.user 属性一般将设置为contrib.authUser类的实例。框架

request.auth 属性用于任何其余身份验证信息,例如,它可用于表示请求已签名的身份验证令牌。dom

DRF 5种验证方式

# 基于用户名和密码的认证
class BasicAuthentication(BaseAuthentication):
    pass

# 基于Session的认证
class SessionAuthentication(BaseAuthentication):
    pass

# 基于Tokend的认证
class TokenAuthentication(BaseAuthentication):
    pass

# 基于远端用户的认证(专用用户管理服务器)
class TokenAuthentication(BaseAuthentication):
    pass

如何肯定身份验证?

身份验证方案始终定义为类列表。REST框架将尝试对列表中的每一个类进行身份验证,并将设置request.user和request.auth使用成功进行身份验证的第一个类的返回值。post

若是没有类进行身份验证,request.user则将设置为实例django.contrib.auth.models.AnonymousUser,request.auth并将其设置为None。url

的价值request.user和request.auth对身份认证的请求能够经过修改UNAUTHENTICATED_USER和UNAUTHENTICATED_TOKEN设置。rest

设置身份验证方案

  1. 可使用该DEFAULT_AUTHENTICATION_CLASSES设置全局设置默认认证方案。例如code

    REST_FRAMEWORK = {
         'DEFAULT_AUTHENTICATION_CLASSES': (
             'rest_framework.authentication.BasicAuthentication',
             'rest_framework.authentication.SessionAuthentication',
      )
     }
  2. 您还可使用APIView基于类的视图在每一个视图或每一个视图集的基础上设置身份验证方案。

    from rest_framework.authentication import SessionAuthentication, BasicAuthentication
     from rest_framework.permissions import IsAuthenticated
     from rest_framework.response import Response
     from rest_framework.views import APIView
    
     class ExampleView(APIView):
         authentication_classes = (SessionAuthentication, BasicAuthentication)
         permission_classes = (IsAuthenticated,)
    
         def get(self, request, format=None):
             content = {
                 'user': unicode(request.user),  # `django.contrib.auth.User` instance.
                 'auth': unicode(request.auth),  # None
             }
             return Response(content)
  3. 或者,若是您正在使用@api_view具备基于功能的视图的装饰器。

    @api_view(['GET'])
     @authentication_classes((SessionAuthentication, BasicAuthentication))
     @permission_classes((IsAuthenticated,))
     def example_view(request, format=None):
         content = {
             'user': unicode(request.user),  # `django.contrib.auth.User` instance.
             'auth': unicode(request.auth),  # None
         }
         return Response(content)

案例: 基于自定义Token认证

第一步: 定义一个用户表和一个保存用户Token的表

class UserInfo(models.Model):
    username = models.CharField(max_length=16)
    password = models.CharField(max_length=32)
    type = models.SmallIntegerField(
        choices=((0, '普通用户'), (1, 'VIP用户')),
        default=0
    )


class Token(models.Model):
    user = models.OneToOneField(to='UserInfo')
    token_code = models.CharField(max_length=128)

第二步: 定义一个登录视图

from rest_framework.views import APIView
from app2 import models
from rest_framework.response import Response
import hashlib, time

def get_random_token(username):
    """
    根据用户名和时间戳生成随机token
    """
    timestamp = str(time.time())
    m = hashlib.md5(bytes(username, encoding="utf-8"))
    m.update(bytes(timestamp, encoding="utf-8"))
    return m.hexdigest()


class LoginView(APIView):
    """
    校验用户名是否正确从而生成token的视图
    """
    def post(self, request):
        res = {"code": 0}
        # print(request.data)
        username = request.data.get("username")
        password = request.data.get("password")

        user = models.UserInfo.objects.filter(username=username, password=password).first()
        if user:
            token = get_random_token(username)
            models.Token.objects.update_or_create(defaults={"token_code": token}, user=user)
            res["token"] = token
        else:
            res["code"] = 1
            res["error"] = "用户名或密码错误"
        return Response(res)

第三步定义一个认证类

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from app2 import models


class MyAuth(BaseAuthentication):
    def authenticate(self, request):
        # if request.method in ["POST", "PUT", "DELETE"]:  
        
        # 若是在表单中须要判断请求方式    因为表单是post请求,因此获取token 的方式为 request.data.get("token")
        # request.query_params为url中的参数
        request_token = request.query_params.get("token", None)  
        if not request_token:
            raise AuthenticationFailed('q.缺乏token')

        token_obj = models.Token.objects.filter(token_code=request_token).first()
        if not token_obj:
            raise AuthenticationFailed("无效的Token")
        # token_obj.user 经过token这张表的对象和user这个关联字段 找到 UserInfo表的对象及当前用户对象
        return token_obj.user, request_token
        
        # else:
        #     return None, None

第四步: 使用认证类

视图级别认证

# (用的很少)
class CommentViewSet(ModelViewSet):

    queryset = models.Comment.objects.all()
    serializer_class = app01_serializers.CommentSerializer
    authentication_classes = [MyAuth, ]

全局级别认证

# 在settings.py中配置
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.MyAuth", ]
}
相关文章
相关标签/搜索