適合小白的Django rest_framework Token入門

出自:https://blog.csdn.net/yueguangMaNong/article/details/90519819

前言

我為什么要寫這篇文章猿涨?

最近由于工作需要聂宾,在原來的項目(Django,B/S)的基礎上需要增加和客戶端(Client)的通信救崔。這個時候session機制就不合適了,需要用到token。我選擇了Rest Framework 插件來完成這個功能逆害。關于django token的教程晋南,網上一搜一大堆惠猿,我為什么還要寫?主要由以下幾點:


飲水思源:寫這篇文章之前,我被各種bug折磨了一天偶妖,借鑒了兩位大佬的東西姜凄,歡迎去他們下面查看原文。

http://www.reibang.com/p/e0a206212df4

http://www.reibang.com/p/078fb116236e?


網上文章雖然多趾访,但多數(shù)是大神的教程态秧,神龍見首不見尾,原理一講扼鞋,一段關鍵代碼貼上來就完事了申鱼,對我這樣的學渣實在是不怎么友好。

做個學習記錄云头,給后來者一個方便

開始

整個過程總共分為以下幾步

創(chuàng)建一個 Django項目捐友,新建一個app(廢話)

安裝?django-rest-framework (還是廢話)

在settings中注冊rest-framework,配置 REST_FRAMEWORK

編寫自己的驗證方法溃槐,并加入REST_FRAMEWORK配置

在登陸視圖中創(chuàng)建 Token

在操作視圖中添加 Toekn 驗證

使用postman 驗證

創(chuàng)建Django項目

我相信搜索到這篇文章的都不是0基礎匣砖,起碼創(chuàng)建項目,新增一個app是沒問題的吧昏滴。我就略過這步了猴鲫。如果有需要指導創(chuàng)建項目,新增app的谣殊,請留言拂共!


安裝 REST_FRAMEWORK

> pip install django-rest-framework


注冊 rest-framework并配置

不需要導入這個包,直接注冊即可

INSTALLED_APPS = [

? ? ...

? ? 'rest_framework.authtoken'

? ? ...

]

配置一下姻几, 這個是必須的匣缘,不然返回數(shù)據的時候回報錯

REST_FRAMEWORK = {

? ? 'DEFAULT_RENDERER_CLASSES': (

? ? ? ? 'rest_framework.renderers.JSONRenderer',

? ? ? ? 'rest_framework.renderers.BrowsableAPIRenderer',

? ? ),

}


編寫我們的驗證方法

在app下面創(chuàng)建一個名為auth.py的文件,將下面的內容寫入這個文件中

import datetime

from django.utils.translation import ugettext_lazy

from django.core.cache import cache

from rest_framework.authentication import BaseAuthentication

from rest_framework import exceptions

from rest_framework.authtoken.models import Token

from rest_framework import HTTP_HEADER_ENCODING

# 獲取請求頭信息

def get_authorization_header(request):

? ? auth = request.META.get('HTTP_AUTHORIZATION', b'')

? ? if isinstance(auth, type('')):

? ? ? ? auth = auth.encode(HTTP_HEADER_ENCODING)

? ? return auth

# 自定義認證方式鲜棠,這個是后面要添加到設置文件的

class ExpiringTokenAuthentication(BaseAuthentication):

? ? model = Token

? ? def authenticate(self, request):

? ? ? ? auth = get_authorization_header(request)

? ? ? ? if not auth:

? ? ? ? ? ? return None

? ? ? ? try:

? ? ? ? ? ? token = auth.decode()

? ? ? ? except UnicodeError:

? ? ? ? ? ? msg = ugettext_lazy("無效的Token肌厨, Token頭不應包含無效字符")

? ? ? ? ? ? raise exceptions.AuthenticationFailed(msg)

? ? ? ? return self.authenticate_credentials(token)

? ? def authenticate_credentials(self, key):

? ? ? ? # 嘗試從緩存獲取用戶信息(設置中配置了緩存的可以添加,不加也不影響正常功能)

? ? ? ? token_cache = 'token_' + key

? ? ? ? cache_user = cache.get(token_cache)

? ? ? ? if cache_user:

? ? ? ? ? ? return cache_user, cache_user? # 這里需要返回一個列表或元組豁陆,原因不詳

? ? ? ? # 緩存獲取到此為止

? ? ? ? # 下面開始獲取請求信息進行驗證

? ? ? ? try:

? ? ? ? ? ? token = self.model.objects.get(key=key)

? ? ? ? except self.model.DoesNotExist:

? ? ? ? ? ? raise exceptions.AuthenticationFailed("認證失敗")

? ? ? ? if not token.user.is_active:

? ? ? ? ? ? raise exceptions.AuthenticationFailed("用戶被禁用")

? ? ? ? # Token有效期時間判斷(注意時間時區(qū)問題)

? ? ? ? # 我在設置里面設置了時區(qū) USE_TZ = False柑爸,如果使用utc這里需要改變。

? ? ? ? if (datetime.datetime.now() - token.created) > datetime.timedelta(hours=0.1*1):

? ? ? ? ? ? raise exceptions.AuthenticationFailed('認證信息已過期')

? ? ? ? # 加入緩存增加查詢速度盒音,下面和上面是配套的表鳍,上面沒有從緩存中讀取,這里就不用保存到緩存中了

? ? ? ? if token:

? ? ? ? ? ? token_cache = 'token_' + key

? ? ? ? ? ? cache.set(token_cache, token.user, 600)


? ? ? ? # 返回用戶信息

? ? ? ? return token.user, token

? ? def authenticate_header(self, request):

? ? ? ? return 'Token'

將這個驗證方法注冊到配置里面

REST_FRAMEWORK = {

? ? # 新增的

? ? 'DEFAULT_AUTHENTICATION_CLASSES': (

? ? ? ? 'apps.xtauth.auth.ExpiringTokenAuthentication',? # 根據自己的實際情況填寫路徑

? ? ),

? ? # 下面是剛剛已經寫好的

? ? 'DEFAULT_RENDERER_CLASSES': (

? ? ? ? 'rest_framework.renderers.JSONRenderer',

? ? ? ? 'rest_framework.renderers.BrowsableAPIRenderer',

? ? ),

}

一切準備工作就緒祥诽,下面就開始使用它了譬圣。


創(chuàng)建Token

創(chuàng)建token首先要有用戶,我這里直接使用系統(tǒng)的User表雄坪,就不直接創(chuàng)建了

下面的代碼寫在視圖views.py

from django.http import JsonResponse

from django.shortcuts import HttpResponse

from rest_framework.decorators import api_view

from rest_framework.authtoken.models import Token

from django.contrib import auth

@api_view(['POST'])

def login(request):

? ? receive = request.data

? ? username = receive.get('username')

? ? password = receive.get('password')

? ? user = auth.authenticate(username=username, password=password)

? ? if not user:

? ? ? ? return HttpResponse("用戶名和密碼不匹配")

? ? # 校驗通過

? ? # 刪除原有的Token

? ? old_token = Token.objects.filter(user=user)

? ? old_token.delete()

? ? # 創(chuàng)建新的Token

? ? token = Token.objects.create(user=user)

? ? return JsonResponse({"username": user.username, "token": token.key})

說明一下:

裝飾器api.view是rest framework提供的厘熟,它可以指定請求方法,如果這里使用了它,那么針對這個方法的CSRF就會失效绳姨,所以不需要再額外添加 csrf_exempt 裝飾器

這個裝飾器會給request對象添加一個data屬性登澜,post上傳的數(shù)據都可以在這里面直接獲取,示例中用戶名和密碼就是直接從里面取出來的飘庄,上傳的json數(shù)據已經轉換好了脑蠕,直接獲取即可。

auth.authenticate() 方法是Django提供的驗證用戶名和密碼是否匹配的跪削,和rest framework毛關系都沒有

創(chuàng)建token是通過Token.objects.create() 創(chuàng)建的谴仙。創(chuàng)建之前最好先刪除原來的token,否則一個用戶多次創(chuàng)建token會報錯的碾盐,數(shù)據庫唯一約束


驗證Token

創(chuàng)建好了之后晃跺,自然就該驗證了,寫一個什么函數(shù)驗證一下

@api_view(['POST'])

def do_something(request):

? ? receive = request.data

? ? print(receive)

? ? if request.user.is_authenticated:? # 驗證Token是否正確

? ? ? ? print("Do something...")

? ? ? ? return JsonResponse({"msg": "驗證通過"})

? ? else:

? ? ? ? print("驗證失敗")

? ? ? ? return JsonResponse({"msg": "驗證失敗"})

說明:

request.user.is_authenticated:這個是驗證Token是否正確的廓旬。user對象也是使用了api_view裝飾器之后添加的哼审。

很明顯谐腰,rest framework孕豹, 我們應該遵循RestFul規(guī)范,返回json格式數(shù)據才是中規(guī)中矩的十气。如果起前面的設置中REST_FRAMEWORK下面沒有配置 rest_framework.renderers.JSONRenderer 的話励背,這里會報錯排监,一定要添加


路由配置

from django.urls import path

from . import views

urlpatterns = [

? ? path('login/', views.login),

? ? path('doSomething/', views.do_something),

]

很簡單支救,就是簡單的登陸和操作驗證兩個url


Postman測試

功能都已經完成了骨宠,就是這么簡單楼眷,最后我們來測試一下

先創(chuàng)建一個用戶:

用戶名:zhangsan? ? ? ?密碼: 123456

然后使用Postman登陸獲取Token

可以看到踱卵,一切都那么自然疏旨,成功獲取到了Token

接下來就來測試一下這個token的正確性

過期的情況

由于之前時間設置得太短贝咙,導致寫完文字后token已經失效了虑啤,尷尬鸳慈。來個正確的打開方式

成功的示范

注意幾點:

headers里面的key只能是【Authorization】饱溢,別的名稱將會驗證失敗,至于能不能走芋,應該是可以的绩郎,只是我不知道(手動狗頭)

token一定要在有效期內才能驗證通過(廢話),時間在auth.py文件里面設置翁逞,注意時區(qū)的問題肋杖。自己試驗,建議設置USE_TZ = False挖函,簡單粗暴状植。


OK,大功告成,希望這篇文章能夠幫你浅萧,歡迎留言回復逐沙。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市洼畅,隨后出現(xiàn)的幾起案子吩案,更是在濱河造成了極大的恐慌,老刑警劉巖帝簇,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件徘郭,死亡現(xiàn)場離奇詭異,居然都是意外死亡丧肴,警方通過查閱死者的電腦和手機残揉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來芋浮,“玉大人抱环,你說我怎么就攤上這事≈较铮” “怎么了镇草?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長瘤旨。 經常有香客問我梯啤,道長,這世上最難降的妖魔是什么存哲? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任因宇,我火速辦了婚禮,結果婚禮上祟偷,老公的妹妹穿的比我還像新娘察滑。我一直安慰自己,他們只是感情好修肠,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布贺辰。 她就那樣靜靜地躺著,像睡著了一般氛赐。 火紅的嫁衣襯著肌膚如雪魂爪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天艰管,我揣著相機與錄音滓侍,去河邊找鬼。 笑死牲芋,一個胖子當著我的面吹牛撩笆,可吹牛的內容都是我干的捺球。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼夕冲,長吁一口氣:“原來是場噩夢啊……” “哼氮兵!你這毒婦竟也來了?” 一聲冷哼從身側響起歹鱼,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤泣栈,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后弥姻,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體南片,經...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年庭敦,在試婚紗的時候發(fā)現(xiàn)自己被綠了疼进。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡秧廉,死狀恐怖伞广,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情疼电,我是刑警寧澤嚼锄,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站澜沟,受9級特大地震影響灾票,放射性物質發(fā)生泄漏峡谊。R本人自食惡果不足惜茫虽,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望既们。 院中可真熱鬧濒析,春花似錦、人聲如沸啥纸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽斯棒。三九已至盾致,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間荣暮,已是汗流浹背庭惜。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留穗酥,地道東北人护赊。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓惠遏,卻偏偏與公主長得像,于是被迫代替她去往敵國和親骏啰。 傳聞我的和親對象是個殘疾皇子节吮,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內容