前言
用戶登錄后,才有操作當前用戶的權限,不能操作其它人的用戶,這就是需要用到權限認證,要不然你登錄自己的用戶,去操作別人用戶的相關數據,就很危險了。
- 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