概述
這個包提供對Django REST framework的JSON Web Token 認證支援。
需要滿足條件
- Python (2.7, 3.3, 3.4, 3.5)
- Django (1.8, 1.9, 1.10)
- Django REST Framework (3.0, 3.1, 3.2, 3.3, 3.4, 3.5)
安全
與JWT的一些更典型的用法不同,此模組僅生成身份驗證令牌,該身份驗證令牌將驗證請求DRF保護的API資源之一的使用者。實際的請求引數本身不包含在JWT宣告中,這意味著它們沒有被簽名並且可能被篡改。 您僅應通過SSL / TLS公開API端點,以防止內容篡改和某些型別的重放攻擊。
安裝
使用pip
方式安裝
$ pip install djangorestframework-jwt
用法
在settings.py
中,新增JSONWebTokenAuthentication
到Django rest framework的DEFAULT_AUTHENTICATION_CLASSES
中。
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
),
}
在urls.py
中,新增以下URL路由,以允許通過包含使用者名稱和密碼的POST
獲得令牌。
from rest_framework_jwt.views import obtain_jwt_token
#...
urlpatterns = [
'',
# ...
url(r'^api-token-auth/', obtain_jwt_token),
]
如果您擁有一個使用者名稱為admin和密碼為password123的使用者,則可以通過在終端中執行以下操作來簡單測試端點是否正常執行。
$ curl -X POST -d "username=admin&password=password123" http://localhost:8000/api-token-auth/
或者,您可以使用Django REST框架支援的所有內容型別來獲取auth令牌。 例如:
$ curl -X POST -H "Content-Type: application/json" -d '{"username":"admin","password":"password123"}' http://localhost:8000/api-token-auth/
現在,為了訪問受保護的api網址,您必須包含Authorization:JWT <your_token>
標頭。
$ curl -H "Authorization: JWT <your_token>" http://localhost:8000/protected-url/
重新整理令牌
如果JWT_ALLOW_REFRESH
為True,則可以“重新整理”未過期的令牌以獲得具有更新的過期時間的全新令牌。 新增如下網址格式:
from rest_framework_jwt.views import refresh_jwt_token
# ...
urlpatterns = [
# ...
url(r'^api-token-refresh/', refresh_jwt_token),
]
如下所示將現有令牌傳遞到重新整理端點:{“ token”:EXISTING_TOKEN}
。 請注意,只有未過期的令牌才有效。 JSON響應看起來與正常的獲取令牌端點{“ token”:NEW_TOKEN}
相同。
$ curl -X POST -H "Content-Type: application/json" -d '{"token":"<EXISTING_TOKEN>"}' http://localhost:8000/api-token-refresh/
可以重複使用令牌重新整理(令牌1->令牌2->令牌3),但是此令牌鏈將原始令牌(使用使用者名稱/密碼憑證獲取)的時間儲存為orig_iat
。 您最多隻能將令牌重新整理到JWT_REFRESH_EXPIRATION_DELTA
。
一個典型的用例是一個Web應用程式,您想讓使用者“登入”該網站而不必重新輸入密碼,或者在令牌過期之前被嚇倒了。 想象一下,他們有一個1個小時的令牌,正好在他們仍在做某事的最後一刻。 使用移動裝置,您也許可以儲存使用者名稱/密碼來獲取新令牌,但這在瀏覽器中並不是一個好主意。 每次使用者載入頁面時,您都可以檢查是否存在現有的未過期令牌,如果該令牌即將過期,請重新整理該令牌以擴充套件會話。 換句話說,如果使用者正在活躍地使用您的網站,則他們可以保持其“會話(session)”有效。
驗證令牌
在某些微服務架構中,身份驗證由單個服務處理。 其他服務委託確認使用者已登入到此身份驗證服務的責任。 這通常意味著服務會將將從使用者收到的JWT傳遞給身份驗證服務,並在將受保護資源返回給使用者之前等待JWT有效的確認。
此軟體包使用驗證端點支援此設定。 新增以下網址格式:
from rest_framework_jwt.views import verify_jwt_token
#...
urlpatterns = [
# ...
url(r'^api-token-verify/', verify_jwt_token),
]
將令牌傳遞到驗證端點將返回200響應,如果令牌有效,則返回令牌。 否則,它將返回一個400 Bad Request(錯誤請求)以及一個指出令牌無效的原因的錯誤。
$ curl -X POST -H "Content-Type: application/json" -d '{"token":"<EXISTING_TOKEN>"}' http://localhost:8000/api-token-verify/
其它配置
JWT_AUTH = {
'JWT_ENCODE_HANDLER':
'rest_framework_jwt.utils.jwt_encode_handler',
'JWT_DECODE_HANDLER':
'rest_framework_jwt.utils.jwt_decode_handler',
'JWT_PAYLOAD_HANDLER':
'rest_framework_jwt.utils.jwt_payload_handler',
'JWT_PAYLOAD_GET_USER_ID_HANDLER':
'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler',
'JWT_RESPONSE_PAYLOAD_HANDLER':
'rest_framework_jwt.utils.jwt_response_payload_handler',
'JWT_SECRET_KEY': settings.SECRET_KEY,
'JWT_GET_USER_SECRET_KEY': None,
'JWT_PUBLIC_KEY': None,
'JWT_PRIVATE_KEY': None,
'JWT_ALGORITHM': 'HS256',
'JWT_VERIFY': True,
'JWT_VERIFY_EXPIRATION': True,
'JWT_LEEWAY': 0,
'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=300),
'JWT_AUDIENCE': None,
'JWT_ISSUER': None,
'JWT_ALLOW_REFRESH': False,
'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),
'JWT_AUTH_HEADER_PREFIX': 'JWT',
'JWT_AUTH_COOKIE': None,
}
該軟體包使用JSON Web令牌Python實現PyJWT,並允許修改其中的一些可用選項。
JWT_SECRET_KEY
這是用於簽署JWT的金鑰。確保這是安全的,並且不會共享或公開。
預設值為專案的settings.SECRET_KEY
。
JWT_GET_USER_SECRET_KEY
這是JWT_SECRET_KEY的更強大的版本。它是按使用者定義的,因此,如果令牌被盜用,所有者可以輕鬆更改它。更改此值將使給定使用者的所有令牌不可用。值應該是一個函式,僅接受使用者作為引數並返回它的金鑰。
預設為None
。
JWT_PUBLIC_KEY
這是cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey
型別的物件。它將用於驗證傳入的JWT的簽名。設定後將覆蓋JWT_SECRET_KEY
。閱讀文件以獲取更多詳細資訊。請注意,必須將JWT_ALGORITHM
設定為RS256
,RS384
或RS512
之一。
預設為None
。
JWT_PRIVATE_KEY
這是cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey
型別的物件。它將用於對JWT的簽名元件進行簽名。設定後將覆蓋JWT_SECRET_KEY
。閱讀文件以獲取更多詳細資訊。請注意,必須將JWT_ALGORITHM
設定為RS256
,RS384
或RS512
之一。
預設為None
。
JWT_ALGORITHM
可能的值是PyJWT中任何受支援的密碼簽名演算法。
預設值為“ HS256”
。
JWT_VERIFY
如果密碼錯誤,則會引發一個jwt.DecodeError
告訴您。您仍然可以通過將JWT_VERIFY
設定為False
來獲得有效負載。
預設值為True
。
JWT_VERIFY_EXPIRATION
您可以通過將JWT_VERIFY_EXPIRATION
設定為False
來關閉到期時間驗證。如果沒有到期驗證,JWT將永遠存在,這意味著攻擊者可以無限期地使用洩露的令牌。
預設值為True
。
JWT_LEEWAY
這使您可以驗證過去但不是很遠的到期時間。例如,如果您有一個JWT有效負載,其有效時間設定為建立後的30秒,但您知道有時您將在30秒後對其進行處理,則可以將回旋時間設定為10秒,以便有一定的餘量。
預設值為0
秒。
JWT_EXPIRATION_DELTA
這是Python的datetime.timedelta的一個例項。這將被新增到datetime.utcnow()來設定到期時間。
預設值為datetime.timedelta(seconds = 300)(5分鐘)
。
JWT_AUDIENCE
這是一個字串,將根據令牌的aud
欄位(如果存在)進行檢查。
預設值為None
(如果JWT上出現aud
,則失敗)。
JWT_ISSUER
這是一個字串,將根據令牌的iss
欄位進行檢查。
預設值為None
(不檢查JWT上的iss
)。
JWT_ALLOW_REFRESH
啟用令牌重新整理功能。從rest_framework_jwt.views.obtain_jwt_token
發行的令牌將具有orig_iat
欄位。預設為False
。
JWT_REFRESH_EXPIRATION_DELTA
令牌重新整理的限制是一個datetime.timedelta
例項。這是原始令牌之後可以重新整理未來令牌的時間。
預設值為datetime.timedelta(days = 7)(7天)
。
JWT_PAYLOAD_HANDLER
指定自定義函式以生成令牌有效載荷。
JWT_PAYLOAD_GET_USER_ID_HANDLER
如果您儲存的user_id
與預設的有效負載處理程式不同,請實現此功能以從有效負載中獲取user_id
。注意:不推薦使用JWT_PAYLOAD_GET_USERNAME_HANDLER
。
JWT_PAYLOAD_GET_USERNAME_HANDLER
如果您儲存的username
與預設有效負載處理程式不同,請實施此功能以從有效負載中獲取使用者名稱。
JWT_RESPONSE_PAYLOAD_HANDLER
負責控制登入或重新整理後返回的響應資料。重寫以返回自定義響應,例如包括使用者的序列化表示形式。預設返回JWT
令牌。
def jwt_response_payload_handler(token, user=None, request=None):
return {
'token': token,
'user': UserSerializer(user, context={'request': request}).data
}
預設是 {'token': token}
JWT_AUTH_HEADER_PREFIX
您可以修改需要與令牌一起傳送的Authorization標頭值字首。 預設值為JWT。 PR#4中引入了此決定,以允許在DRF中同時使用此程式包和OAuth2。
用於令牌和授權標頭的另一個常見值是Bearer
。
預設值為JWT
。
JWT_AUTH_COOKIE
如果除了授權標頭之外還想使用http cookie
作為令牌的有效傳輸方式,則可以將其設定為字串。 您在此處設定的字串將用作在請求令牌時將在響應標頭中設定的cookie名稱。 令牌驗證過程還將調查此cookie(如果已設定)。 如果請求中同時包含標頭和cookie,則“授權”標頭具有優先權。
預設值為“None”
,建立令牌時不設定cookie,或在驗證令牌時不接受。
擴充套件JSONWebTokenAuthentication
現在,JSONWebTokenAuthentication假定JWT將出現在標頭或cookie(如果已配置)中(請參閱JWT_AUTH_COOKIE)。 JWT規範不需要這樣做(請參閱:進行服務呼叫)。 例如,JWT可以出現在查詢字串中。 如果使用者無法設定標頭(例如HTML中的src元素),則需要具有在查詢字串中傳送JWT的功能。
為了實現此功能,使用者可以編寫自定義身份驗證
:
class JSONWebTokenAuthenticationQS(BaseJSONWebTokenAuthentication):
def get_jwt_value(self, request):
return request.QUERY_PARAMS.get('jwt')
建議使用BaseJSONWebTokenAuthentication
,這是一個新的基類,沒有解析HTTP標頭的邏輯。
手動建立新令牌
有時您可能需要手動生成令牌,例如在建立帳戶後立即將令牌返回給使用者。 您可以按照以下步驟進行操作:
from rest_framework_jwt.settings import api_settings
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)