django rest framework我的学习笔记(六)————Tutorial4.认证于受权

官网地址
目前,咱们的API没有对如 edit 或者 delect作出任何限制。咱们但愿有一些更加高级的功能可以作到:html

  • Code snippets 应该永远和建立者相关
  • 只有认证的用户才可以建立snippets
  • 只有建立者才能更新或者删除他的snippet
  • 没有认真的用户应该只能读

向咱们的model添加内容

咱们对咱们的code snippets models作一些修改。首先,咱们添加几个字段。其中一个字段用于表示code snippet的建立者。另一个字段用于储存突出显示的代码的HTML表示形式。
添加下列两个字段到 models.py文件中的Snippetmodel。python

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

咱们也须要确保,当这个model被保存的时候,咱们使用pygments代码高亮库来填充咱们的highlighted字段。
咱们须要导入一些东西:sql

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

而后咱们须要为咱们的Snippetmodel添加.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)

当全部都昨晚以后,咱们须要更新咱们的数据库。一般,为了实现这一点,咱们会建立数据迁移文件(migration),可是本教程用于教学,因此咱们直接删除数据库并从新建立。django

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

你也能够建立几个不一样的用户来测试咱们的API。最快的方式就是使用createsuperuser命令。编程

python manage.py createsuperuser

为咱们的User models 添加终端

如今,咱们有一些可用的用户了。咱们最好为咱们的API添加用户代理。api

from django.contrib.auth.models import User

class UserSerializer(serializer.ModelSerializer):
    snippets = serializer.PrimaryKeyRelatedField(many=True,queryset=Snippet.objects.all())
    
    class Meta:
        model = User
        fields = {"id","username","snippets"}

由于snippetsUsermodels 的反向关系,在默认的ModelSerializerclass中,并不会包含这种关系,因此咱们须要添加一个明确的字段来表示这个关系。浏览器

咱们还须要添加一些view在views.py文件中。咱们但愿咱们的用户表示为只读视图。因此咱们使用ListAPIViewRetrieveAPIView通用class-based views.session

from django.contrib.auth.models import User
from snippets.Serializers import UserSerializer

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

最后,咱们须要添加咱们的视图到API中,添加如下的patterns到urls.py文件中:app

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

关联User和Snippets

如今,若是咱们建立一个code snippet,咱们没法将建立的snippet和建立者关联起来,User数据不是做为序列化的一部分发送的,而是做为request的一个属性.咱们处理这个问题的方法是,在咱们的snippet views中重写.perform_create()方法,这容许咱们修改实例保存的方式,处理任何传入请求和请求url中的参数。
SnippetListview class中,添加以下方法:

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

咱们的create()序列化方法将会从request中验证经过的数据里添加额外的owner字段。

更新咱们的serializer

如今,咱们的snippet已经和他的建立者关联了。让咱们来更新SnippetSerializer来体现这个关联。添加如下的字段在咱们的serializers.py文件中:

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

注意:确保你的Meta class的fields中添加了'owner'
这个字段作了一个颇有趣的事。这个source参数控制哪个属性用于填充字段,而且能够指向这个序列化实例上的任何属性,它也可使用.来访问属性下的属性,这相似于django的模板语言.
这个字段咱们也可以添加ReadOnlyFieldclass,来不一样于其余字段,如CharField,BooleanField等...ReadOnlyField永远只能读,而且使用序列化表示,可是当咱们反序列化时,不能更新模块。咱们也可以使用CharField(read_only=True)

为咱们的视图添加必要的权限

如今,咱们的code snippets 已经和users关联,咱们但愿确保只有认证的用户才可以建立,更新和删除code snippets。
REST framework包含了几种permission class,咱们可使用这些类来限制哪些人有权限使用这些view.在这个案例中,咱们须要的是IsAuthenticateOrReadOnly。这将确保认证用户拥有读写权限,而未认证用户只有读的权限。
首先,添加如下的内容到views模块。

from rest_framework import permissions

而后,添加如下的属性到SnippetListSnippetDetailview classes

permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

在咱们的Browsable API中添加登陆

若是你打开浏览器并导航到browsable API,你发现你没有登陆,不可以建立新的code snippets.为了作到这一点,咱们须要用户可以登陆。
咱们可以在咱们的browsable API中添加login view,来编写咱们的项目级urls.py文件(根urls.py文件)。
添加如下内容到文件中:

from django.conf.urls import include

而后,添加login和logout view在咱们的browsable API.

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

事实上,r'^api-auth/'部分,你可使用任何你想用的url。惟一的限制是namespace必须是rest_framework。在django1.9+中,REST framework将设置namespace,因此你能够把这个限制排除在外。
如今,若是你再一次打开浏览器并刷新页面,你将会看到页面的右上角看到登陆连接。
建立了一些code snippets后,导航到'users/',在每一个user的snippets字段中,都会显示相对应的code snippets。

Object级别的权限

咱们但愿全部用户都能看到全部code snippets,可是只有建立者可以修改或者删除他的code snippets.
为了实现这个功能,咱们须要建立一个自定义的permission.
在snippets app 中,建立一个新文件permissions.py

from rest_framework import permissions

class IsOwnerOrReadOnly(permissions.BasePermission):
    """
    自定义permission 保证只有全部者可以编写。
    """
    def has_object_permission(self,request,view,obj):
        #任何请求都拥有读权限
        #因此咱们永远容许GET,HEAD,OPTIONS requests
        if request.method in permissions.SAFE_METHODS:
            return True
        return obj.owner == request.user

如今,咱们将咱们自定义的permission添加到snippetDetailview class中:

permission_classes = (permissions.IsAuthenticateOrReadOnly,IsOwnerOrReadOnly)

API认证

由于咱们如今为咱们的API设置了permission,若是咱们须要写任何snippets,咱们须要认证咱们的请求。咱们尚未设置任何身份认证,因此默认的认证是sessionAuthenticationBasucAuthentication.当咱们经过浏览器与API交互时,咱们能够登陆,而后浏览器的session将会为咱们的请求提供身份认证。若是咱们以编程的方式于API进行交互,咱们须要在每一个请求上显式地提供身份验证凭证。
若是咱们尝试建立一个snippet,就会获得一个错误:

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

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

咱们能够包含咱们的帐户名密码来请求建立:

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

{
    "id": 1,
    "owner": "tom",
    "title": "foo",
    "code": "print 789",
    "linenos": false,
    "language": "python",
    "style": "friendly"
}
相关文章
相关标签/搜索