权限是 web 应用的重要组成部分。没有权限控制,任何人的请求都会对数据资源进行操控,那就乱套了。
本章就来学习 drf 中如何进行权限管理。
教程来源杜塞-django-vue系列
博客链接 传送门
上一章我们已经将用户以外键的形式关联到文章中,但是由于 author
字段允许为空,所以理论上我们上一节发表的文章是没有作者的文章:
>http http://127.0.0.1:8000/api/article/8/
HTTP/1.1 200 OK
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS
Content-Length: 124
Content-Type: application/json
Date: Mon, 14 Jun 2021 05:43:30 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.9.4
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
{
"author": null,
"body": "",
"created": "2021-06-13T15:01:15.586622",
"id": 8,
"title": "may",
"updated": "2021-06-13T15:01:15.586622"
}
我们可以对文章直接赋予作者(也可以伪造作者):
>http -a xianwei:admin123456 POST http://127.0.0.1:8000/api/article/ title=python body=python author=999
HTTP/1.1 400 Bad Request
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 58
Content-Type: application/json
Date: Mon, 14 Jun 2021 06:09:51 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.9.4
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
{
"author": [
"Invalid pk \"999\" - object does not exist."
]
}
解决这个问题,既然请求中带有作者信息,那我们就可以从request
中提取用户信息,并额外存储到数据中。
修改视图:
# article/views.py
class ArticleList(generics.ListCreateAPIView):
···
# 新增,存储用户作者
def perform_create(self, serializer):
serializer.save(author=self.request.user)
- 新增的这个
perform_create()
从父类ListCreateAPIView
继承而来,它在序列化数据真正保存之前调用,因此可以在这里添加额外的数据(即用户对象)。 serializerv
参数是ArticleListSerializer
序列化器实例,并且已经携带着验证后的数据。它的save()
方法可以接收关键字参数作为额外的需要保存的数据。
在命令行重新测试:
>http -a xianwei:admin123456 POST http://127.0.0.1:8000/api/article/ title="user" body="with user"
HTTP/1.1 201 Created
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 132
Content-Type: application/json
Date: Mon, 14 Jun 2021 06:00:30 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.9.4
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
{
"author": 3,
"body": "with user",
"created": "2021-06-14T14:00:30.477454",
"id": 11,
"title": "user",
"updated": "2021-06-14T14:00:30.477454"
}
id=3,是因为我有三个用户。
但是我们仍可以手动传错误的 author
:
>http -a xianwei:admin123456 POST http://127.0.0.1:8000/api/article/ title=java body=java author=999
HTTP/1.1 400 Bad Request
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 58
Content-Type: application/json
Date: Mon, 14 Jun 2021 06:10:40 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.9.4
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
{
"author": [
"Invalid pk \"999\" - object does not exist."
]
}
好在序列化器中允许你指定只读字段,修改序列化器:
# article/serializers.py
class ArticleListSerializer(serializers.ModelSerializer):
class Meta:
···
` # 新增
read_only_fields = ['author']
我们再次发送POST创建文章请求时,序列化器就不理会我们请求中附带的 author
数据了。
>http -a xianwei:admin123456 POST http://127.0.0.1:8000/api/article/ title=sss body=ddd author=999
HTTP/1.1 201 Created
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 62
Content-Type: application/json
Date: Mon, 14 Jun 2021 06:16:24 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.9.4
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
{
"created": "2021-06-14T14:16:24.718403",
"id": 12,
"title": "sss"
}
显示用户信息
虽然作者外键关联到了文章中,但我们只能查看到作者id,而不能看到其姓名等其他信息,所以我们要把作者具体信息嵌入文章信息中。
新建 app ,用来绑定用户信息(记得注册到setting文件内):
(env) > python manage.py startapp user_info
在user_info内新建序列化器:
# user_info/serializers.py
from rest_framework import serializers
from django.contrib.auth.models import User
class UserDescSerializer(serializers.ModelSerializer):
"""与文章列表中引用的嵌套序列化器"""
class Meta:
model = User
fields=[
'id',
'username',
'last_login',
'date_joined',
]
序列化器我们已经熟悉了,这个序列化器用在文章列表中,用来展示作者基本信息。
最后修改文章列表的序列化器,把他们嵌套起来:
# article/serializers.py
# 这里我们要把author字段添加进fields内
from user_info.serializers import UserDescSerializer
class ArticleListSerializer(serializers.ModelSerializer):
# read_only 参数设置为只读
author = UserDescSerializer(read_only=True)
class Meta:
model = Article
fields = [
'id',
'title',
'created',
'author',
]
这就 OK 了,在命令行测试一下:
>http http://127.0.0.1:8000/api/article/
HTTP/1.1 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 549
Content-Type: application/json
Date: Mon, 14 Jun 2021 06:34:25 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.9.4
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
[
{
"author": null,
"created": "2021-06-13T15:01:15.586622",
"id": 8,
"title": "may"
},
···
]
任务完成。