質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
JWT(JSON Web Token)

JWT(JSON Web Token)とは、JSONをベースとしたアクセストークンの仕様。電子署名付きのURL safeなJSONのことを指します。電子署名が付いているため、改ざんをチェックできる点がメリットです。

Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

2回答

519閲覧

JWTのトークンを使って/home (Protected ルート)にアクセスしたい

zyusuke

総合スコア5

JWT(JSON Web Token)

JWT(JSON Web Token)とは、JSONをベースとしたアクセストークンの仕様。電子署名付きのURL safeなJSONのことを指します。電子署名が付いているため、改ざんをチェックできる点がメリットです。

Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2023/04/21 17:07

編集2023/04/21 17:13

実現したいこと

JWTのトークンを使って/home (Protected ルート)にアクセスしたい

前提

Flaskでログイン機能を作っています。
Headersに "Authorization" : "Bearer <token>"という形で/homeというルートにアクセスするためのリクエストを送ると、トークンが承認され、一瞬だけアクセスすることができるのですが、すぐ"Token Missing" 401のエラーとともにキックアウトされてしまいます。

発生している問題・エラーメッセージ

"Token is missing!" (トークンが見当たりません)401ERROR

イメージ説明

該当のソースコード

この関数がheadersからトークンを受け取り、チェックするものです。

Python

1def token_required(func): 2 @wraps(func) 3 def decorated(*args,**kwargs): 4 token = None 5 if 'Authorization' in request.headers: 6 token = request.headers['Authorization'].split(' ')[1] 7 print(token) 8 if not token: 9 return jsonify({'Alert!' : 'Token is missing!'}),401 10 try: 11 data = jwt.decode(token, app.config['SECRET_KEY'],algorithms=["HS256"]) 12 print(data) 13 except jwt.ExpiredSignatureError: 14 print("Expired!") 15 return jsonify({'message': 'Token has expired'}),401 16 except jwt.InvalidTokenError: 17 print('Invalid token') 18 return jsonify({'Alert!' : 'Invalid token!'}),401 19 return func(*args,**kwargs) 20 return decorated

バックエンド側のログインの関数

Python

1@app.route('/auth/login',methods=['GET','POST']) 2def loginUser(): 3 if request.method == 'POST': 4 data = request.get_json() 5 username = data['username'] 6 password = data['password'] 7 if not data or not username or not password: 8 return jsonify({'message': 'Missing required fields'}), 400 9 if check_username_exist(username) and checkPassword(get_userID(username),password): 10 token = jwt.encode({ 11 'user':username, 12 'exp': datetime.utcnow() + timedelta(hours=1)},app.config['SECRET_KEY'],algorithm='HS256') 13 return make_response(jsonify({'token': token}),200) 14 else: 15 return jsonify({'message': 'Password is incorrect'}),400 16 return jsonify({'message': 'Could not verify', 'WWW-Authenticate': 'Basic auth="Login required"'}), 401

フロントエンド側のログインの関数

python

1$(document).ready(function () { 2 $("form").on("submit", function (event) { 3 const userInfo = { 4 username: $("#username").val(), 5 password: $("#password").val(), 6 }; 7 $.ajax({ 8 type: "post", 9 url: "http://127.0.0.1:5000/auth/login", 10 dataType: "json", 11 contentType: "application/json", 12 data: JSON.stringify(userInfo), 13 success: function (result) { 14 const token = result.token 15 localStorage.setItem("token", token); 16 $.ajax({ 17 url: "http://127.0.0.1:5000/home", 18 type: "GET", 19 headers: { 20 "Authorization": "Bearer " + localStorage.getItem("token"), 21 "Content-Type": "application/json", 22 }, 23 success: function () { 24 window.location.href = "/home"; 25 }, 26 error: function (jqXHR, textStatus, errorThrown) { 27 console.log(errorThrown); 28 alert("Error: " + textStatus); 29 }, 30 }); 31 }, 32 error: function (xhr, status, error) { 33 console.log(xhr.responseText); 34 alert("Error: " + error); 35 }, 36 }); 37 event.preventDefault(); 38 }); 39 });

試したこと

OAuthLib の設定が必要という記事をみて試してみたのですがだめでした。
しっかりトークンが承認されているのも確認でき、しっかり200が帰ってくるのですが、その後401が帰ってきます。
Expireの時間も1時間に伸ばしてみましたが、だめでした。

ここ二日間この問題で詰まっています。誰かわかる方がいたら教えてほしいです。お願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

WebAPIにアクセスする際はトークンを利用し、ページなどにアクセスする際はクッキー認証を用いました。

投稿2023/04/21 22:31

編集2023/04/26 20:38
zyusuke

総合スコア5

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2023/04/21 22:53

そういうトークン丸見えでセキュリティ的に問題がありそうなことを自己解決というのは疑問ですけど。 それから、私の回答をみてそういう方法を考えたのだと思いますけど、であればいわゆる「自己解決」ではないです。
zyusuke

2023/04/21 23:57

信じてくれるかは分かりませんが、自己解決し、そのことを投稿しようと思い戻ってきたところ、あなたの回答を見ました。なので一応自己解決です。 また、確かにトークンが丸見えになってしまっていますね。おっしゃる通りです。そこの部分は修正しておきます。
退会済みユーザー

退会済みユーザー

2023/04/22 00:20

認証にトークンを使うのが適切かどうかから考え直した方がよさそうな気がします。 相手は Web API ではなくて普通のページのようですが、であればクッキーベースの認証チケットを使った方が良いのではないですか?
zyusuke

2023/04/22 00:26

コメントありがとうございます。 授業の課題の一つとして認証にトークンを使わないといけないので、そこは変えることができません。 トークンではなく、クッキーベースの認証ということでしょうか
退会済みユーザー

退会済みユーザー

2023/04/22 02:57 編集

> トークンではなく、クッキーベースの認証ということでしょうか 相手が Web API ではなくて、ブラウザから普通のページ(この質問では Home)を要求する場合はトークンを使うのは不適切で、クッキーに認証チケットを入れてやり取りするクッキーベースの認証方式を使った方が良いと思います。 クッキーベースの認証方式にすれば、ログインした時点でサーバーから認証クッキーが送られてきて、それをブラウザが自動的に保持します。 なので、 window.location.href = "/home"; でブラウザが home を要求する際、要求ヘッダに自動的に認証クッキーが含まれるようになります。 一方、相手が Web API の場合は、セキュリティ上の理由で (CSRF 対策)、認証にはトークン + HTTPS 通信を使うことが多いようです。 トークンは要求ヘッダに含めて HTTPS で暗号化して見えないようにするのがキモです。 なので、質問者さんの「自己解決」のように、トークンをクエリ文字列として URL に含めるのはダメです。それはダメなので、window.location.href="/home" とか、a タグを使うとか、アドレスバーに url を入力するとか、お気に入りをクリックするとかでは何ともなりません。
zyusuke

2023/04/22 09:22

Web API の時はトークンが必要とはどういうことでしょうか。 ログイン後、自身のホームページや他のページなどにアクセスする際はトークンを使ってアクセスすると習ったのですが、これは間違いなのでしょうか。
zyusuke

2023/04/22 13:15

訂正します。理解することができました。 ログインにはクッキー認証を追加し、APIにはトークンを用いた認証(@token_required)に変更しました。 貴重なコメントありがとうございます😭
退会済みユーザー

退会済みユーザー

2023/04/23 01:01 編集

回答を書き直していただけませんか。すくなくとも、トークンをクエリ文字列として URL に含める (トークン丸見えでセキュリティ的に問題) というのを解決策としないようお願いします。 ひょっとしたら、あとから検索などでこのスレッドにたどり着いた人が、それを見てトークンを url に埋め込むということをするかもしれません。 ここ Teratail は「価値のあるコンテンツを世の中に残し届けることを目的としています」ということですので、ここを利用させてもらっている以上協力しましょう。
guest

0

「フロントエンド側のログインの関数」の中にある

window.location.href = "/home";

のときにトークンを送ってないからではないのですか?

投稿2023/04/21 21:43

編集2023/04/21 21:44
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問