django-rest-framework源码分析2—认证(Authentication)源码解析

本文详细介绍了认证的概念,包括互联网中的常见认证方式,如用户名密码、邮箱验证和手机验证码。接着,通过Django的源码分析了传统认证模式,如MD5加密,并展示了基于API视图的认证流程。最后,讨论了如何在全局和局部层面应用自定义认证类,提供了一种基于token的认证实现示例。
摘要由CSDN通过智能技术生成

什么是认证(Authentication)

通俗地讲就是验证当前用户的身份,证明 “你是你自己”(比如:你每天上下班打卡,都需要通过指纹打卡,当你的指纹和系统里录入的指纹相匹配时,就打卡成功)

互联网中的认证:

  • 用户名密码登录
  • 邮箱发送登录链接
  • 手机号接收验证码
  • 只要你能收到邮箱 / 验证码,就默认你是账号的主人

传统认证方式

# models
class UserInfo(models.Models):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=64)
    
class UserToken(models.Models):
    user = models.OneToOneField(to='UserInfo')
    token = models.CharField(max_length=64)
# views
def md5(user):
    import hashlib
    import time
    ctime = str(time.time())
    m = hashlib.md5(bytes(user,enceding='utf-8'))
    m.update(bytes(ctime,enceding='utf-8'))
    return m.hexdigest()
    
class AuthView(APIView):
    def post(self,request,*args,**kwargs):
        ret = {"code":'1000','msg':None}
        try:
            user = request._request.POST.get('username')
            pwd = reuqest._request.POST.get('password')
            obj = models.UserInfo.objects.filter(username=name,password=pwd).first()
            if not obj:
                ret['code']='1001'
                ret['msg']='用户名秘密错误'
            token = md5(user)
            models.UserToken.objects.update_or_create(user=obj,default={'token':token})
            ret['token']=token
        except Excepion as e:
            ret['code']='1002'
            ret['msg']='请求异常'
        return JsonResponse(ret)

源码分析

#认证中的基类,主要实现authenticateauthenticate_header方法


class BaseAuthentication:
    """
    All authentication classes should extend BaseAuthentication.
    """

    def authenticate(self, request):
        """
        Authenticate the request and return a two-tuple of (user, token).
        """
        raise NotImplementedError(".authenticate() must be overridden.")

    def authenticate_header(self, request):
        """
        Return a string to be used as the value of the `WWW-Authenticate`
        header in a `401 Unauthenticated` response, or `None` if the
        authentication scheme should return `403 Permission Denied` responses.
        """
        pass

#基于用户名和密码的认证

class BasicAuthentication(BaseAuthentication):

#基于session的认证

class SessionAuthentication(BaseAuthentication):

#基于token的认证

class TokenAuthentication(BaseAuthentication): ---

#远程用户认证


class RemoteUserAuthentication(BaseAuthentication):
    """
    REMOTE_USER authentication.

    To use this, set up your web server to perform authentication, which will
    set the REMOTE_USER environment variable. You will need to have
    'django.contrib.auth.backends.RemoteUserBackend in your
    AUTHENTICATION_BACKENDS setting
    """

认证流程

authentication_classes
请求到dispatch方式

def dispatch(self, request, *args, **kwargs):
      """
      `.dispatch()` is pretty much the same as Django's regular dispatch,
      but with extra hooks for startup, finalize, and exception handling.
      """
      self.args = args
      self.kwargs = kwargs
      request = self.initialize_request(request, *args, **kwargs)
      self.request = request
      self.headers = self.default_response_headers  # deprecate?
      try:
          self.initial(request, *args, **kwargs)

调用self.initial()

def initial(self, request, *args, **kwargs):
    self.perform_authentication(request)

调用 perform_authentication() 返回request.user

def perform_authentication(self, request):
     request.user  

**在dispatch中initialize_request封装了Request **

def initialize_request(self, request, *args, **kwargs):
    parser_context = self.get_parser_context(request)
    return Request(
        request,
        parsers=self.get_parsers(),
        authenticators=self.get_authenticators(),
        negotiator=self.get_content_negotiator(),
        parser_context=parser_context
    )

Request 有方法注解 user 调用_authenticate 循环认证对象 执行方法

@property
def user(self):
    if not hasattr(self, '_user'):
        with wrap_attributeerrors():
            self._authenticate()
    return self._user

def _authenticate(self):
    for authenticator in self.authenticators:
        try:
            user_auth_tuple = authenticator.authenticate(self)
        except exceptions.APIException:
            self._not_authenticated()
            raise
        if user_auth_tuple is not None:
            self._authenticator = authenticator
            self.user, self.auth = user_auth_tuple
            return
    self._not_authenticated()

使用方法

  • 全局使用

自定义的认证类可以通过全局设置 放在setting文件中 源码中会读取setting中的

REST_FRAMEWORK={
       'DEFAULT_AUTHENTICATION_CLASSES'=('自定义的认证类'),
       'UNAUTHENTICATED_USER':None,
       'UNAUTHENTICATED_TOKEN':None
   }   
  • 局部使用(视图级别的认证)

内置的认证类 rest_framework.authentication BasicAuthentication

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
class MyAuth(BaseAuthentication):
	def authenticate(self, request):
		if request.method in ["POST", "PUT", "DELETE"]:
			request_token = request.data.get("token", None)
			if not request_token:
				raise AuthenticationFailed('缺少token')
			token_obj = models.Token.objects.filter(token_code=request_token).first()
			if not token_obj:
				raise AuthenticationFailed('无效的token')
			return token_obj.user.username, None
		else:
			return None, None

继承 BasicAuthentication 创建自定义的认证类 实现 authenticate方法
添加到视图类的 authentication_classes

class CommentViewSet(ModelViewSet):
	queryset = models.Comment.objects.all()
	serializer_class = app01_serializers.CommentSerializer
	authentication_classes = [MyAuth, ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值