django rest framework許可權管理實戰
前言
本文標題為實戰,那麼希望你已經搭建好了環境。如果沒有,請參考官方文件進行環境搭建:
通過學習這個例子,你可以學到:
- 如何使用django rest framework去實現RESTful api
- 學會如何進行許可權控制
希望對rest framework已經有了一定的瞭解,至少要知道serializers的作用,還有Response等等,基礎知識還是要有的。
實戰內容
我們實戰的內容是,搭建一個部落格應用,提供註冊,登入功能。
所有使用者都可以發表部落格。
實現部落格的建立者可以對自己的部落格進行修改,刪除等操作。
非建立者只能進行瀏覽。
##思路
在登入的時候,將使用者的id儲存到request.session中,當用戶修改部落格或者是刪除部落格的時候,進行比對。所以許可權管理主要是permissions.py這個檔案的編寫,之後再在views.py中進行設定許可權即可。
開始
-
新建一個project:
django-admin.py startproject rest
-
新建一個app:
python manage startapp blog
-
在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
-
在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')
-
在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')
-
在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."}
-
在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()), ]
-
在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 }
-
建立資料庫
python manage makemigrations
python manage migrate
到此為止,就全部完成了,接下來可以訪問API了!
使用
為了方便提交json資料,我使用了一款名叫Postman的工具,是GoogleChrome的一款外掛,建議你也安裝一個。如果你不想安裝,那麼你可以使用命令列的httpie工具,安裝:
$ pip install --upgrade pip setuptools
$ pip install --upgrade httpie
-
註冊一個使用者,向http://127.0.0.1:8000/register提交一個post請求,引數如圖:
對應的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
-
先不登入,直接提交一篇部落格:
對應httpie的命令:http --json POST http://127.0.0.1:8000/blogs/ title="第一篇部落格" body="哎喲 不錯哦"
結果是:
{ "detail": "Authentication credentials were not provided." }
-
登入:
對應的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"
}
-
像第2點一樣,再次提交部落格,返回結果:
{ "id": 5, "title": "ICELEE的部落格", "body": "哎喲 不錯哦", "owner": "ICE" }
你可以再建立一個使用者,然後登入,試著刪除上面的部落格試試,估計你是沒辦法刪除的,因為你不是部落格的擁有者,這就是許可權控制的作用啦~~~