python测试开发django-61.权限认证(permission)
- 2019 年 10 月 4 日
- 笔记
前言
用户登录后,才有操作当前用户的权限,不能操作其它人的用户,这就是需要用到权限认证,要不然你登录自己的用户,去操作别人用户的相关数据,就很危险了。
- authentication是身份认证,判断当前用户的登录方式是哪种认证方式
- permissions 是权限认证,判断哪些用户有操作权限
authentication身份认证
身份验证是将收到的请求和一组标识证书(如用户名密码、令牌)进行关联的一种机制,以便权限和策略可以根据这个标识证书来决定是否允许该请求。因此,身份验证发生在验证权限和限制检查之前。
当收到的请求通过身份验证时:
- request.user属性会设置为django.contrib.auth.User对象,即我们登录的对象(我们定义用户继承于User)。
- request.auth会设置为对应的Token(如果带有Token)或者None(如果不带有Token)。 当收到请求身份验证失败时:
- request.user属性会设置为django.contrib.auth.models.AnonymousUser对象。
- request.auth会设置为None。
django rest framework权限和认证有四种方式:
- BasicAuthentication 此身份验证方案使用HTTP基本身份验证,根据用户的用户名和密码进行签名。基本身份验证通常仅适用于测试
- TokenAuthentication 此身份验证方案使用基于令牌的简单HTTP身份验证方案。令牌认证适用于客户端 – 服务器设置,例如本机桌面和移动客户端。
- SessionAuthentication 此身份验证方案使用Django的默认会话后端进行身份验证。会话身份验证适用于与您的网站在同一会话上下文中运行的AJAX客户端。
- RemoteUserAuthentication 此身份验证方案允许您将身份验证委派给Web服务器,该服务器设置REMOTE_USER 环境变量。
permission权限认证
权限检查通常使用request.user和request.auth属性中的身份验证信息来确定是否应允许传入请求。
当权限检查失败时,将根据以下规则返回HTTP 403 Forbidden或HTTP 401 Unauthorized:
- 如果收到的请求身份验证通过,但是权限验证失败,则返回HTTP 403 Forbidden;
- 如果收到的请求身份验证失败,且最高优先级验证类不能使用WWW-Authenticate请求头,则返回HTTP 403 Forbidden;
- 如果收到的请求身份验证失败,且最高优先级验证类可以使用WWW-Authenticate请求头,则返回HTTP 401 Unauthorized
权限级别也有四种
- AllowAny 允许所有用户
- IsAuthenticated 表示仅仅允许身份验证通过的用户访问,其他用户无法访问。
- IsAdminUser 表示仅仅允许管理员用户访问,普通用户无法访问。
- IsAuthenticatedOrReadOnly 表示仅仅允许身份验证通过的用户访问,或者只允许只读请求(GET请求)访问。
相关配置
在settings.py中,INSTALLED_APPS添加rest_framework和rest_framework.authtoken
INSTALLED_APPS = [ 'apiapp', 'rest_framework.authtoken', 'rest_framework', ]
REST_FRAMEWORK添加权限认证方式和身份认证方式
REST_FRAMEWORK = { # 权限认证 'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticated', # IsAuthenticated 仅通过认证的用户 'rest_framework.permissions.AllowAny', # AllowAny 允许所有用户 'rest_framework.permissions.IsAdminUser', # IsAdminUser 仅管理员用户 'rest_framework.permissions.IsAuthenticatedOrReadOnly', # IsAuthenticatedOrReadOnly 认证的用户可以完全操作,否则只能get读取 ), # 身份认证 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', # token认证 ) }
登录生成token
登录的时候,不需要身份认证,permission_classes设置成AllowAny,允许所有的用户
permission_classes = (AllowAny,) # AllowAny 允许所有用户
from django.http import JsonResponse from django.shortcuts import HttpResponse from rest_framework.authtoken.models import Token from django.contrib import auth from rest_framework.views import APIView from rest_framework import viewsets from rest_framework import serializers from .models import * from django.http import QueryDict from rest_framework.request import Request from rest_framework.permissions import IsAuthenticated,AllowAny from rest_framework.authentication import TokenAuthentication '''作者:上海悠悠,QQ交流群:750815713''' class LoginViewSet(APIView): '''登录获取token方法''' permission_classes = (AllowAny,) # AllowAny 允许所有用户 def post(self, request, *args, **kwargs): username = request.data.get('username') # print(username) password = request.data.get('password') user = auth.authenticate(username=username, password=password) if not user: return HttpResponse({"code": 0, "msg": "用户名或密码不对!"}) # 删除原有的Token old_token = Token.objects.filter(user=user) old_token.delete() # 创建新的Token token = Token.objects.create(user=user) return JsonResponse({"code": 0, "msg": "login success!", "username": user.username, "token": token.key})
添加card相关信息,接着前面一篇讲的,添加authentication_classes和permission_classes
authentication_classes = (TokenAuthentication,) # token认证 permission_classes = (IsAuthenticated,) # # IsAuthenticated 仅通过认证的用户
def get_parameter_dic(request, *args, **kwargs): # 作者:上海悠悠,QQ交流群:750815713 if isinstance(request, Request) == False: return {} query_params = request.query_params if isinstance(query_params, QueryDict): query_params = query_params.dict() result_data = request.data if isinstance(result_data, QueryDict): result_data = result_data.dict() if query_params != {}: return query_params else: return result_data class CardSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Card fields = "__all__" class CardViewSet(viewsets.ModelViewSet): '''# 作者:上海悠悠,QQ交流群:750815713''' authentication_classes = (TokenAuthentication,) # token认证 permission_classes = (IsAuthenticated,) # # IsAuthenticated 仅通过认证的用户 queryset = Card.objects.all() serializer_class = CardSerializer def get(self, request, *args, **kwargs): params=get_parameter_dic(request) return JsonResponse(data=params) def post(self, request, *args, **kwargs): params=get_parameter_dic(request) return JsonResponse(data=params) def put(self, request, *args, **kwargs): params=get_parameter_dic(request) return JsonResponse(data=params)
models.py设计card表
class Card(models.Model): '''银行卡 基本信息 # 作者:上海悠悠,QQ交流群:750815713''' card_id = models.CharField(max_length=30, verbose_name="卡号", default="") card_user = models.CharField(max_length=10, verbose_name="姓名", default="") add_time = models.DateField(auto_now=True, verbose_name="添加时间") class Meta: verbose_name_plural = '银行卡账户' verbose_name = "银行卡账户_基本信息" def __str__(self): return self.card_id
urls.py添加方法地址
from apiapp import views from django.conf.urls import url from rest_framework import routers from django.conf.urls import include # 作者:上海悠悠,QQ交流群:750815713 router = routers.DefaultRouter() router.register(r'cards', views.CardViewSet) urlpatterns = [ url(r'^api/v1/login/$', views.LoginViewSet.as_view()), url(r'^', include(router.urls)), ]
测试接口
先获取登录token,把token值复制出来:1c0debb44fa0054d312616e7000ae78ce396df8e
{ "code": 0, "msg": "login success!", "username": "test", "token": "1c0debb44fa0054d312616e7000ae78ce396df8e" }

访问添加银行卡账号的接口时,需在头部带上token,格式为
Authorization: Token 1c0debb44fa0054d312616e7000ae78ce396df8e
带上token去请求的时候,就可以正常的添加成功

查看数据库card表会有数据新增成功

如果token错误,或者没有token就会出现401 Unauthorized
