Django Rest Framework令牌认证


78

我已经阅读了《 Django Rest Framework指南》并完成了所有教程。一切似乎都有意义,并且按应有的方式工作。我得到了如上所述的基本身份验证和会话身份验证。 http://django-rest-framework.org/api-guide

但是,我在文档的令牌认证部分苦苦挣扎,它缺少或没有教程那么深入。
http://django-rest-framework.org/api-guide/authentication/#tokenauthentication

它说我需要为用户创建令牌,但是否说明了在models.py中的位置?

我的问题是:

有人可以为初学者更好地解释文档的令牌认证部分吗?

Answers:


71

不,不在您的models.py中-在模型方面,您所需要做的就是rest_framework.authtoken在您的中包含适当的app()INSTALLED_APPS。这将提供一个外键给用户的令牌模型。

您需要做的是确定何时以及如何创建这些令牌对象。在您的应用中,是否每个用户都会自动获得令牌?还是只有某些授权用户?或仅在他们明确要求一个时?

如果每个用户都应该始终拥有一个令牌,那么在链接到的页面上会有一段代码片段,向您展示如何设置自动创建它们的信号:

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

将此文件放在任何位置的models.py文件中,并且在Django线程启动时将被注册)

如果令牌仅应在特定时间创建,则在您的视图代码中,您需要在适当的时间创建并保存令牌:

# View Pseudocode
from rest_framework.authtoken.models import Token

def token_request(request):
    if user_requested_token() and token_request_is_warranted():
        new_token = Token.objects.create(user=request.user)

创建(并保存)令牌后,即可用于身份验证。


什么意思post_save
244boy17年

2
@ 244boy它被设置create_auth_token信号处理程序,以便每当User保存a(因此post_save)时,create_auth_token都将被调用。信号是Django的内部生命周期事件处理机制。
Jim K.

86

@ ian-clelland已经提供了正确的答案。他的帖子中只提到了一些小片段,因此我将记录完整的过程(我正在使用Django 1.8.5和DRF 3.2.4):

  1. 创建超级用户之前,请执行以下操作。否则,超级用户将无法创建其令牌。

  2. 转到settings.py并添加以下内容:

    INSTALLED_APPS = (
        'rest_framework',
        'rest_framework.authtoken',
        'myapp',
    )
    
    REST_FRAMEWORK = {
        'DEFAULT_PERMISSION_CLASSES': (
            'rest_framework.permissions.IsAuthenticated',
        ),
        'DEFAULT_AUTHENTICATION_CLASSES': (
            'rest_framework.authentication.TokenAuthentication',
        )
    }
    
  3. myappmodels.py中添加以下代码:

    from django.db.models.signals import post_save
    from django.dispatch import receiver
    from rest_framework.authtoken.models import Token
    from django.conf import settings
    
    # This code is triggered whenever a new user has been created and saved to the database
    @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)
    

    或者,如果您想更明确一些,请在myapp项目下创建一个名为Signals.py的文件。将上面的代码放入其中,然后在__init__.py中编写import signals

  4. 打开一个控制台窗口,导航到您的项目目录,然后输入以下命令:

    python manage.py migrate
    python manage.py makemigrations
    

    看一下数据库,应该使用以下字段创建一个名为authtoken_token的表:键(这是令牌值),创建的(创建日期的时间),user_id(引用auth_user表的id列的外键)

  5. 使用创建一个超级用户python manage.py createsuperuser。现在,使用来查看数据库中的authtoken_tokenselect * from authtoken_token;,您应该看到已添加了一个新条目。

  6. 使用curl或者更简单的替代httpie测试访问你的API,我使用httpie:

    http GET 127.0.0.1:8000/whatever 'Authorization: Token your_token_value'
    

    而已。从现在开始,对于任何API访问,您都需要在HTTP标头中包含以下值(请注意空格):

    Authorization: Token your_token_value
    
  7. (可选)如果您提供用户名和密码,DRF还可以返回用户的令牌。您要做的就是在urls.py中添加以下内容:

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

    使用httpie进行验证:

    http POST 127.0.0.1:8000/api-token-auth/ username='admin' password='whatever'
    

    在返回正文中,您应该看到以下内容:

    {
        "token": "blah_blah_blah"
    }
    

而已!


感谢您的详细评论。令牌在哪里匹配?我们可以编辑什么吗?
Vidya

1
@rrmo令牌存储在名为auth_token的数据库表中(或类似的名称,我不记得确切的名称。该表只有三列,即主键,令牌和用户模型的外键)。每次接收到身份验证请求时,我认为都会提取数据库表以将传入令牌与存储的令牌进行比较。

@Cheng关于点#3:在把代码signals.py和添加import signals__init__.py加注django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet在Django 1.9。
narendra-choudhary

Bu如何从移动应用程序接收令牌,例如如何使用用户名和密码生成令牌(例如创建base64令牌),然后在请求中发送令牌?
耶稣阿尔玛勒-Hackaprende

@JesusAlmaral令牌是在服务器端而不是客户端端创建的。用户填写注册信息并将其发送到服务器以创建帐户后,将与该帐户一起创建令牌。创建令牌后,您可以将其值发送到客户端。

18

在Django 1.8.2和rest框架3.3.2上,上述所有操作不足以启用基于令牌的身份验证。

尽管在Django设置文件中指定了REST_FRAMEWORK设置,但@api_view装饰器仍需要基于函数的视图:

from rest_framework.decorators import api_view

@api_view(['POST','GET'])
def my_view(request):
    if request.user.is_authenticated():
       ...

否则根本不执行令牌认证


2
尽管有少数支持,但此答案还提供了一个非常有用的观点:如果没有@api_view装饰器,则视图将不使用令牌auth。也许可以将其添加到所选答案中。
Paolo Stefan

两年半后...谢谢
zobbo

14

只是在此加两分钱,如果您有一个处理用户创建(和激活)的自定义用户管理器,您还可以像这样执行此任务:

from rest_framework.authtoken.models import Token
# Other imports

class UserManager(BaseUserManager):

    def create_user(self, **kwargs):
        """
        This is your custom method for creating user instances. 
        IMHO, if you're going to do this, you might as well use a signal.

        """
        # user = self.model(**kwargs) ...
        Token.objects.create(user=user)

    #You may also choose to handle this upon user activation. 
    #Again, a signal works as well here.

    def activate_user(**kwargs):
        # user = ...
        Token.objects.create(user=user)

如果您已经创建了用户,则可以在终端中进入python shell,并为数据库中的所有用户创建令牌。

>>> from django.contrib.auth.models import User
>>> from rest_framework.authtoken.models import Token 
>>> for user in User.objects.all():
>>> ...    Token.objects.create(user=user)

希望能有所帮助。


10

有一种更干净的方法来获取用户令牌。

只需运行manage.py shell

然后

from rest_framework.authtoken.models import Token
from django.contrib.auth.models import User
u = User.objects.get(username='admin')
token = Token.objects.create(user=u)
print token.key

那么应该在表DB_Schema.authtoken_token中找到一条记录



By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.