DjangoRestFramework 的 TokenAuthentication

本文主要讲解 DjangoRestFramework 的 TokenAuthentication,我们知道 Django 原生的认证机制是:

from django.contrib.auth import authenticate, login
from django.contrib.auth.decorators import login_required, permission_required

在登录视图函数中用 login() 和 业务视图函数用装饰器 log_required。这种方式非常依赖浏览器根据响应头的 Set-Cookie 会自动写 cookie 的特性。 所以该方式的局限是:客户端只能是浏览器, 这不利于我们的服务提供给其他系统调用。系统之间的调用是通过 request 包来调用的,request 包是没有这个行为的。除非调用方自己来实现:解析 Set-Cookie ,然后保存 cookie 到某个地方,然后下次请求该域名时带上 cookie。这可以参考文章:Python socket 发送 HTTP POST请求。所以有时候我们需要另一种认证方式:基于 token 的认证。DRF 的 TokenAuthentication 和 oauth 都是可选方案,本文重点关注前者。

  1. 基本配置

settings.py:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    ......
    'rest_framework',
    'rest_framework.authtoken',
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
        # 'rest_framework.authentication.TokenAuthentication',
    ),
    'DEFAULT_THROTTLE_CLASSES': (
        'app01.utils.VisitThrottle',
    ),
    'DEFAULT_THROTTLE_RATES': {
        'general_rate':'5/m',
        'vip_rate':'10/m',
    },
}

url.py:

from rest_framework import routers
app02_router = routers.DefaultRouter()
app02_router.register(r'autoregister', app02_view.RoleViewSet)

from rest_framework.authtoken import views as drf_auth_views

urlpatterns = [
    .........  
    # 学习 restframework 的 login 和 TokenAuthentication
    # https://blog.csdn.net/qq_39980136/article/details/89503850
    url(r'^drf/', include('rest_framework.urls')),               ----- DRF 的登录 url 和 视图函数
    url(r'^drf_token/', drf_auth_views.obtain_auth_token),       ----- DRF 居然给提供了这么现成的接口
    url(r'^auth/', include('django.contrib.auth.urls')), 
]

配置完后需要再执行 python manage.py migrate 完成 rest_framework.authtoken 的数据库迁移,这会在数据库中创建表 authuser_token。

  1. 获取 token

简单浏览 obtain_auth_token 的源码,可知只需要如下请求即可获取一个 token

(archiver_env) root@robert-Ubuntu:/media/sf_WorkSpace/ToDoHistory# cat drf_token.py 
import json
import requests
url = 'http://192.168.56.101:8080/drf_token/'
input_dict = {'username':'admin', 'password':'start01all'}
res = requests.post(url=url, json=input_dict)
print json.loads(res.text)
(archiver_env) root@robert-Ubuntu:/media/sf_WorkSpace/ToDoHistory# 
(archiver_env) root@robert-Ubuntu:/media/sf_WorkSpace/ToDoHistory# python drf_token.py 
{u'token': u'd159519c4f93725b69e95dd8bf43af745800f266'}
(archiver_env) root@robert-Ubuntu:/media/sf_WorkSpace/ToDoHistory# 
  1. 把得到的 Token 封装到业务请求头中

根据 DRF 文档客户端在进行身份验证的时候,前端需要将token值封装在HTTP协议中的header中。token应以字符串文字“Token”为前缀,空格分隔两个字符串。
例如:Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
这样的话,我们在请求其他页面的时候,就会获取到request中的user的值

该认证方案的缺点:
1.用户向登陆时服务会创建一个token值返回给用户,同时也将这个token值保存到了服务器数据库表中,如果是一个分布式系统的话,想通过一套认证系统的token表用来验证用户登陆,就会出现问题。
2.authtoken表中存放的token值没有过期时间字段,如果token值一旦泄露,非常危险。
3.随着用户的增多,token值会占用服务器大量空间,同时也会加大数据库的查询压力,性能下降。
关于 Token 不过期的问题,请参考下篇文章:解决 DjangoRestFramework 的 TokenAuthentication Token 没有过期的问题

发布了44 篇原创文章 · 获赞 0 · 访问量 3945

猜你喜欢

转载自blog.csdn.net/cpxsxn/article/details/102616005
今日推荐