前言
常見的認(rèn)證機(jī)制:
1.Session認(rèn)證
- 保存在服務(wù)端(會增加服務(wù)器的存儲開銷)
- 在分布式架構(gòu)中,維護(hù)
Session的會話同步比較困難 - 有
CSRF攻擊(跨站請求)的風(fēng)險
2.Token認(rèn)證
- 保存在客戶端
- 跨語言、跨平臺(
json格式) - 擴(kuò)展性較強(qiáng)
- 鑒權(quán)性能高
更詳細(xì)講解點(diǎn)擊此處
一、JWT/Json Web Token
-
JWT是目前最流行的跨域身份驗(yàn)證解決方案,詳情點(diǎn)擊 -
JWT所使用的用戶模型是Django自帶的用戶模型,也就是auth_user表
1、三大部分組成
- 1.
header頭部- 使用
base64進(jìn)行加密,可以被解密 - 只用于聲明類型和所使用的加密算法
- 使用
- 2.
playload載荷- 使用
base64進(jìn)行加密,可以被解密 - 存放過期時間、簽發(fā)用戶等非敏感信息
- 使用
- 3.
signature- 對加密后的
header+playload使用HS256算法進(jìn)行加密,然后secret加鹽處理 -
SECRET_KEY在django項(xiàng)目的setting.py中,生成項(xiàng)目時自動生成,也可以更改為動態(tài)形式
- 對加密后的
1、安裝
pip install djangorestframework-jwt
2、使用
1、在主項(xiàng)目全局指定默認(rèn)使用JWT認(rèn)證,所有項(xiàng)目都需要認(rèn)證;主項(xiàng)目/setting.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
# 使用JWT Token認(rèn)證
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
# Basic類型的認(rèn)證(賬號和密碼)
'rest_framework.authentication.SessionAuthentication',
# Session會話認(rèn)證
'rest_framework.authentication.BasicAuthentication',
],
}
2、添加登錄路由(JWT提供了登錄視圖),子項(xiàng)目/urls.py
from django.urls import path
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
path('login/', obtain_jwt_token),
]
3、添加主項(xiàng)目路由,主項(xiàng)目/urls.py
urlpatterns = [
path('users/', include('user.urls'))
]
4、在需要鑒權(quán)認(rèn)證的視圖集進(jìn)行鑒權(quán)級別設(shè)置(不同的視圖頁面會有不同的鑒權(quán)需求),子項(xiàng)目/views.py
# 登錄才可訪問,更多的鑒權(quán)方式可以看permissions中的內(nèi)容
permission_classes = [permissions.IsAuthenticated]
5、啟動項(xiàng)目并訪問即可測試
6、DRF自帶的權(quán)限:
AllowAny
IsAuthenticated
IsAdminUser
IsAuthenticatedOrReadOnly
3、改動
- 1、修改
Token默認(rèn)過期時間(默認(rèn)5分鐘)-
./site-packages/rest_framework_jwt/settings.py中'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=300)設(shè)置為5分鐘 - 在
主項(xiàng)目/setting.py中進(jìn)行修改為1天
-
JWT_AUTH = {
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1)
}
- 2、修改登錄后的響應(yīng)內(nèi)容
- 源代碼只返回token:
def jwt_response_payload_handler(token, user=None, request=None):
"""
Returns the response data for both the login and refresh views.
Override to return a custom response such as including the
serialized representation of the User.
Example:
def jwt_response_payload_handler(token, user=None, request=None):
return {
'token': token,
'user': UserSerializer(user, context={'request': request}).data
}
"""
return {
'token': token
}
- 重寫,返回用戶的id和username,在
utils路徑下創(chuàng)建jwt_handler.py對上部分代碼進(jìn)行重寫
def jwt_response_payload_handler(token, user=None, request=None):
return {
'token': token,
'user_id': user.id,
'username': user.username
}
- 在
主項(xiàng)目/setting.py中進(jìn)行修改,使用重寫后的設(shè)置
JWT_AUTH = {
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1)
# 原本使用的是源碼,現(xiàn)在修改成重寫后的
'JWT_PAYLOAD_GET_USERNAME_HANDLER': 'utils.jwt_handler.jwt_response_payload_handler'
}
二、httpie工具快速調(diào)試JWT的插件:httpie-jwt-auth
當(dāng)?shù)卿浄祷亓?code>JWT生成的token值后,后面訪問需要鑒權(quán)的視圖請求中,需要帶上固定格式的值:jwt token值,這樣調(diào)試起來很不方便,因?yàn)?code>token值很長(jwt是前綴,可通過設(shè)置JWT_AUTH_HEADER_PREFIX的值進(jìn)行修改)
1、安裝
pip install -U httpie-jwt-auth
2、登錄,獲取到token值
http :8000/user/login/ username=xxx password=xxx
3、設(shè)置環(huán)境變量,簡化token的傳遞
export JWT_AUTH_TOKEN = 'your token'
export JWT_AUTH_PREFIX='JWT'
4、發(fā)出帶token的請求
http -A jwt: 8000/user/projects