(DRF)JWT認証


I Token VS JWT
DRFのToken
DRFでサポートされているデフォルトのTokenは、単純なランダム文字列です.
  • と各ユーザ1:1の関係、
  • は有効期間がありません.
  • """ Token Example """
    
    >> import binascii
    >> import os
    >> binascii.hexlify(os.urandom(20)).decode()
    
    ff199ba3d83de440a31e55c48494f906c8cfae2
    
    
    ShellからTokenを出力すると、ランダム文字列であることがわかります.しかし、これは有意義なデータを処理するのが難しいように見えます.
    JWT (JSON Web Token)
    一方、JWTはトークン自体のデータを持ち、データベースを問い合わせることなく論理的に認証することができる.
  • 形式:ヘッダー(Header).PayLoad(内容).VerifySignature(署名)eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFza2RqYW5nbyIsImV4cCI6MTUxNTcyMTIxMSwiZW1haWwiOiIifQ.Zf_o3S7Q7-cmUzLWlGEQE5s6XoMguf8SLcF-2VdokJリーダをbase 64にエンコードalg:ハッシュアルゴリズムtyp:トークンタイプ
    Payloadをbase 64にエンコードsub/name:トークンヘッダiat:コインの発行時間.(iuused_at)
    署名=ヘッダ/パスワードの組合せ、秘密鍵で署名、base 64で符号化exp:トークンの有効期限(有効期限)aud:コインの対象(観客)iss:トークン発行者(発行者)

  • サーバは、トークン発行時にSECRET_KEY(秘密鍵)を使用して署名し、発行時間を保存する.
  • SECRET_KEY(秘密鍵)署名は暗号化されているため、セキュリティデータを入れるのではなく、最小限の必須情報だけを入れるべきである.SECRET_KEYにおいて議論される注意点は、データベースパスワード、AWS鍵、およびOAuthトークンを含む.
    これらの機密情報を保護するために、Djangoはsettings.SECRET_KEYを使用するか、または個別のJWT_SECRET_KEYを設定する.

  • key/valueというexpを使用して、claimはタグに含める情報および情報の一部を表す.
  • djangorestframework-jwtはPayloadでuser id、user name、およびemail名claimを使用します.

  • 「リフレッシュ」(Refresh)メカニズムをサポートします.Token有効期間内に更新するか、username/passwordで再認証を要求します.

  • 発行されたTokenを破棄することは不可能です.
  • """ JWT Example """
    
    >> from bse64 import b64decode
    >> b64decode('eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9')
    b'{"typ":"JWT","alg":"HS256"}'
    >> b64decode('eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFza2RqYW5nbyIsImV4cCI6MTUxNTcyMTIxMSwiZW1haWwiOiIifQ==')
    b'{"user_id":1,"username":"askdjango","exp":1515721211,"email":""}'
    
    🚀 (Django) SECRET_KEY
    🚀 (JWT) Introduction
    I JWT
    JWTのライフサイクル
    JWTは有効期限があり、Refreshをサポートします.
    Tokenセキュリティの保護
    通常のTokenでもJWTTokenでも、Tokenは安全に保存されなければなりません.スマートフォンアプリケーションでは、インストールされているアプリケーションごとに安全なストレージスペースがありますが、Webブラウザにはありません.
  • Toeknは、アプリケーション環境でのみ推奨されます.
  • Webクライアント環境では、セッション認証がより良い選択になる可能性があります.ただし、長/Webクライアントは、同じホスト名を持つ必要があります.
  • 通信はhttpsを使用する必要があります.
  • I djangorestframework-simplejwt
    🚀 (SimpleJWT) Getting started
    DRFはJWTを提供しないため、simplejwtサードパーティ製ライブラリを使用します.ガイドラインを参照してください.
    1.インストール
    $ pip install djangorestframework-simplejwt
    2.設定
    パッケージとurlを登録します.
    # settings.py
    
    INSTALLED_APPS = [
    	...
        'rest_framework_simplejwt',
    ]
    
    REST_FRAMEWORK = {
    	...
    	'DEFAULT_AUTHENTICATION_CLASSES' : [
        	...
            'rest_framework_simplejwt.authentication.JWTAuthentication',
    	]
    }
    # accounts/urls.py
    
    from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView, TokenVerifyView
    
    urlpatterns = [
    	path('api-jwt-auth/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
        path('api-jwt-auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
        path('api-jwt-auth/verify/', TokenVerifyView.as_view(), name='token_verify'),
    ]
    3.HTTPieによるJWTの発行と検証
    HTTPie POSTを使用してJWT Tokenを得る.
    >> http POST http://localhost:8000/accounts/api-jwt-auth/ username="username password="password
    """ 인증에 성공할 경우, 토큰 응답이 옵니다. """
    
    {
        "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjQ0NjU2NjcyLCJpYXQiOjE2NDQ2NTYzNzIsImp0aSI6IjRjM2Y4Yzc3NmJhNDQ0MjRiNGFjYmVhOWMyYmMyNGQ3IiwidXNlcl9pZCI6MX0.720rWqd1MJD8Gc_0Xr2OgqercCIa0d6q1AnchDL3M6s",
        "refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTY0NDc0Mjc3MiwiaWF0IjoxNjQ0NjU2MzcyLCJqdGkiOiI3YmQ0MjU1MjlhMTE0ZWNjYjZhZmVhMzM0ODMwZTMzMSIsInVzZXJfaWQiOjF9.gAjTKuVY91PZwL5dlLP04KfDlXvwk8-e6sP45Y2ujjM"
    }
    
  • 認証が失敗した場合、404 Bad Request応答が受信される.
  • で発行されたJWT Tokenのhttps://jwt.ioでの意味は何ですか?
  • HTTPieを使用して、送信されたJWT Tokenを確認します.
    >> http http://localhost:8000/accounts/api-jwt-auth/verify/ token="token"
  • 認証が成功すると、入力されたTokenが返されます.
  • expが期限切れになった場合、401の許可されていないSignature has expired応答が受信される.
  • 4.送信されたJWT Tokenへの送信を要求する転送リストAPI
  • DRF Tokenは検証ヘッダ開始文字列として「Token」を使用し、JWTは「JWT」を使用します.
  • APIリクエストのたびに認証が行われ、成功すると応答が受信されます.
  • # djangorestframework-jwt
    >> http http://localhost:8000/app/post "Authorization: JWT {{토큰}}"
    # djangorestframework-simplejwt
    >> http http://localhost:8000/app/post "Authorization: Bearer {{토큰}}"
    5.JWTTokenが期限切れになったら?
    >> http http://localhost:8000/accounts/api-jwt-auth/verify/ token="token"
    HTTP/1.0 401 Unauthorized
    {
    	"detail": "Signature has expired."
    }
    有効期間が経過している場合は、有効期間内に更新する必要があります.
  • expが期限切れになった場合、401の許可されていないSignature has expired応答が受信される.
  • 有効期間内にTokenのみ更新可能、
  • の有効期間を超えた場合は、ユーザー名/パスワードで認証する必要があります.
  • djangresframework-jwtでは、JWT Tokenの有効期間はsettings.JWT_AUTHJWT_EXPIRATION_DELTAを参照し、defaultは5分間である.
  • 6.JWTTokenの更新
  • はToken有効期間内に更新する必要があります.
  • djangresframework-jwtのsettings.JWT_AUTHのデフォルト値はfalseであり、この場合、リフレッシュ要求時にorig iatフィールドが見つからないことを示す応答が返されます.更新するにはTrueに設定する必要があります.
  • djangoresframework-simplejwtではdefaultによる更新がサポートされているため、変更する設定値はありません.有効期限は5分が短すぎるので、もう少し長く設定すればいいです.
  • >> http POST http://localhost:8000/accounts/api-jwt-auth/refresh/ token="token"
    restframework-simplejwtでの主な設定
    🚀 (SimpleJWT) Settings
    # settings.py
    
    from datetime import timedelta
    ...
    
    SIMPLE_JWT = {
        'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
        'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
        'ROTATE_REFRESH_TOKENS': False,
        'BLACKLIST_AFTER_ROTATION': False,
        'UPDATE_LAST_LOGIN': False,
    
        'ALGORITHM': 'HS256',
        'SIGNING_KEY': SECRET_KEY,
        'VERIFYING_KEY': None,
        'AUDIENCE': None,
        'ISSUER': None,
        'JWK_URL': None,
        'LEEWAY': 0,
    
        'AUTH_HEADER_TYPES': ('Bearer',),
        'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
        'USER_ID_FIELD': 'id',
        'USER_ID_CLAIM': 'user_id',
        'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',
    
        'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
        'TOKEN_TYPE_CLAIM': 'token_type',
        'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser',
    
        'JTI_CLAIM': 'jti',
    
        'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
        'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
        'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
    }
    📌 リファレンスソース
  • (屈Arn)フィードバック付きPython/張高Webサービス開発完全ガイド
  • DRFでのJWTの使用方法