Rest API 基于令牌的身份验证。基本认证

Posted

技术标签:

【中文标题】Rest API 基于令牌的身份验证。基本认证【英文标题】:Rest API token based authentication. Basic Auth 【发布时间】:2017-11-27 20:24:40 【问题描述】:

我已经使用 rest_framework 实现了基于令牌的身份验证,到目前为止一切正常,但我有一个问题,如果我使用 basic-auth 在标头中发送用户名和密码,那么为什么我需要发送 user-有效载荷的名称和密码。当我在正文部分发送包含有效负载的请求时,在请求的标题中没有用户名和密码,我得到以下响应:


  "detail": "CSRF Failed: CSRF token missing or incorrect."

当我在标题中发送用户名和密码而没有发送带有有效负载的用户名和密码时,我得到以下响应:


  "detail": "Invalid username/password."

为什么我在发送有效载荷时需要在标题部分发送用户名和密码。我不太确定这个概念。谁能解释一下并告诉我正确的方法。我用过这个reference。

以下是我的代码: authuser.py

"""Authentication classes for Django Rest Framework.
Classes:
    ExpiringTokenAuthentication: Authentication using extended authtoken model.
"""

from rest_framework import exceptions
from rest_framework.authentication import TokenAuthentication

from rest_framework_expiring_authtoken.models import ExpiringToken


class ExpiringTokenAuthentication(TokenAuthentication):

    """
    Extends default token auth to have time-based expiration.
    Based on http://***.com/questions/14567586/
    """

    model = ExpiringToken

    def authenticate_credentials(self, key):
        """Attempt token authentication using the provided key."""
        if key == "2572e6dbe3b2e150764cd72712713b2975785197":
            token = self.model.objects.get(key=key)
        else:
            try:
                token = self.model.objects.get(key=key)
            except self.model.DoesNotExist:
                raise exceptions.AuthenticationFailed('Invalid token')

            if not token.user.is_active:
                raise exceptions.AuthenticationFailed('User inactive or deleted')

            #if token.expired():
             #   raise exceptions.AuthenticationFailed('Token has expired')

        return (token.user_id, token)

查看.py

 class ObtainExpiringAuthToken(ObtainAuthToken):

    """View enabling username/password exchange for expiring token."""
    model = ExpiringToken
    def post(self, request):
        try:
            payload=json.loads(request.body)
        except:
            return Response('success':False,'message':'Invalid Payload.')
        """Respond to POSTed username/password with token."""
        serializer = AuthTokenSerializer(data=request.data)
        if serializer.is_valid():
            token, _ = ExpiringToken.objects.get_or_create(
                user=serializer.validated_data['user']
            )
            if token.expired():
                # If the token is expired, generate a new one.
                token.delete()
                token = ExpiringToken.objects.create(
                    user=serializer.validated_data['user']
                )

            try:
                user = User.objects.get(id=token.user_id)
            except:
                return Response('success':False,'message':'User does not exists.')
    return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)

obtain_expiring_auth_token = 获得ExpiringAuthToken.as_view()

models.py:

@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
    if created:
        Token.objects.create(user=instance)

class ExpiringToken(Token):

    """Extend Token to add an expired method."""

    class Meta(object):
        proxy = True

    def expired(self):
        """Return boolean indicating token expiration."""
        now = timezone.now()
        #if self.created < now - token_settings.EXPIRING_TOKEN_LIFESPAN:
         #   return True
        return True

settings.py:

REST_FRAMEWORK = 
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    ),
    'DEFAULT_PARSER_CLASSES': (
        'rest_framework.parsers.JSONParser',
    )

【问题讨论】:

您是否对收到 CRSF 令牌错误的原因感到困惑?或者你想知道为什么你必须发送一个 CSRF-token?如果您使用带有模板的视图进行调用,则必须将 % csrf_token % 放入表单中。 @Bono 是的,我需要知道为什么会收到 CRSF 令牌错误?我只是在开发一个 API,所以我不需要模板。每当我在标题部分和有效负载中发送用户名和密码时,我都会得到所需的响应。我只想在有效负载或标头中发送凭据。 @AnujMasand 你在哪里/如何设置ExpiringTokenAuthentication 你是不是在登录的时候没有拿到token,为什么每次都用payload发送用户名和密码,你只需要在header中发送生成的token。我的意思是,如果您不使用令牌身份验证,那么它的意义何在。当您在标头中发送用户名和密码时,您是通过 BasicAuthentication 而不是 TokenAuthentication 进行身份验证。将登录期间生成的令牌放在标题中,直到注销并与交易一起玩。 @Fazil Zaid,感谢您的光临。你很亲密。 Fazil 我只使用过一次,然后我将使用我返回的有效负载令牌。我明白你的意思。我正在寻找的是,在使用基本身份验证时,为什么我需要使用有效负载发送用户名和密码。 【参考方案1】:

获得此错误的唯一可能方法是启用SessionAuthentication。默认全局启用。

http://www.django-rest-framework.org/api-guide/authentication/#setting-the-authentication-scheme

请仔细检查您的设置或在您的视图类中设置一个正确的设置以覆盖全局设置。

【讨论】:

我已经编辑了我的帖子,这是我在settings.py文件中使用的,请看一下。

以上是关于Rest API 基于令牌的身份验证。基本认证的主要内容,如果未能解决你的问题,请参考以下文章

REST API 中基于令牌的身份验证

Netsuite - REST API - 使用基于令牌的身份验证 (TBA) 进行查询 - (在 Python 中)

基于浏览器的 REST api 身份验证

需要一些有关 REST API 的 JWT 身份验证的信息

Netsuite - REST API - 如何使用基于令牌的身份验证 (TBA) 创建新条目记录 - (在 Python 中)

REST API 令牌认证