Python Django DRF框架JWT Auth
REST框架JWT Auth
Django REST Framework的JSON Web令牌認證支援
概觀
該軟體包為Django REST框架提供JSON Web令牌認證支援。
要求
Python(2.7,3.3,3.4,3.5)
Django(1.8,1.9,1.10)
Django REST框架(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框架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框架支援的所有內容型別來獲取身份驗證令牌。例如:
$ 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,則可以“重新整理” 未過期的令牌以獲得具有更新到期時間的全新令牌。像這樣新增一個URL模式:
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小時的令牌,只是在他們還在做某事的最後一刻。使用移動裝置,您可以儲存使用者名稱/密碼以獲取新令牌,但這在瀏覽器中不是一個好主意。每次使用者載入頁面時,您都可以檢查是否存在現有的未過期令牌,如果它已接近過期,請重新整理它以擴充套件其會話。換句話說,如果使用者正在積極使用您的網站,他們可以保持他們的“會話”活著。
驗證令牌
在一些微服務架構中,身份驗證由單個服務處理。其他服務委派確認使用者已登入此身份驗證服務的責任。這通常意味著服務將從使用者接收的JWT傳遞給身份驗證服務,並在將受保護資源返回給使用者之前等待JWT有效的確認。
使用驗證端點在此包中支援此設定。新增以下URL模式:
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/
其他設定
您可以覆蓋一些其他設定,類似於您使用Django REST框架本身的方式。以下是所有可用的預設值。
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 Token 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_VERIFYto來獲取有效負載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(如果aud在JWT上存在則失敗)。
JWT_ISSUER
這是一個字串,將根據iss令牌欄位進行檢查。
預設是None(不要檢查issJWT)。
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方式與預設的有效負載處理程式不同,請實現此功能以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
如果除了Authorization標頭之外還要使用http cookie作為令牌的有效傳輸,則可以將其設定為字串。您在此處設定的字串將用作cookie名稱,該名稱將在請求令牌時在響應標頭中設定。如果設定,令牌驗證程式也將檢視此cookie。如果請求中存在標頭和cookie,則“授權”標頭優先。
預設為None且在建立令牌時未設定cookie,也未在驗證時接受。
擴充套件 JSONWebTokenAuthentication
現在JSONWebTokenAuthentication假設JWT將在標題中,或者如果配置了cookie(請參閱JWT_AUTH_COOKIE)。JWT規範不要求這樣做(參見:撥打服務電話)。例如,JWT可能會出現在查詢字串中。在使用者無法設定標題的情況下(例如HTML中的src元素),需要在查詢字串中傳送JWT的能力。
要實現此功能,使用者可以編寫自定義Authentication:
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)