🙄

【JWT】続き:クライアントPCからシステムサーバに対して、JWTを送信する方法 

2023/02/23に公開

概要

今回は下記記事の続き。前回開発したコードついて、デコレータを使用しブラッシュアップする。
https://zenn.dev/oreilly_ota/articles/0bbd0f3ca3c234

認証のブラッシュアップ

クライアントからのrequestに、Authorizationが含まれているかチェックする。例えば、PostmanでNo Authを選択してrequestを送ると、401 Unauthorizedと出力される。一方で、Authorization方法をBearer Tokenと指定すると成功する。

if 'Authorization' not in request.headers:
  abort(401)

また下記コードを実装することで、クライアントのリクエストが "bearer xxxxx" という形で、bearer認証のトークンが来ていることが確認できる。

if len(header_parts) != 2
  abort(401)
elif header_parts[0].lower() == bearer':
  abort(401)

コードを改修する

コードは、get_toke_auth_headerとheaders関数に分けることができる。前者については、クライアントのリクエストをチェックした上で、トークン部分となるheader_parts[1]を返り値として、headers関数に渡す。headersでは、それを受け取り、jwtに変数として格納しprint出力する。

def get_token_auth_header():
# check if authorization is not in request
    if 'Authorization' not in request.headers:
        abort(401)
# get the token   
    auth_header = request.headers['Authorization']
    header_parts = auth_header.split(' ')
# check if token is valid
    if len(header_parts) != 2:
        abort(401)
    elif header_parts[0].lower() != 'bearer':
        abort(401) 
return header_parts[1]

app = FLASK(__name__)

@app.route('/headers')
def headers():
    jwt = get_token_auth_header()
    print(jwt)
    return "not implemented"

デコレータを使用する

上記コードをデコレータを使用し改修する。

from flask import Flask, request, abort
from functools import wraps

def get_token_auth_header():
# check if authorization is not in request
    if 'Authorization' not in request.headers:
        abort(401)
# get the token   
    auth_header = request.headers['Authorization']
    header_parts = auth_header.split(' ')
# check if token is valid
    if len(header_parts) != 2:
        abort(401)
    elif header_parts[0].lower() != 'bearer':
        abort(401) 
    return header_parts[1]

def requires_auth(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        jwt = get_token_auth_header()
        return f(jwt, *args, **kwargs)
    return wrapper
app = Flask(__name__)

@app.route('/headers')
@requires_auth
def headers(jwt):
    print(jwt)
    return "not implemented"

上記コードを解説する前に、実際にローカルホストで動かした時、PostmanでどのようにクライアントPCからサービスサーバに対して、requestを送っているか確認する。添付の通り、Authorizationを指定して、ValueでBearer xxxxとtokenを送ると、200レスポンスがかえって来る。

print(jwt)と出力しているので、terminal上でjwtの値が出力される。

では、なぜデコレータを指定する必要があるか。今回は、/headersというURIへのAPI送信を確認した。API毎にJWTを受け取ることになるので、例えばimageというAPIやmovieというAPIなど、APIの種類が増えてきた時、下記のように単純にコピペしてAPI毎のrequest内容を取得できる。

# API毎に、下記のスラッシュ部分を変更する
@app.route('/image')
@requires_auth
def headers(jwt):
    print(jwt)
    return "not implemented"

デコレータの解説

では、どのようにデコレータ部分が使用されているか解説する。まずこちらは、headersというAPIを取得している。そして、requires_authに対してデコレータを張っている。

@app.route('/headers')
@requires_auth
def headers(jwt):
    print(jwt)
    return "not implemented"

次にrequires_authを見ると、返り値としてwrapperを受けていることがわかる。wrapperはjwtを値として受けており、これはget_token_auth_header()で取得している。

def requires_auth(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        jwt = get_token_auth_header()
        return f(jwt, *args, **kwargs)
    return wrapper
app = Flask(__name__)

最後にget_token_auth_header()を確認する。こちらを確認すると、今まで説明した通り、クライアントPCからのrequestがauthorization bearer tokenであるかチェックして、そのtoken部分を取得して、それを返している。

def get_token_auth_header():
# check if authorization is not in request
    if 'Authorization' not in request.headers:
        abort(401)
# get the token   
    auth_header = request.headers['Authorization']
    header_parts = auth_header.split(' ')
# check if token is valid
    if len(header_parts) != 2:
        abort(401)
    elif header_parts[0].lower() != 'bearer':
        abort(401) 
    return header_parts[1]

まとめると、

  • get_token_auth_header()でJWTを取得する。
  • 取得した値を、デコレータとしてrequires_auth(f)で返す
  • そのデコレータで返した値を、API別で@requires_authで返している。

引用

www.udacity.com

Discussion