Django 之REST framework学习4:认证和权限(Authentication & Permissions)

到现在为止,所有的人都可以删除或者修改数据,接下来我们看下该如何优化,使数据的操作只限于某些人即增加权限和认证

首先要修改下我们的model类:

首先我们要在Snippet这个model类中增加几个字段:其中一个字段用来代表创建者,另外一个字段用来存储被高亮显示html代码:

owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)
highlighted = models.TextField()

我们还需要确保当model模型类对象被创建时,我们可以用pygments模块去生成高亮的字段,这里我们需要额外引入一些模块:

from pygments.lexers import get_lexer_by_name
from pygments.formatters.html import HtmlFormatter
from pygments import highlight

现在我们给model模型类增加一个.save()方法:

def save(self, *args, **kwargs):
    """
    使用pygments去创建一个高亮的html代码片段
    """
    lexer = get_lexer_by_name(self.language)
    linenos = self.linenos and 'table' or False
    options = self.title and {'title': self.title} or {}
    formatter = HtmlFormatter(style=self.style, linenos=linenos,
                              full=True, **options)
    self.highlighted = highlight(self.code, lexer, formatter)
    super(Snippet, self).save(*args, **kwargs)

所有做完之后我们需要重新做下数据库迁移,官方是直接删库重新做的,就差跑路了!!!

rm -f db.sqlite3
rm -r snippets/migrations
python manage.py makemigrations snippets
python manage.py migrate

然后我们需要创建一些用户进行测试,这里使用了createsuperuser命令:

python manage.py createsuperuser

现在我们有了可用于测试的用户,那么最好也将这么用户放到API中(方便区分),
创建一个序列化器很容易的,在serializers.py中添加:

from django.contrib.auth.models import User

class UserSerializer(serializers.ModelSerializer):
    snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())

    class Meta:
        model = User
        fields = ('id', 'username', 'snippets')

因为'snippets'对User model类中来说反向的关系,所以在使用ModelSerializer类时
默认不会处理这一字段,所以我们需要序列化时添加一个明确的字段。
我们还需要在views.py中添加一些视图函数,为了给用户添加一些只读权限的视图函数,这里我们用到
ListAPIViewRetrieveAPIView这两个通用的cbv:

#记得导入UserSerializer
from snippets.serializers import UserSerializer
from django.contrib.auth.models import User


class UserList(generics.ListAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer


class UserDetail(generics.RetrieveAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

urls.py 中添加:

url(r'^users/$', views.UserList.as_view()),
url(r'^users/(?P<pk>[0-9]+)/$', views.UserDetail.as_view()),

用户与Snippets关联:

此时我们创建code snippet,没有办法用snippet实例与创建这个code snippet的用户关联,
用户只是作为请求的一个属性却没有作为序列化的一部分被发送出去;
我们处理的方法就是在snippet 视图函数中重写.perform_create()方法,
这样一来我们就可以干预处理实例的创建和处理请求的信息。在SnippetList
视图函数中添加:

def perform_create(self, serializer):
    serializer.save(owner=self.request.user)

现在我们的serializer中的create()会把额外的'owner'字段连同请求中的
有效数据一起接收。

更新序列化器serializer:

到目前为止,创建snippets 的用户和snippets 已经关联到一起,我们需要在 serializers.py
处理下SnippetSerializer:

owner = serializers.ReadOnlyField(source='owner.username')

PS:确保你在内部的Meta clas的字段列表中添加了'owner',字段

这个字段会做一些很有意思的事情,source参数可以控制哪个属性是用来生成
字段的,并且可以指向被序列化实例的任意一个属性。它也能采用点式操作,也可以和Django
的模板语言一起使用。
我们添加的字段是一个无类型的ReadOnlyField 类,其他的比如CharField
BooleanField都是有类型的,这个可能不好理解,无类型的类通常是只读的,也
只会被用于序列化中,不会用于反序列化时更新model实例,我们也可以用CharField(read_only=True)
来代替ReadOnlyField

给视图函数添加必要的权限:

用户和snippets的关系已经被绑定到一起,我们接下来该做的就是给授权用户添加权限增删改查权限
IsAuthenticatedOrReadOnly这个类就可以确保被授权的请求有读写权限,未授权的请求
有只读的权限。
在视图模块中添加:

from rest_framework import permissions

在视图函数SnippetListSnippetDetail中添加:

permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

现在我们打开浏览器发现我们的添加权限已经没了,怎么办?

我们需要作为用户登录后才能有添加权限,这样我们需要在项目级别的urls.py
中添加:

from django.conf.urls import include
urlpatterns += [
    url(r'^api-auth/', include('rest_framework.urls')),
]

上述代码包含登录退出的视图函数,这部分的r'^api-auth/'可以是任意你想用的URL地址,官方后面bla,bla一堆就是让你测试看效果0.0!!!

对象级别的权限

如果我们的数据需要所有人看见,但是只有数据的创建人可以删除或者更新数据,
那么我们需要自定义权限:
在snippets应用中创建permissions.py文件:

from rest_framework import permissions

class IsOwnerOrReadOnly(permissions.BasePermission):
    """
    Custom permission to only allow owners of an object to edit it.
    """

    def has_object_permission(self, request, view, obj):
        # Read permissions are allowed to any request,
        # so we'll always allow GET, HEAD or OPTIONS requests.
        if request.method in permissions.SAFE_METHODS:
            return True

        # Write permissions are only allowed to the owner of the snippet.
        return obj.owner == request.user

接下来我们需要在SnippetDetail视图类中编辑permission_classes
属性,来给我们的snippet实例添加自定义的权限:

from snippets.permissions import IsOwnerOrReadOnly
permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                      IsOwnerOrReadOnly,)

测试看效果:此处省略若干英文单词~

现在我们的API中有若干权限,那么我们想要访问这些API,需要给请求授权:

现在我们并没有任何给请求授权的类,那么默认的使用SessionAuthentication
BasicAuthentication
当我们通过浏览器和API交互时,只要一登录,我们浏览器的session就会给requests相应的授权;
当我们通过编程命令和API交互时,需要给每个请求添加具体的认证信息,否则会报异常:

http POST http://127.0.0.1:8000/snippets/ code="print 123"

{
    "detail": "Authentication credentials were not provided."
}

使用之前创建的账户信息进行访问,成功:

http -a admin:password123 POST http://127.0.0.1:8000/snippets/ code="print 789"

{
    "id": 1,
    "owner": "admin",
    "title": "foo",
    "code": "print 789",
    "linenos": false,
    "language": "python",
    "style": "friendly"
}

Summary,还需要吗?!我就知道不需要了,累吐血了~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值