转自: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
Configuration
1.1 django-rest-auth
1.2 django-rest-framework验证
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
延伸
ReferenceConfiguration
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)也无法访问成功。
- 验证
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 工具
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