Django+React全栈开发:关联用户
上一篇文章其实已经讲了一点登录验证相关的内容,不过主要还是为了回答一位群友关于定制DJango用户模型的提问而临时写的,认证(authentication)与授权(authorization)实质上是两个步骤,但是一般都放在一起讲,认证是识别身份,你用管理员账户登录,密码正确,身份被确认为管理员,这是认证,因为是文章作者,所以有编辑文章的权限,这是授权。
文章关联用户
用户与文章应该是一对多的关系,首先要修改我们的Article模型:
class Article(models.Model): author = models.ForeignKey( User, on_delete=models.CASCADE, related_name='articles' ) # ......
接着去执行迁移操作:
$ python manage.py makemigrations $ python manage.py migrate
注意到之前的文章都是没有作者的,所以执行迁移的时候会要求要么退出迁移,在模型上添加默认值,或者现在给出默认值。建议多熟悉迁移操作并且适当掌握一些SQL
用法,这种涉及到数据变更的,有时候还得手动解决冲突。这里给我们之前创建的管理员账户ID做默认值就行,当然开发环境简单粗暴点也可以直接删库。
先修改一下序列化器,加入author
字段:
class ArticleSerializer(serializers.ModelSerializer): class Meta: model = Article fields = ['id', 'title', 'body', 'author', 'created', 'updated']
然后用命令行工具httpie测试一下API:
$ http POST 127.0.0.1:8000/api/articles/ title="user" body="relationship" author=1
可以正常创建新文章,但是,我们只要在POST请求里带上用户ID,就可以为任意用户创建文章,这是不可取的,现在来解决这个问题。
权限类
上一节已经讲过了自定义权限类,现在来写一个只允许管理员创建删除修改,其他用户只读的权限类。
新建article/permissions.py
:
from rest_framework import permissions class IsAdminOrReadOnly(permissions.BasePermission): def has_permission(self, request, view): if request.method in permissions.SAFE_METHODS: return True return request.user.is_superuser
继承父类的has_permission
方法,这个方法的返回值是布尔值,True
即表示授权通过,对任意用户的请求在SAFE_METHODS
内的,直接通过,否则就看用户是否是管理员。
# SAFE_METHODS源码 SAFE_METHODS = ('GET', 'HEAD', 'OPTIONS')
现在要修改一下视图类:
# 引入自定义的权限类 from article.permissions import IsAdminOrReadOnly class ArticleViewSet(viewsets.ModelViewSet): # 加上这一行 permission_classes = [IsAdminOrReadOnly]
现在再使用httpie测试,会得到错误响应:
{ "detail": "Authentication credentials were not provided." }
现在带上验证信息再请求一次:
$ http -a elliot:test1234 POST 127.0.0.1:8000/api/articles/ title="user" body="relationship" author=1 ...... { "author": 1, "body": "relationship", "created": "2021-04-18T07:24:40.144287Z", "id": 5, "title": "user", "updated": "2021-04-18T07:24:40.144560Z" }
这次成功了,但是还有个问题,就是author
这个字段仍然需要传递,并且只要是管理员,这个author值可以填任何已存在的用户ID。现在再来修复这个问题。
请求对象
class ArticleViewSet(viewsets.ModelViewSet): # 添加这个方法 def perform_create(self, serializer): serializer.save(author=self.request.user)
这里覆写了父类的perform_create
方法,在序列化器保存时,从请求对象中获取user
值并赋值给author参数,但是用户仍然可以传递author字段,可以在序列化器中把它设置为只读:
class ArticleSerializer(serializers.ModelSerializer): class Meta: # 添加属性 read_only_fields = ['author', ]
再次测试:
$ http -a elliot:test1234 POST 127.0.0.1:8000/api/articles/ title="author is readonly" body="author is readonly" author=2 ..... { "author": 1, "body": "author is readonly", "created": "2021-04-18T07:39:31.175273Z", "id": 8, "title": "author is readonly", "updated": "2021-04-18T07:39:31.175525Z" }
这样即使传递了非法的author字段也会被忽略掉。
原文标题:Django+React全栈开发:关联用户
原文作者:公子政
原文链接:https://www.elliot00.com/posts/react-django-user
许可协议:署名-非商业性使用-相同方式共享 4.0 国际