前言
当用户登录后,才有操作当前用户的权限,只可以操作自己的账户,不能操作别人的账户,怎样实现?这就需要用到权限认证。
authentication是身份认证,用于判断当前用户的登录方式是哪种认证方式。
permission是权限认证,判断哪些用户有操作权限
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属性中的身份验证信息来确定是否应允许传入请求。
当权限检查失败时,将根据一下规则返回Http403 Forbidden或Http 401 Unauthorized:
如果收到的请求身份验证通过,但是权限验证失败,则返回Http403 Forbidden;
如果收到的请求身份验证失败,且最高优先级验证类不能使用WWW-Authenticate请求头,则返回403Forbidden;
如果收到的请求身份验证失败,且最高优先级验证类能使用WWW-Authenticate请求头,则返回401 Unauthorized;
权限级别也有四种:
- AllowAny 允许所有用户
- IsAuthenticated 表示仅仅允许身份验证通过的用户访问,其他用户无法访问。
- IsAdminUser 表示仅仅允许管理员用户访问,普通用户无法访问。
- IsAuthenticatedOrReadOnly 表示仅仅允许身份验证通过的用户访问,或者只允许只读请求(GET请求)访问。
settings.py相关配置
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'ke25', 'xadmin', 'rest_framework', 'rest_framework.authtoken', ]
settings.py文件可以全局配置,会对所有的接口生效,REST_FRAMEWORK添加权限认证方式和身份认证方式
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', # token认证 ), # 权限认证 全局配置 'DEFAULT_PERMISSION_CLASSES':( #'rest_framework.permissions.IsAuthenticated',# IsAuthenticated 仅通过认证的用户 'rest_framework.permissions.AllowAny',# AllowAny 允许所有用户 #'rest_framework.permissions.IsAdminUser',# IsAdminUser 仅管理员用户 #'rest_framework.permissions.IsAuthenticatedOrReadOnly', # IsAuthenticatedOrReadOnly 认证的用户可以完全操作,否则只能get读取 ), ) }
局部添加权限
局部权限只针对当前的接口生效,登录生成token,登录允许所有已有用户登录,设置局部权限:
permission_classes = (AllowAny,) #允许所有用户
from . import models from django.shortcuts import render 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.permissions import IsAuthenticated,AllowAny from rest_framework.authentication import TokenAuthentication from rest_framework import serializers class LoginViewSet(APIView): '''登录方法''' permission_classes = (AllowAny,) #允许所有用户 def post(self, request, *args, **kwargs): username = request.data.get('username') password = request.data.get('password') user = auth.authenticate(username=username, password=password) if not user: return JsonResponse({"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身份认证permission权限认证
authentication_classes = (TokenAuthentication,) # token认证
permission_classes = (IsAuthenticated,) # # IsAuthenticated 仅通过认证的用户
views.py代码如下:
class CardAPISerializer(serializers.ModelSerializer): '''序列化数据的类,根据model表来获取字段''' class Meta: model = models.Card fields = '__all__' # fields = ('card_id','card_user') class CardListAPIView(APIView): '''REST framework的APIView实现获取card列表 ''' '''return list of all user''' authentication_classes = (TokenAuthentication,)#token认证 permission_classes = (IsAuthenticated,)#IsAuthenticated仅通过认证的用户 def get(self, request, format=None): cards = models.Card.objects.all() serializer = CardAPISerializer(cards,many=True) return JsonResponse({"code":0, "msg":"查询成功", "data":serializer.data}) def post(self,request,format=None): '''create Card 反序列化''' verify_data = CardAPISerializer(data=request.data) # 只改这里 if verify_data.is_valid(): # 判断数据是否合法 verify_data.save() return JsonResponse({"code": 0, "msg": "创建成功", "data": request.data}) else: return JsonResponse({"code": 0, "msg": "创建成功", "data":'request data invaild %s'% verify_data.errors})
models.py
from django.db import models # Create your models here. class Card(models.Model): card_id = models.IntegerField(verbose_name="卡号") card_user = models.CharField(verbose_name='姓名',max_length=128) add_time = models.DateTimeField(verbose_name='日期',auto_now_add=True) class Meta: verbose_name = '银行卡账户' verbose_name_plural = '银行卡账户信息' def __str__(self): return self.card_id
urls.py
url(r'^api/v1/login/$', vie.LoginViewSet.as_view()), url(r'api/v1/cardlist/$', vie.CardListAPIView.as_view()),
接口关联测试
登录接口
登录接口response,获取token值
将token添加到cardlist接口请求头
如果token错误,或者没有token就会出现401 Unauthorized