【JWT】続き:クライアントPCからシステムサーバに対して、JWTを送信する方法
概要
今回は下記記事の続き。前回開発したコードついて、デコレータを使用しブラッシュアップする。
認証のブラッシュアップ
クライアントからの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