關(guān)于Django-rest-framework Token認(rèn)證的一點點問題

最近項目中使用django-rest-framework作為后臺框架溯警,給客戶端返回json結(jié)果。

在用戶驗證方面用到token驗證蝴罪,這是一種安卓/iso/..手機(jī)客戶端常用的,方便的驗證方式。

原理是客戶端給我發(fā)一段字符串,這段字符串是用戶在注冊驴党,登入的時候、服務(wù)器生成的获茬,并關(guān)聯(lián)到用戶港庄。保存到數(shù)據(jù)庫,然后返回給客戶端恕曲,客戶端之后呢鹏氧,就可以憑借這個字符串來確認(rèn)“我是我,不是別人”佩谣。而不用每次驗證都要通過賬號密碼把还。 _ _ _

django-rest-framework 有一套默認(rèn)的token驗證機(jī)制dfs token驗證 具體用法不再細(xì)講了,官方文檔寫得很清楚茸俭。

但是筆者發(fā)現(xiàn)一個問題吊履,這個token驗證機(jī)制存的token,一旦生成就保持不變调鬓。這樣就引發(fā)一些問題艇炎,萬一某人拿到你的token不就為所欲為了嗎,就像別人拿到你的密碼一樣腾窝。

解決方案: 給token設(shè)置過期時間缀踪,超過存活時間居砖,這段token不再具有驗證功能,每次用戶重新登入驴娃,刷新token(這段新token的有存活時間)奏候。這樣,重新登入后托慨,你的token更新了鼻由,某些居心不良的人即便拿著之前搶來的token也沒用。stackoverflow上已經(jīng)有了token過期時間的討論厚棵。 參考他們的代碼我這樣寫蕉世。

改進(jìn)

#coding=utf-8   auth.py
from django.utils.translation import ugettext_lazy as _
from django.core.cache import cache

import datetime

from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
from account.models import Token
from rest_framework import HTTP_HEADER_ENCODING

def get_authorization_header(request):
    """
    Return request's 'Authorization:' header, as a bytestring.

    Hide some test client ickyness where the header can be unicode.
    """
    auth = request.META.get('HTTP_AUTHORIZATION', b'')
    if isinstance(auth, type('')):
        # Work around django test client oddness
        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 = _('Invalid token header. Token string should not contain invalid characters.')
            raise exceptions.AuthenticationFailed(msg)

        return self.authenticate_credentials(token)

    def authenticate_credentials(self, key):
        try:
            token = self.model.objects.get(key=key)
        except self.model.DoesNotExist:
            raise exceptions.AuthenticationFailed('認(rèn)證失敗')

        if not token.user.is_active:
            raise exceptions.AuthenticationFailed('用戶被禁止')

        utc_now = datetime.datetime.utcnow()

        if token.created < utc_now - datetime.timedelta(hours=24 * 14):
            raise exceptions.AuthenticationFailed('認(rèn)證信息過期')

    def authenticate_header(self, request):
        return 'Token'

還要配置settings文件

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'yourmodule.auth.ExpiringTokenAuthentication',
    ),
}

再改進(jìn) 使用了cache緩存對token和關(guān)聯(lián)的用戶進(jìn)行了緩存,因為token驗證經(jīng)常需要從數(shù)據(jù)庫讀取婆硬,加入緩存狠轻,大幅提高速度。

def authenticate_credentials(self, key):

    token_cache = 'token_' + key
    cache_user = cache.get(token_cache)
    if cache_user:
        return cache_user     # 首先查看token是否在緩存中彬犯,若存在向楼,直接返回用戶

    try:
        token = self.model.objects.get(key=key)
    except self.model.DoesNotExist:
        raise exceptions.AuthenticationFailed('認(rèn)證失敗')

    if not token.user.is_active:
        raise exceptions.AuthenticationFailed('用戶被禁止')

    utc_now = datetime.datetime.utcnow()

    if token.created < utc_now - datetime.timedelta(hours=24 * 14):  # 設(shè)定存活時間 14天
        raise exceptions.AuthenticationFailed('認(rèn)證信息過期')

    if token:
        token_cache = 'token_' + key
        cache.set(token_cache, token.user, 24 * 7 * 60 * 60)  # 添加 token_xxx 到緩存

    return (token.user, token)

我的login函數(shù)是這樣寫的

@api_view(['POST'])
def login_views(request):
    receive = request.data   
    if request.method == 'POST':
        username = receive['username']
        password = receive['password']
        user = auth.authenticate(username=username, password=password)
        if user is not None and user.is_active:
            # update the token
            token = Token.objects.get(user=user)  
            token.delete()
            token = Token.objects.create(user=user)
            user_info = UserInfo.objects.get(user=user)
            serializer = UserInfoSerializer(user_info)

            response = serializer.data             
            response['token'] = token.key

            return json_response({
                "result": 1,
                "user_info":response, # response contain user_info and token 
                })
        else:
            try:
                User.objects.get(username=username)
                cause = u'密碼錯誤'
            except User.DoesNotExist:
                cause = u'用戶不存在'

            return json_response({
                "result": 0,
                "cause":cause,
                })
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市谐区,隨后出現(xiàn)的幾起案子湖蜕,更是在濱河造成了極大的恐慌,老刑警劉巖宋列,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件昭抒,死亡現(xiàn)場離奇詭異,居然都是意外死亡炼杖,警方通過查閱死者的電腦和手機(jī)灭返,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來坤邪,“玉大人熙含,你說我怎么就攤上這事⊥Х模” “怎么了怎静?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長黔衡。 經(jīng)常有香客問我消约,道長,這世上最難降的妖魔是什么员帮? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮导饲,結(jié)果婚禮上捞高,老公的妹妹穿的比我還像新娘氯材。我一直安慰自己,他們只是感情好硝岗,可當(dāng)我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布氢哮。 她就那樣靜靜地躺著,像睡著了一般型檀。 火紅的嫁衣襯著肌膚如雪冗尤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天胀溺,我揣著相機(jī)與錄音裂七,去河邊找鬼。 笑死仓坞,一個胖子當(dāng)著我的面吹牛背零,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播无埃,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼徙瓶,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了嫉称?” 一聲冷哼從身側(cè)響起侦镇,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎织阅,沒想到半個月后壳繁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蒲稳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年氮趋,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片江耀。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡剩胁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出祥国,到底是詐尸還是另有隱情昵观,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布舌稀,位于F島的核電站啊犬,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏壁查。R本人自食惡果不足惜觉至,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望睡腿。 院中可真熱鬧语御,春花似錦峻贮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至碉纺,卻和暖如春船万,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背骨田。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工耿导, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人盛撑。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓碎节,卻偏偏與公主長得像,于是被迫代替她去往敵國和親抵卫。 傳聞我的和親對象是個殘疾皇子狮荔,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容