Django-RESTful Api 之认证和权限

问题

  • 没有认证和权限功能,任何资源都可以被任意用户随意修改,所以增加认证和权限功能
    • student 与其创建者相互关联
    • 只有经过身份验证 (登陆) 的用户才可以创建 student
    • 只有创建 student 的用户才可以对其进行更新和删除
    • 未经验证 (游客) 用户只能对数据进行访问 (获取) 的功能

给学生增加所有者字段

1
owner = models.ForeignKey('auth.User', related_name='students')

重新生成表

  • 删除数据库、删除迁移文件、重新创建数据库、重新生成迁移文件、执行迁移、将班级数据插入

创建几个用户

1
python manage.py createsuperuser

在 serializers.py 文件中给 User 添加序列化类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from rest_framework import serializers
from myApp.models import Student
from django.contrib.auth.models import User


# 只能序列化Student模型对象
class StudentSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')

class Meta:
model = Student
fields = ("id", "name", "sex", "age", "content", "grade", "owner")


class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ("id", "username", "students")

增加用户的接口

  • 路由:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    from django.conf.urls import url
    from myApp import views
    from rest_framework.urlpatterns import format_suffix_patterns

    urlpatterns = [
    url(r'^students/$', views.StudentsList.as_view()),
    url(r'^students/(?P<pk>\d+)', views.StudentDetail.as_view()),

    # 用户
    url(r'^users/$', views.UsersList.as_view()),
    url(r'^users/(?P<pk>\d+)', views.UserDetail.as_view()),
    ]
    urlpatterns = format_suffix_patterns(urlpatterns)
  • 视图:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    from myApp.models import Student, Grade
    from myApp.serializers import StudentSerializer, UserSerializer
    from rest_framework import generics
    from django.contrib.auth.models import User


    class UsersList(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer


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

把 Student 和 User 关联

  • 概述:此时还不能把 Student 和 User 关联起来,因为在使用的时候 User 的数据时通过 request 传入的,而不是以序列化传递过来的数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    from myApp.models import Student, Grade
    from myApp.serializers import StudentSerializer, UserSerializer
    from rest_framework import generics
    from django.contrib.auth.models import User
    from rest_framework import permissions


    class StudentsList(generics.ListCreateAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

    # 让用户通过POST请求创建一个新的student时,在保存对象数据时,会把request中的user赋值给student的owner属性
    def perform_create(self, serializer):
    serializer.save(owner=self.request.user)

在显示学生时还需要显示学生属于哪个用户,可以选择展示

1
2
3
4
5
6
7
# 只能序列化Student模型对象
class StudentSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')

class Meta:
model = Student
fields = ("id", "name", "sex", "age", "contend", "grade", "owner")

添加权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from myApp.models import Student, Grade
from django.contrib.auth.models import User
from myApp.serializers import StudentSerializer, UserSerializer
from rest_framework import generics
from rest_framework import permissions


class StudentsList(generics.ListCreateAPIView):
queryset = Student.objects.all()
serializer_class = StudentSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

# 让用户通过POST请求创建一个新的student时,在保存对象数据时,会把request中的user赋值给student的owner属性
def perform_create(self, serializer):
serializer.save(owner=self.request.user)


class StudentDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Student.objects.all()
serializer_class = StudentSerializer
# 只有所有者用户才能删除、修改,其他用户只能查询
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

为可浏览的 API 添加登陆功能

  • 在工程目录下的同工程相同名字的目录下的 urls.py 中添加如下代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    from django.conf.urls import url, include
    from django.contrib import admin

    urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^', include('myApp.urls')),
    ]

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

添加对象权限

  • 要实现让所有的 student 可以被所有人访问,但是每个 student 只能被其创建者操作。需要自定义权限,使每个学生只能被他的创建者操作。在 myApp 目录下创建 permissions.py

  • 自定义权限:

    1
    2
    3
    4
    5
    6
    7
    8
    from rest_framework import permissions


    class IsOwnerOrReadOnly(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
    if request.method in permissions.SAFE_METHODS:
    return True
    return obj.owner == request.user
  • 添加自定义权限:

    1
    2
    3
    4
    5
    6
    7
    8
    from myApp.permissions import IsOwnerOrReadOnly


    class StudentDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer
    # 只有所有者用户才能删除、修改,其他用户只能查询
    permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly)

API 授权

  • 现在没有使用 authentication 类,所以项目目前还是使用默认的 SessionAuthentication 和 BaseAuthentication
  • 在浏览器访问 API 的时候,浏览器会存储会话信息
  • 如果通过其他方式操作 API,我们必须在每次发送请求的时候添加授权信息,就是添加用户名和密,否则会报错
    1
    http://user1:sunck1999@127.0.0.1:8000/students/1