rest-framework源码解析--TokenAuthentication

        首先,在token验证模块中,我们看到的是这一函数:

    def get_model(self):
        if self.model is not None:
            return self.model
        from rest_framework.authtoken.models import Token
        return Token

这里我们先不看 if 语句,直接去看 Token (如下图)

class Token(models.Model):
    """
    The default authorization token model.
    """
    key = models.CharField(_("Key"), max_length=40, primary_key=True)
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL, related_name='auth_token',
        on_delete=models.CASCADE, verbose_name=_("User")
    )
    created = models.DateTimeField(_("Created"), auto_now_add=True)

    class Meta:
        # Work around for a bug in Django:
        # https://code.djangoproject.com/ticket/19422
        #
        # Also see corresponding ticket:
        # https://github.com/encode/django-rest-framework/issues/705
        abstract = 'rest_framework.authtoken' not in settings.INSTALLED_APPS
        verbose_name = _("Token")
        verbose_name_plural = _("Tokens")

    def save(self, *args, **kwargs):
        if not self.key:
            self.key = self.generate_key()
        return super().save(*args, **kwargs)

    @classmethod
    def generate_key(cls):
        return binascii.hexlify(os.urandom(20)).decode()

    def __str__(self):
        return self.key

         可以很明显的看出,在这里,我们建立了一个一对一的 Token 模型 指向的是 User 模型,通过元类调用 generate_key 来生产模型中的 key 字段的值,最后由魔术方法 __str__ 来作为返回值。

        回到我们的 get_model 函数,通过判断是否存在token表来执行操作:

  • 如果已有 token 表(自己定义的或是通过 Token 模型生成的表),返回该表
  • 表不存在,其返回的值就是通过 Token 模型建立的 token 表
    def get_model(self):
        if self.model is not None:
            return self.model
        from rest_framework.authtoken.models import Token
        return Token


         既然我们已经明白了 get_model() 的作用,那么我们就从它入手,找到 token验证模块中使用 get_model() 的函数:

    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)

        先看函数名,作为一个被广泛使用的包,命名肯定是规范的,可读的。

好的,Google 翻译告诉了我们答案,再看它的函数体中的这行代码:

        令牌 = model( 也就是 Token ).object.select_related(' user ').get( key= key )

这里等于号后面的 key 是传递进来的参数,那么我们就需要看一下是谁调用了该函数(下图)

    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)
        """
        1.无效的令牌头。没有提供任何凭据。
        2.无效的令牌头。此字符串不应包含空格。
        """
        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) #这里这里 <<== 
  • 可以看到,传递的是 token ,
  • 继续往上面看 :token = auth[1].decode() 
  • 继续:auth = get_authorization_header(request).split()
  • 再向上:(下图)
def get_authorization_header(request):
    """
    Return request's 'Authorization:' header, as a bytestring.
    返回请求的“Authorization:”头,作为bytestring。
    Hide some test client ickyness where the header can be unicode.
    在头可以是unicode的地方隐藏一些测试客户端易读性。
    """
    auth = request.META.get('HTTP_AUTHORIZATION', b'') #这里这里 <<== 
    if isinstance(auth, str):
        # Work around django test client oddness
        # HTTP_HEADER_ENCODING = 'iso-8859-1'
        auth = auth.encode(HTTP_HEADER_ENCODING)
    return auth

好了,这里大概就算是验证模块的首发站了,看官方给的英文注解(看不懂的看Google 翻译出来的,虽然第二句翻译的有些奇怪...)

在这一函数中,通过 request.META.get() 我们拿到了请求头中的 凭证( Authorization ) 的数据,也就是 凭证头 以及 凭证体,见下图:

 在上图中,凭证头是 token ,凭证体是 b571d6300db3c0d86438efa25616179e7f005c0d

之后将 凭证数据 赋值给 auth ,接着我们回到 验证函数中:

    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)

auth = get_authorization_header(request).split()

get_authorization_header(request) 上面已经说过了,返回一个 auth ,在通过 split 将凭证 拆分,之后就是校验部分,很好理解,就不多赘述了。

最后是将凭证体 传递给了 authenticate_credentials,再由 authenticate_credentials 返回 通过 token 认证的用户 以及 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 验证流程 概述:


  1. 客户端通过登录模块登录时,对是否是第一次登录进行判断:是,为其在 Token 表中新建一条数据,获取 Token 表中的 token 值;否,直接获取 Token 表中的 token 值。判断语句结束后,服务器将 token 值传递到客户端并由客户端保存在某一存储空间中
  2. 当我们访问需要 token 验证的 API 接口时,将 token 与数据一同传输到服务器
  3. 服务器解析客户端传递的数据与请求,当需要 token 用于验证时,在数据表中查找对应的 token 值:如果找到了,那就开始处理请求的其他部分;没找到,那就返回一个 401 错误 ( Unauthorized ),终止操作,等待下一次请求或关闭连接。

 好了,关于 TokenAuthentication 的源码部分就到这里了。

#Ps:边看源码边写博客属实掉头发,容我眯一会儿,如果觉得我写的狗屁不通也请不要怪罪嗷。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sthons

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值