权限是 web 应用的重要组成部分。没有权限控制,任何人的请求都会对数据资源进行操控,那就乱套了。
本章就来学习 drf 中如何进行权限管理。
教程来源杜塞-django-vue系列
博客链接 传送门
依靠用户身份来限制权限是比较通用的做法,在静态模式下存在,drf中那也当然存在。
改写文章模型添加用户外键,确定每篇文章的作者,保险起见,我们要提前删除现有的所有文章。
修改文章model,添加以下:
#article/model.py
from django.contrib.auth.models import User
# 博客文章
class Article(models.Model):
# 用户
author = models.ForeignKey(
User,
null=True,
on_delete=models.CASCADE,
related_name='articles'
)
执行迁移(每次对模型进行修改都需要!!!):
> python manage.py makemigrations
> python manage.py migrate
启动服务器,然后再次请求:
(venv) E:\drf\drf_vue_blog>http http://127.0.0.1:8000/api/article/
HTTP/1.1 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 2
Content-Type: application/json
Date: Sun, 13 Jun 2021 06:22:02 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
[]
空空如也。
接下来对文章列表接口进行操作.
DRF 内置了如IsAuthenticated
、IsAdminUser
、AllowAny
等权限控制类。
由于是个人博客,因此只准许管理员发布文章。修改文章列表视图如下:
# article/views.py
from rest_framework.permissions import IsAdminUser
class ArticleList(generics.ListCreateAPIView):
···
# 新增
permission_classes = [IsAdminUser]
permission_classes
可以接收一个列表,因此权限控制类可以设置多个,请求必须满足所有控制条件才允许被放行。
测试一下:
(venv) E:\drf\drf_vue_blog>http http://127.0.0.1:8000/api/article/
HTTP/1.1 403 Forbidden
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 58
Content-Type: application/json
Date: Sun, 13 Jun 2021 06:23:43 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
{
"detail": "Authentication credentials were not provided."
}
(venv) E:\drf\drf_vue_blog>http POST http://127.0.0.1:8000/api/article/ title=may body=not..
HTTP/1.1 403 Forbidden
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 58
Content-Type: application/json
Date: Sun, 13 Jun 2021 06:24:11 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
{
"detail": "Authentication credentials were not provided."
}
可以发现确实起作用了,但是除了管理员之外其他人也无法查看,显然这不是我们最重要的结果。
接下来让我们重写。新建 article/permissions.py
:
from rest_framework import permissions
class IsAdminUserOrReadOnly(permissions.BasePermission):
"""
定义我们需要的权限
1.进管理员可以进行修改
2.其他用户仅能查看
"""
def has_permission(self, request, view):
# 对所有人允许 GET,HEAD,OPTIONS请求
if request.method in permissions.SAFE_METHODS:
return True
# 仅管理员可进行其他操作
return request.user.is_superuser
自定义的权限类继承了 BasePermission
这个基础的父类,并实现了父类中的钩子方法 def has_permission
。此方法在每次请求到来时被唤醒执行,里面简单判断了请求的种类是否安全(即不更改数据的请求),如果安全则直接通过,不安全则只允许管理员用户通过。
再次修改视图:
# article/views.py
from .permissions import IsAdminUserOrReadOnly
permission_classes = [IsAdminUser]
# 改为
permission_classes = [IsAdminUserOrReadOnly]
# ArticleList和ArticleDetail添加
改完后进行测试。
首先测试用户未登录状态:
(venv) E:\drf\drf_vue_blog>http http://127.0.0.1:8000/api/article/
HTTP/1.1 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 2
Content-Type: application/json
Date: Sun, 13 Jun 2021 06:43:43 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
[]
(venv) E:\drf\drf_vue_blog>http POST http://127.0.0.1:8000/api/article/ title=may body=not..
HTTP/1.1 403 Forbidden
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 58
Content-Type: application/json
Date: Sun, 13 Jun 2021 06:44: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
{
"detail": "Authentication credentials were not provided."
}
我们发现,虽然没有文章返回,但是体现出了权限的作用(添加文章测试也是一样的效果,不做多赘述)。
在后台创建普通用户 Obama(这是基础),用普通用户身份进行请求:
# 普通用户Obama密码admin123456
(venv) E:\drf\drf_vue_blog>http -a Obama:admin123456 http://127.0.0.1:8000/api/article/
HTTP/1.1 200 OK 成功
···
[]
(venv) E:\drf\drf_vue_blog>http -a Obama:admin123456 POST http://127.0.0.1:8000/api/article/ title=may body=not..
HTTP/1.1 403 Forbidden 失败
Allow: GET, POST, HEAD, OPTIONS
···
{
"detail": "您没有执行该操作的权限。"
}
这边中文是因为我更改时区问题,英文为:"detail": "You do not have permission to perform this action.
最后创建超级管理员进行测试,我的为 xianwei:
# 管理员在用户 xianwei,密码:admin123456
(venv) E:\drf\drf_vue_blog>http -a xianwei:admin123456 http://127.0.0.1:8000/api/article/
HTTP/1.1 200 OK 请求成功
···
[]
(venv) E:\drf\drf_vue_blog>http -a xianwei:admin123456 POST http://127.0.0.1:8000/api/article/ title=may body=not..
HTTP/1.1 201 Created 请求成功
···
{
"created": "2021-06-13T15:01:15.586622",
"id": 8,
"title": "may"
}
最终完成了我们要的效果,任何人可以查看,只有管理员进行新增(CREATE)、更新(PUT)、删除(DELETE)等修改操作