1. 程式人生 > >django rest framework許可權管理實戰

django rest framework許可權管理實戰

前言

本文標題為實戰,那麼希望你已經搭建好了環境。如果沒有,請參考官方文件進行環境搭建:

官方教程

通過學習這個例子,你可以學到:

  1. 如何使用django rest framework去實現RESTful api
  2. 學會如何進行許可權控制

希望對rest framework已經有了一定的瞭解,至少要知道serializers的作用,還有Response等等,基礎知識還是要有的。

實戰內容

我們實戰的內容是,搭建一個部落格應用,提供註冊,登入功能。

所有使用者都可以發表部落格。

實現部落格的建立者可以對自己的部落格進行修改,刪除等操作。

非建立者只能進行瀏覽。
##思路
在登入的時候,將使用者的id儲存到request.session中,當用戶修改部落格或者是刪除部落格的時候,進行比對。所以許可權管理主要是permissions.py這個檔案的編寫,之後再在views.py中進行設定許可權即可。

開始

  1. 新建一個project:

    django-admin.py startproject rest

  2. 新建一個app:

    python manage startapp blog

  3. 在blog的models中,建立我們需要的model:

    class User(models.Model):
        username = models.CharField(max_length=20,null=False)
        password = models.CharField(max_length=20,null=False)
        name = models.CharField(max_length=10,null=False) #名稱
    
    class Blog(models.Model):
        title = models.CharField(max_length=50,null=False)
        body = models.TextField()
        owner = models.ForeignKey(User) #部落格的建立者
        
        def __str__(self):
            return self.title
    
  4. 在blog目錄下新建一個serializers.py序列化檔案:

    from rest_framework import serializers
    from blog.models import *
    
    class BlogSerializer(serializers.ModelSerializer):
        owner = serializers.ReadOnlyField(source='owner.name') #只讀
        class Meta:
            model = Blog
            fields = ('id', 'title', 'body', 'owner')
    
    #用於註冊的時候返回json資料
    class UserRegisterSerializer(serializers.ModelSerializer):
        class Meta:
            model = User
            fields = ('id', 'username','password', 'name')
    
    class UserSerializer(serializers.ModelSerializer):
        blog_set = serializers.PrimaryKeyRelatedField(many=True, queryset=Blog.objects.all())
        class Meta:
            model = User
            fields = ('id', 'username', 'blog_set')
    
  5. 在blog目錄下新建一個許可權檔案:permissions.py
    當用戶登入之後,我們會在requests.session中加入使用者的id,所以我們用id作為許可權判斷的依據:

    #coding=utf-8
    from rest_framework import permissions
    class IsOwnerOrReadOnly(permissions.BasePermission):
        def has_permission(self, request, view):
            if request.method in permissions.SAFE_METHODS:
                return True
            return request.session.get('user_id') is not None
            
        def has_object_permission(self, request, view, blog):
            # 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
            return blog.owner.id == request.session.get('user_id')
    
  6. 在views.py中,我們加入下列程式碼:

    # -*- coding: utf-8 -*-
    from __future__ import unicode_literals
    
    from django.shortcuts import render
    
    # Create your views here.
    from rest_framework import viewsets
    from rest_framework.permissions import AllowAny
    from rest_framework.response import Response
    from rest_framework.status import HTTP_200_OK, HTTP_400_BAD_REQUEST
    from rest_framework.views import APIView
    
    from blog.permissions import IsOwnerOrReadOnly
    from blog.serializers import *
    
    #用於登入
    class UserLoginAPIView(APIView):
        queryset = User.objects.all()
        serializer_class = UserSerializer
        permission_classes = (AllowAny,)
    
        def post(self, request, format=None):
            data = request.data
            username = data.get('username')
            password = data.get('password')
            user = User.objects.get(username__exact=username)
            if user.password == password:
                serializer = UserSerializer(user)
                new_data = serializer.data
                # 記憶已登入使用者
                self.request.session['user_id'] = user.id
                return Response(new_data, status=HTTP_200_OK)
            return Response('password error', HTTP_400_BAD_REQUEST)
    
    #用於註冊
    class UserRegisterAPIView(APIView):
        queryset = User.objects.all()
        serializer_class = UserRegisterSerializer
        permission_classes = (AllowAny,)
    
        def post(self, request, format=None):
            data = request.data
            username = data.get('username')
            if User.objects.filter(username__exact=username):
                return Response("使用者名稱已存在",HTTP_400_BAD_REQUEST)
            serializer = UserRegisterSerializer(data=data)
            if serializer.is_valid(raise_exception=True):
                serializer.save()
                return Response(serializer.data,status=HTTP_200_OK)
            return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)
    
    #用於部落格的增刪改查  除了檢視,其他都需要許可權
    class BlogViewSet(viewsets.ModelViewSet):
        queryset = Blog.objects.all()
        serializer_class = BlogSerializer
        permission_classes = (IsOwnerOrReadOnly,)
    
        def perform_create(self, serializer):
            print self.request.user
            serializer.save(owner=User.objects.get(id=self.request.session.get('user_id')))
    
    class UserViewSet(viewsets.ModelViewSet):
        queryset = User.objects.all()
        serializer_class = UserSerializer
    
    

    這樣,我們就實現了許可權的控制,如果檢視部落格,那麼不會有什麼問題。如果要提交部落格,或者是刪除部落格,都是需要使用者登入的,而且刪除需要使用者本人。沒有許可權則會返回{"detail": "Authentication credentials were not provided."}

  7. 在rest的urls.py中,我們為我們的view設定路由:

    from django.conf.urls import url,include
    from django.contrib import admin
    from rest_framework import routers
    from blog.views import *
    router = routers.DefaultRouter()
    router.register(r'users',UserViewSet)
    router.register(r'blogs',BlogViewSet)
    
    urlpatterns = [
        url(r'^',include(router.urls)),
        url(r'^admin/', admin.site.urls),
        url(r'^register',UserRegisterAPIView.as_view()),
        url(r'^login',UserLoginAPIView.as_view()),
    ]
    
  8. 在settings.py中,加入一些程式碼:

    INSTALLED_APPS = [
    	...
    	...
        'rest_framework',#rest框架 
        'blog',#我們的app
    ]
    #add to your settings.py
    REST_FRAMEWORK = {
        'DEFAULT_PERMISSION_CLASSES': [
            'rest_framework.permissions.AllowAny',
        ],
        'PAGE_SIZE': 10
    }
    
  9. 建立資料庫

python manage makemigrations

python manage migrate

到此為止,就全部完成了,接下來可以訪問API了!

使用

為了方便提交json資料,我使用了一款名叫Postman的工具,是GoogleChrome的一款外掛,建議你也安裝一個。如果你不想安裝,那麼你可以使用命令列的httpie工具,安裝:

$ pip install --upgrade pip setuptools

$ pip install --upgrade httpie
  1. 註冊一個使用者,向http://127.0.0.1:8000/register提交一個post請求,引數如圖:
    註冊.png

    對應的httpie命令:

    http --json POST http://127.0.0.1:8000/register username="ICELEE" password="mypass" name="icelee"
    

    返回結果如下:

    {
        "id": 3,
        "username": "ICELEE",
        "password": "mypass",
        "name": "ICE"
    }
    

    因為我已經註冊了兩個了,所以id為3

  2. 先不登入,直接提交一篇部落格:
    提交部落格.png
    對應httpie的命令:

    http --json POST http://127.0.0.1:8000/blogs/ title="第一篇部落格" body="哎喲 不錯哦"

    結果是:

    {
        "detail": "Authentication credentials were not provided."
    }
    
  3. 登入:
    登入.png

對應的httpie命令:
http --json POST http://127.0.0.1:8000/login/ username="ICELEE" password="mypass"

返回的結果:

{
    "id": 3,
    "blog_set": [],
    "username": "ICELEE",
    "password": "mypass",
    "name": "ICE"
}
  1. 像第2點一樣,再次提交部落格,返回結果:

    {
        "id": 5,
        "title": "ICELEE的部落格",
        "body": "哎喲 不錯哦",
        "owner": "ICE"
    }
    

你可以再建立一個使用者,然後登入,試著刪除上面的部落格試試,估計你是沒辦法刪除的,因為你不是部落格的擁有者,這就是許可權控制的作用啦~~~