django基於存儲在前端的token用戶認證

一.前提

首先是這個代碼基於先後端分離的API,咱們用了django的framework模塊,幫助咱們快速的編寫restful規則的接口前端

前端token原理:django

把(token=加密後的字符串,key=name)在登入後發到客戶端,之後客戶端再發請求,會攜帶過來服務端截取(token=加密後的字符串,key=name),咱們再利用解密方法,將token和key進行解碼,而後進行比對,成功就是登入過的認證,失敗就是沒有登入過的後端

還有一種方式,把{name:maple,id:1} 用我本身知道的加密方式加密以後變成了:加密字符串,加密字符串|{name:maple,id:1} 當作token,發到客戶端,之後客戶端再發請求,會攜帶,加密字符串|{name:maple,id:1}過來,服務端截取{name:maple,id:1},再用咱們的加密方式加密:加密字符串,拿到加密後的字符串進行比對,這種方式,只要寫一個密碼函數就能夠了,無需寫解密函數服務器

二.token加密與解密

在django的app中定義個token模塊restful

將有關token的函數都放在裏面,後面要用到,都調用這個模塊
app

加密token函數:前後端分離

import time
import base64
import hmac

def get_token(key, expire=3600):
    '''
    :param key: str (用戶給定的key,須要用戶保存以便以後驗證token,每次產生token時的key 均可以是同一個key)
    :param expire: int(最大有效時間,單位爲s)
    :return: token
    '''
    ts_str = str(time.time() + expire)
    ts_byte = ts_str.encode("utf-8")
    sha1_tshexstr  = hmac.new(key.encode("utf-8"),ts_byte,'sha1').hexdigest()
    token = ts_str+':'+sha1_tshexstr
    b64_token = base64.urlsafe_b64encode(token.encode("utf-8"))
    return b64_token.decode("utf-8")

解密函數:dom

def out_token(key, token):
    '''
    :param key: 服務器給的固定key
    :param token: 前端傳過來的token
    :return: true,false
    '''

    # token是前端傳過來的token字符串
    try:
        token_str = base64.urlsafe_b64decode(token).decode('utf-8')
        token_list = token_str.split(':')
        if len(token_list) != 2:
            return False
        ts_str = token_list[0]
        if float(ts_str) < time.time():
            # token expired
            return False
        known_sha1_tsstr = token_list[1]
        sha1 = hmac.new(key.encode("utf-8"),ts_str.encode('utf-8'),'sha1')
        calc_sha1_tsstr = sha1.hexdigest()
        if calc_sha1_tsstr != known_sha1_tsstr:
            # token certification failed
            return False
        # token certification success
        return True
    except Exception as e:
        print(e)

3、視圖CBV

登入函數:函數

from rest_framework.response import Response
from rest_framework.views import APIView
from app01 import models
# get_token生成加密token,out_token解密token
from app01.token_module import get_token,out_token




class AuthLogin(APIView):
    def post(self,request):
        response={"status":100,"msg":None}
        name=request.data.get("name")
        pwd=request.data.get("pwd")
        print(name,pwd)
        user = auth.authenticate(username=name, password=pwd)
        # user=models.User.objects.filter(username=name,password=pwd).first()
        if user:
            # token=get_random(name)
            # 將name進行加密,3600設定超時時間
            token=get_token(name,60)
            models.UserToken.objects.update_or_create(user=user,defaults={"token":token})
            response["msg"]="登入成功"
            response["token"]=token
            response["name"]=user.username
        else:
            response["msg"]="用戶名或密碼錯誤"
        return Response(response)

登入後訪問函數:post

from rest_framework.views import APIView
from app01 import models
from app01.serialize_module import BookSerialize
from app01.authentication_module import TokenAuth1,TokenAuth2


class Books(APIView):
    authentication_classes = [TokenAuth2]
    def get(self,request):
        response = {"status": 100, "msg": None}
        book_list=models.Book.objects.all()
        book_ser = BookSerialize(book_list, many=True)
        response["books"]=book_ser.data
        return Response(response)

路由:

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^books/$', views.Books.as_view()),
    url(r'^login/$', views.AuthLogin.as_view()),
]

framework認證功能

from rest_framework.authentication import BaseAuthentication
from app01 import models
from rest_framework.exceptions import NotAuthenticated
# get_token生成加密token,out_token解密token
from app01.token_module import get_token,out_token


# 存儲在前端的token解密比對
class TokenAuth2(BaseAuthentication):
    def authenticate(self,request):
        token=request.GET.get("token")
        name=request.GET.get("name")
        token_obj=out_token(name,token)
        if token_obj:
            return
        else:
            raise NotAuthenticated("你沒有登入")

利用postman軟件在前端提交

登入POST請求:

返回結果:

訪問get請求:

相關文章
相關標籤/搜索