一簡介
JWT 是一個開放标準(RFC 7519),它定義了一種用于簡潔,自包含的用于通信雙方之間以 JSON 對象的形式安全傳遞資訊的方法。該資訊可以被驗證和信任,因為它是數字簽名的。JWTS可以使用秘密(使用HMAC算法)或公鑰/私鑰對使用RSA或ECDSA來簽名。
JWT的組成部分:
header
Header是由下面這個格式的Json通過Base64編碼(編碼不是加密,是可以通過反編碼的方式擷取到這個原來的Json,是以JWT中存放的一般是不敏感的資訊)生成的字元串,Header中存放的内容是說明編碼對象是一個JWT以及使用“SHA-256”的算法進行加密(加密用于生成Signature)
playload
Payload是通過Claim進行Base64轉碼之後生成的一串字元串,Claim是一個Json,Claim中存放的内容是JWT自身的标準屬性,所有的标準屬性都是可選的,可以自行添加,比如:JWT的簽發者、JWT的接收者、JWT的持續時間等;同時Claim中也可以存放一些自定義的屬性,這個自定義的屬性就是在使用者認證中用于标明使用者身份的一個屬性,比如使用者存放在資料庫中的id,為了安全起見,一般不會将使用者名及密碼這類敏感的資訊存放在Claim中。将Claim通過Base64轉碼之後生成的一串字元串稱作Payload。
signatrue
Signature是由Header和Payload組合而成,将Header和Claim這兩個Json分别使用Base64方式進行編碼,生成字元串Header和Payload,然後将Header和Payload以Header.Payload的格式組合在一起形成一個字元串,然後使用上面定義好的加密算法和一個密匙(這個密匙存放在伺服器上,用于進行驗證)對這個字元串進行加密,形成一個新的字元串,這個字元串就是Signature。
簽名的目的:最後一步簽名的過程,實際上是對頭部以及負載内容進行簽名,防止内容被竄改。如果有人對頭部以及負載的内容解碼之後進行修改,再進行編碼,最後加上之前的簽名組合形成新的JWT的話,那麼伺服器端會判斷出新的頭部和負載形成的簽名和JWT附帶上的簽名是不一樣的。如果要對新的頭部和負載進行簽名,在不知道伺服器加密時用的密鑰的話,得出來的簽名也是不一樣的。
rest_framework_jwt
rest_framework_jwt是一個封裝了jwt符合restful規範的接口
網站位址:http://getblimp.github.io/django-rest-framework-jwt/
安裝:pip install djangorestframework-jwt
二、配合drf的認證元件的使用方法
配置檔案
#添加rest-framework
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01.apps.App01Config',
"rest_framework",
]
REST_FRAMEWORK = {
# 配置預設的認證方式 base:賬号密碼驗證
#session:session_id認證
'DEFAULT_AUTHENTICATION_CLASSES': (
# drf的這一階段主要是做驗證,middleware的auth主要是設定session和user到request對象
# 預設的驗證是按照驗證清單從上到下的驗證
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
"rest_framework_jwt.authentication.JSONWebTokenAuthentication",
)}
import datetime
# 逾時時間
JWT_AUTH = {
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
# token字首
'JWT_AUTH_HEADER_PREFIX': 'JWT',
}
# 引用Django自帶的User表,繼承使用時需要設定
AUTH_USER_MODEL = "app01.User"
模型表
#使用django自帶的auth元件模型表
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class User(AbstractUser):
phone=models.CharField(max_length=11,null=True)
url路由層
from django.conf.urls import url
from django.contrib import admin
from rest_framework_jwt.views import obtain_jwt_token
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
# url(r'^home/', views.Home.as_view()),
# 登入驗證,使用JWT的子產品,隻要使用者密碼正确會自動生成一個token傳回
url(r'^login/', obtain_jwt_token),
# 通路需要認證的接口
url(r'^index/', views.Index.as_view()),
]
view視圖層
from django.shortcuts import render
from django.http import JsonResponse
# Create your views here.
from rest_framework.views import APIView
from app01.jwtMiddleware import TokenAuth
class Index(APIView):
#局部認證的配置
authentication_classes = [TokenAuth,]
def get(self,request):
return JsonResponse({"index":"ok"})
class Home(APIView):
def get(self,request):
return render(request,"login.html")
rest-framework認證類
from rest_framework.exceptions import AuthenticationFailed
from rest_framework_jwt.serializers import VerifyJSONWebTokenSerializer
class TokenAuth():
def authenticate(self, request):
token={"token":None}
# print(request.META.get("HTTP_TOKEN"))
token["token"] = request.META.get('HTTP_TOKEN')
valid_data = VerifyJSONWebTokenSerializer().validate(token)
print(valid_data)
user = valid_data['user']
print(user)
if user:
return
else:
raise AuthenticationFailed('認證失敗')
模闆
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/login/" method="post">
<input type="text" name="username">
<input type="text" name="password">
<input type="submit" value="登入">
</form>
</body>
</html>
postman
