Django Rest 框架令牌认证

Posted

技术标签:

【中文标题】Django Rest 框架令牌认证【英文标题】:Django Rest Framework Token Authentication 【发布时间】:2013-01-28 02:07:41 【问题描述】:

我已阅读 Django Rest 框架指南并完成所有教程。一切似乎都有意义,并且按应有的方式工作。我得到了基本和会话身份验证的工作。

django rest framework - api guide

但是,我在文档的令牌身份验证部分苦苦挣扎,它有点缺乏或没有像教程那样深入。

django-rest-framework - token authentication

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

有人可以为初学者更好地解释一下文档中的令牌身份验证部分吗?

【问题讨论】:

【参考方案1】:

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

    在创建超级用户之前执行以下操作。否则,超级用户不会创建他/她的令牌。

    转到 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',
        )
    
    

    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

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

    python manage.py migrate
    python manage.py makemigrations
    

    查看您的数据库,应该创建一个名为 authtoken_token 的表,其中包含以下字段:key(这是令牌值)、created(创建日期时间)、user_id(a引用 auth_user 表的 id 列的外键)

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

    使用curl 或更简单的替代方法httpie 来测试对您的api 的访问,我使用的是httpie:

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

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

    Authorization: Token your_token_value
    

    (可选)如果您提供用户名和密码,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"
    
    

就是这样!

【讨论】:

感谢您的详细评论。令牌在哪里匹配?我们可以编辑任何东西吗? @rrmo 令牌存储在名为 auth_token 的数据库表中(或类似的东西,我不记得确切的名称。该表只有三列,主键、令牌和外键用户模型)。每次收到身份验证请求时,我都会获取数据库表以将传入的令牌与存储的令牌进行比较。 @Cheng 关于第 3 点:将代码放入 signals.py 并在 __init__.py 中添加 import signals 在 Django 1.9 中引发 django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet 您如何接收令牌,例如从移动应用程序,您使用用户名和密码生成令牌(例如创建 base64 令牌)并在请求中发送? @JesusAlmaral 令牌是在服务器端而不是客户端创建的。用户填写注册信息发送到服务器创建账号后,会与账号一起创建一个token。创建令牌后,您可以将其值发送到客户端。【参考方案2】:

不,不在您的 models.py 中——在模型方面,您需要做的就是在您的 INSTALLED_APPS 中包含适当的应用程序 (rest_framework.authtoken)。这将提供一个外键给用户的 Token 模型。

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

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

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

(把this放在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 是什么意思? @244boy 它将create_auth_token 设置为signal handler,这样每当User 被保存时(因此post_save),create_auth_token 就会被调用。信号是 django 的内部生命周期事件处理机制。【参考方案3】:

在 Django 1.8.2 和 rest framework 3.3.2 上,按照上述所有方法不足以启用基于令牌的身份验证。

虽然 REST_FRAMEWORK 设置在 django 设置文件中指定,但基于函数的视图需要 @api_view 装饰器:

from rest_framework.decorators import api_view

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

否则根本不执行令牌认证

【讨论】:

尽管赞成票很少,但这个答案增加了一个非常有用的点:没有 @api_view 装饰器,视图将不会使用令牌身份验证。也许可以将其添加到所选答案中。 两年半后...谢谢【参考方案4】:

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

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)

希望对您有所帮助。

【讨论】:

【参考方案5】:

有一种更简洁的方式来获取用户令牌。

只需运行 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 中找到一条记录

【讨论】:

【参考方案6】:

除了这里的优秀答案,我想提一个更好的令牌认证方法:JSON Web Token Authentication。 http://getblimp.github.io/django-rest-framework-jwt/ 提供的实现非常好用。

this answer 中更详细地解释了这些好处。

【讨论】:

【参考方案7】:

JSON Web Token Authentication 是比 Token Authentication 更好的选择。此项目已使用 Django (http://getblimp.github.io/django-rest-framework-jwt/) 实现了 JWT Auth,但目前该项目未维护。

对于替代方案,您可以关注:https://github.com/davesque/django-rest-framework-simplejwt

【讨论】:

以上是关于Django Rest 框架令牌认证的主要内容,如果未能解决你的问题,请参考以下文章

Django Rest 框架邮递员令牌认证

Django REST框架+ Angular项目上的令牌认证

ANDROID VOLLEY + JWT TOKEN 认证 + DJANGO REST 框架

django-rest-framework 令牌认证和注销

Django rest 框架 jwt 令牌权限

令牌的有效期是多久? Django REST 框架