ローリングコンバットピッチなう!

AIとか仮想化とかペーパークラフトとか

【python】Flaskで作ったWeb/APIサーバーにDigest認証を設定する+requestsからpersistent connection(keep-alive)で接続する

[technology][python]FlaskでDigest認証+requestsからpersistent connection(keep-alive)で接続する


rc30-popo.hatenablog.com
の続きです。

Flaskで作成したWebアプリに、pythonのrequestsモジュールを使ったクライアントからpersistent connection出来る様になったのですが、このままでは誰も接続可能になってしまいます。
クローズドネットワーク内での実験ならば良いのですが、いくらなんでも不用心なので最低限の認証くらいはやはり付けるべきかなと考えてDigest認証の設定方法を調べました。

Flaskアプリ側の設定方法はググれば割と簡単に出てきますが、下記の様な感じです。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from flask import Flask, render_template, request, redirect, url_for,jsonify
from werkzeug.serving import WSGIRequestHandler
from flask_httpauth import HTTPDigestAuth

app = Flask(__name__)
app.config['SECRET_KEY'] = 'abcdefghij'
auth = HTTPDigestAuth()


users = {
    'test': 'test1234'
}

@auth.get_password
def get_pw(username):
    global users
    if username in users:
        return users.get(username)
    return None

# Routing:
@app.route('/')
@auth.login_required
def index():
  〜rootのレンダリング処理〜

この中でapp.config['SECRET_KEY']に設定した値は、Digest認証のパスワードではなく、認証が通った後のセッションCookieに埋め込むのに使われる様ですが、詳細は確認していません。ちなみに本エントリのサンプルソースではSSLを使っていないので、通信経路のどこかでセッションCookieを盗聴されると認証が完了した状態でのなりすましが可能と思われます。
これだけではセキュアではないので、真面目にセキュアにしたい場合はSSL化しましょう。SSL化の方法はflask sslとかでググれば出てきます。

認証に使うuser名、passwordはusersというdictにハードコードしていますが、これはサンプルだからで、まともなアプリなら(外部からはアクセス出来ない)バックエンドのDBなりに格納、それを@auth.get_passwordの直後に定義した関数で検索する形になります。

これでとりあえず、アプリのroot('/')にアクセスするとuser名とpasswordを聞かれる様になります。

では、root('/')以外のリソースにアクセスするとどうなるかというと、routingの定義に個別に@auth.login_requiredを書かないとDigest認証の対象にならない様です。

# Routing:
@app.route('/')
@auth.login_required
def index():
  〜rootのレンダリング処理〜

@app.route('/api1')
def api1():
 〜/api1のレンダリング処理〜

これだと/api1へのアクセスでは認証が要求されませんでした。

# Routing:
@app.route('/')
@auth.login_required
def index():
  〜rootのレンダリング処理〜

@app.route('/api1')
@auth.login_required
def api1():
 〜/api1のレンダリング処理〜

これだと、/へのアクセスも/api1へのアクセスも共に認証が要求されます。


さて、この状態でFlaskアプリにアクセスするクライアント側にもDigest認証対応を入れてみます。
これもkeep-aliveしない場合のサンプルはググると簡単に見つかります。

ここでは前回のエントリで使用したrequestsモジュールをkeep-alive対応で使うサンプルソースをベースにDigest認証対応します。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import requests
from requests.auth import HTTPDigestAuth

s = requests.Session()
s.auth = HTTPDigestAuth('test', 'test1234')

response1 = s.get('http://localhost:5000/api1')
response2 = s.get('http://localhost:5000/api2')

こんな感じでrequestsから取得したsessionのインスタンスにauthオブジェクトを設定するだけです。
簡単なんですけど、ググッてもストレートに出てこなかったので参考まで。