【DRF】使用 rest_auth 设置 DRF 的 API(数据库/model) 访问权限

转自:https://blog.csdn.net/qq_29757283/article/details/86539882

本文配置部分主要参考 django-rest-auth 官方文档 ?
另外添加了一些不同的使用方式:
({HTTPie,Curl}×{key,cookie}{\text{HTTPie}, \text{Curl}} \times {\text{key}, \text{cookie}}{HTTPie,Curl}×{key,cookie})

token(key) cookie
获取值 3.2.1 3.3.1
HTTPie 3.2.2.2 3.3.2.1
Curl 3.2.2.1 3.3.2.2

Overview

  1. Configuration
    1.1 django-rest-auth
    1.2 django-rest-framework

  2. 验证
    2.1 It Works
    3 使用 rest_auth 获取认证,访问
    3.1 了解 rest_auth 如何获取认证
    3.2 使用认证的 token 访问数据
    3.2.1 获取 token(key) value
    3.2.1.1 curl 工具
    3.2.1.2 HTTPie
    3.2.2 使用账号的 token 访问 model(REST API)
    3.2.2.1 curl
    3.2.2.2 HTTPie
    3.2.2.3 POSTman 软件
    3.2.2.4 基于 requests 库的 Python 代码
    3.3 使用登录后 Set 的 Cookie 访问数据
    3.3.1 登录和 Set-Cookie
    3.3.2 使用 Cookie 访问数据
    3.3.2.1 HTTPie
    3.3.2.2 Curl
    延伸
    Reference

  3. Configuration

1.1 django-rest-auth
因为 rest-auth 库基于 DRF1,所以首先要安装 DRF 我就不多说了

pip install dango-rest-auth

<proj>/api/urls.py

严谨来说,哪个 urls.py 文件取决于您如何设计项目源码结构,以及这个项目结构如何对应 rest api。所以实际上每个人自己修改的 urls.py 未必相同。
(可以直接修改和 settings.py 同一路径下的 urls.py,代码和下面一样,这样就可以像下文一样访问 http://<domain>:[port]/api/rest_auth/login/ 了)

urlpatterns += [
path('api/rest_auth/', include('rest_auth.urls')),
]
1
2
3
<proj>/<proj>/settings.py :

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

#
# install
#
'rest_framework',
'rest_framework.authtoken',

'rest_auth',

[...]

]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

1.2 django-rest-framework
<proj>/<proj>/settings.py

[...]

REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
)
}

[...]
1
2
3
4
5
6
7
8
9
10
11
12
13
直接添加上面段落。
这一段非常重要,如果没有这一段的化,那么可能使用正确的认证方式(比如下面用到的 user’s key in tokens)也无法访问成功。

  1. 验证

2.1 It Works

现在直接通过 DRF 提供的 rest api 访问 model 将会失败(要求权限认证)。

3 使用 rest_auth 获取认证,访问
3.1 了解 rest_auth 如何获取认证
post manage.py createsuperuser 的账号密码到 django-rest-auth 的 end-point(即 API),获得到 token(rest_auth 使用“key” 表示):

POST 正确的账号密码之后,现在就可以继续使用浏览器访问其它编写的 endpoint(REST API),比如 DRF 官方实现了一个 Snippet model 用作 Tutorial,浏览器在 rest_auth 登录之后,就可以访问 http://<domain>:[port]/api/snippet/。

(这是因为浏览器已经 Set-Cookie 过了,下文会讲到。)

3.2 使用认证的 token 访问数据
3.2.1 获取 token(key) value
token 意思是 user’s key 的集合。在 Django 的 admin 后台管理中可以看到:

通过浏览器访问 rest_auth 的 rest api 获取 token 的方式我们已经在 3.1 节看过了。
当然,实际上我们不会通过浏览器直接访问 http://...:.../api/rest_auth/login/ 这种方式来获取 token。

在前端中使用 javascript,在应用程序中,即是使用编程语言的网络库。
它们在参数上大同小异,在测试(感受如何使用)的时候,还是先通过命令行工具来访问 ?

3.2.1.1 curl 工具
curl -X POST \ -H "Content-Type: application/json" \ --data '{"username": "<your username>", "password": "<your password>"}' \ "http://localhost:8000/api/rest_auth/login/" {"key":"b20...380"}
1 2 3 4 5 6 3.2.1.2 HTTPie http POST
"http://localhost:8000/api/rest_auth/login/"
username=<your username> password=<your password>
HTTP/1.1 200 OK
Allow: POST, OPTIONS
Content-Length: 50
Content-Type: application/json
Date: Mon, 29 Jul 2019 04:25:42 GMT
Server: WSGIServer/0.2 CPython/3.6.8
Set-Cookie: csrftoken=RRkTbmUuv6kWZtbPnJ0Yx23SIXRRe2qZV8z8ycHE2ORpU9McplBLIpmcGOLQDMcy; expires=Mon, 27 Jul 2020 04:25:42 GMT; Max-Age=31449600; Path=/; SameSite=Lax
Set-Cookie: sessionid=m65g5ansi11jhgncmlqiaroemjgplyy8; expires=Mon, 12 Aug 2019 04:25:42 GMT; HttpOnly; Max-Age=1209600; Path=/; SameSite=Lax
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN

{
"key": "b20...380"
}

$
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
3.2.2 使用账号的 token 访问 model(REST API)
3.2.2.1 curl

即:

$ curl -X GET <url> -H 'Authorization: Token <上文POST之后获得的key值>'
1
3.2.2.2 HTTPie
HTTPie 使用 token GET 数据:

$ http GET
"http://localhost:8000/api/snippet/"
"Authorization: Token b20...380"
HTTP/1.1 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 696
Content-Type: application/json
Date: Mon, 29 Jul 2019 04:35:30 GMT
Server: WSGIServer/0.2 CPython/3.6.8
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN

[
{
"code": "print('hello world')",
"id": 1,
"language": "python",
"linenos": false,
"style": "friendly",
"title": "Hello World of Python"
}
]

$
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
HTTPie 使用 token POST 数据:

$ http POST
"http://localhost:8000/api/snippet/"
'Authorization: Token b20...380'
title='Hello World of C'
code="#include <stdio.h>\n\nint main(){\n printf("hello world\n");\n}"
language=c

HTTP/1.1 201 Created
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 168
Content-Type: application/json
Date: Tue, 30 Jul 2019 01:43:36 GMT
Server: WSGIServer/0.2 CPython/3.6.8
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN

{
"code": "#include <stdio.h>\n\nint main(){\n printf("hello world\n");\n}"
"id": 3,
"language": "c",
"linenos": false,
"style": "friendly",
"title": "Hello World of C"
}

$
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
DELETE 数据同理,只需要将 ‘GET’ 换成 ‘DELETE’, 同时根据原本定义好的 REST API,需要将 url 具体到 <int:pk> 即可(.../api/sinppet/1/)

3.2.2.3 POSTman 软件

注意格式: Authorization : Token <the value>;
token 和 value 中间有空格

3.2.2.4 基于 requests 库的 Python 代码
上面分别演示了使用 curl, httpie 命令行工具和 POSTman 桌面 GUI 工具通过 token 访问 rest api。
现在落实到代码中 ?

获取 token:

import json
import requests

r = requests.post("http://<domain>:<port>/api/rest_auth/login/",
data={'username': '<username>', 'password': '<password>'})
if r.status_code == 200:
token = json.loads(r.text)['key']
else:
raise RuntimeError(r.text)

1
2
3
4
5
6
7
8
9
10
使用 token 访问数据:

r = requests.get('http://<domain>:<port>/api/snippet/',
headers={'Authorization': 'Token {}'.format(token)})
if r.status_code == 200:
print(json.loads(r.text))
else:
raise RuntimeError(r.text)

1
2
3
4
5
6
7

3.3 使用登录后 Set 的 Cookie 访问数据
3.3.1 登录和 Set-Cookie
由于没有单独实现 login 功能的页面。所以这里也就直接借用 rest_auth 模块的 login endpoint。
和前文一样,使用 HTTPie 登录等到的 HTTP Response 如下:

$ http POST
"http://localhost:8000/api/rest_auth/login/"
username=<your username> password=<your password>
HTTP/1.1 200 OK
Allow: POST, OPTIONS
Content-Length: 50
Content-Type: application/json
Date: Mon, 29 Jul 2019 04:25:42 GMT
Server: WSGIServer/0.2 CPython/3.6.8
Set-Cookie: csrftoken=RRk...Mcy; expires=Mon, 27 Jul 2020 04:25:42 GMT; Max-Age=31449600; Path=/; SameSite=Lax
Set-Cookie: sessionid=m65g5ansi11jhgncmlqiaroemjgplyy8; expires=Mon, 12 Aug 2019 04:25:42 GMT; HttpOnly; Max-Age=1209600; Path=/; SameSite=Lax
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN

{
"key": "b20...380"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
由上面结果显然可以看出,服务器响应了 Set-Cookie 内容。
如果是浏览器的化,就会解析这个 Set-Cookie 内容,然后对于浏览器来说,它就知道了和该网站访问交互有了一个状态(“登录过”),这个状态就是通过 Cookie 内容体现。也就是说,之后在浏览器上访问这个网站的时候,浏览器都会自动带上 Cookie 发送出去请求。

因为是登录过,也就是说认证过了,所以访问数据是可以被允许的。也就是说通过 cookie 来表明自己的这个请求是认证过的请求 - 即有了 cookie 就不需要 token。

那么显然,直接 GET 某个 REST API 是不含有 Cookie 的;所以这里要根据登录后获得 Response 中的 Set-Cookie 来手动发送带有 Cookie 的请求。
以上面实例中的 Set-Cookie 内容为例,不同的命令行工具的 Cookie 使用方式如下?

3.3.2 使用 Cookie 访问数据
注意上面的 HTTP Response 中有两个 Set-Cookie 对应着两个核心的内容:一个是 csrftoken,一个是 sessionid。

csrftoken
在提交表单时使用(创建、修改、更新和删除),这是为了防止跨域访问。
sessionid
翻译过来就时“会话 ID”,所以服务器判断当前请求对应的用户,和这个用户是否登录过依赖的就是这个 cookie 值。
如果只是 GET 数据,那么 cookie 中只需要这个内容即可,不过为了简单起见,还是全部都一块带上好了。
3.3.2.1 HTTPie
$ http GET
"http://localhost:8000/api/snippet/"
'Cookie: csrftoken=RRk...Mcy;sessionid=m65g5ansi11jhgncmlqiaroemjgplyy8'
HTTP/1.1 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 696
Content-Type: application/json
Date: Mon, 29 Jul 2019 04:25:34 GMT
Server: WSGIServer/0.2 CPython/3.6.8
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN

[
{
"code": "print('hello world')",
"id": 1,
"language": "python",
"linenos": false,
"style": "friendly",
"title": "Hello World of Python"
}
]

$
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
在 HTTPie 文档 ? 中对于 Cookie 的使用有着不错的描述:

Cookies
HTTP clients send cookies to the server as regular HTTP headers. That means, HTTPie does not offer any special syntax for specifying cookies — the usual Header:Value notation is used:

Send a single cookie:
$ http example.org Cookie:sessionid=foo

GET / HTTP/1.1
Accept: /
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cookie: sessionid=foo
Host: example.org
User-Agent: HTTPie/0.9.9
1
2
3
4
5
6
7
Send multiple cookies (note the header is quoted to prevent the shell from interpreting the ;):
$ http example.org 'Cookie:sessionid=foo;another-cookie=bar'

GET / HTTP/1.1
Accept: /
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cookie: sessionid=foo;another-cookie=bar
Host: example.org
User-Agent: HTTPie/0.9.9
1
2
3
4
5
6
7
If you often deal with cookies in your requests, then chances are you’d appreciate the sessions feature.

3.3.2.2 Curl
curl -X GET
-b 'csrftoken=RRk...Mcy;sessionid=datfyeyowug9hktb3l81ilwychlw58v3'
"http://localhost:8000/api/snippet/"
[{"id":1,"title":"Hello World of Python","code":"print('hello world')","linenos":false,"language":"python","style":"friendly"}]
1
2
3
4
5
使用 -b 或 --cookie 指定 Cookie(来源可以是文件或字符串),使用 ; 分隔/连接多个 cookie。

当然,使用 Curl 格式显然没有 HTTPie 美观。不过 Curl 仍然是一个值得了解的命令行工具。

延伸
使用 rest_auth 相当了简化了我们手动去编写代码实现 token 验证的相关逻辑。
但是如果想要从代码层面详细了解 token,或者说自己实现一份和 rest_auth 相近功能的东西,这里有几篇重要的参考文章:

How to Implement Token Authentication using Django REST Framework ?
Django REST framework 的TokenAuth认证及外键Serializer基本实现 ?
Django REST Framework Doc – 认证 ?

Reference
The Ultimate Tutorial for Django REST Framework: Login and Authentication (Part 2) ?

django rest auth Doc > Installation ?
————————————————
版权声明:本文为CSDN博主「RDpWTeHM」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_29757283/article/details/86539882

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容