1. 程式人生 > >Python Django DRF框架JWT Auth

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)