/home/by-natures/dev*

データ界隈で働くエンジニアとしての技術的なメモと、たまに普通の日記。

Flask を使って Basic 認証付きの REST API クラスを作る

Flask(フラスク)は、「プログラミング言語Python用の、軽量なウェブアプリケーションフレームワークである。」 (Wikipedia) ということで、簡単に使うことができる Python のウェブアプリケーションフレームワークです。

インターネット上にもサンプルがたくさん公開されています。curl コマンド等で簡単に動作確認を行うこともできて、python コマンドでスクリプトを実行すると、即座に簡易ウェブサーバが LISTEN 状態となるので、localhost に対して curl コマンドを実行すれば動作確認ができます。

軽量とは言うものの、第三者提供のモジュールも多く、これを組み合わせればかなりのことは実現できそうです。ここでは REST API を実現するために調べたことをご紹介します。

Flask の例外処理について考えてみる」も合わせてどうぞ。

Flask-RESTful でクラス化する

Flask-RESTful は、REST API を実現するための第三者モジュールです。pip でインストールしておきましょう:

$ pip install flask-restful

Flask-RESTful の公式ページに載っている、最もシンプルなサンプルです:

# -*- coding: utf-8 -*-

from flask import Flask
from flask.ext import restful

app = Flask(__name__)
api = restful.Api(app)

class HelloWorld(restful.Resource):
    def get(self):
        return {'hello': 'world'}

api.add_resource(HelloWorld, '/')

if __name__ == '__main__':
    app.run(debug=True)

HelloWorld というリソースを '/' に割り当てています。GET メソッドは get(), POST メソッドは post() が呼ばれるようになっています。Django でも同じような書き方をしますし、これだけでも十分雰囲気は伝わるかと思います。

Flask-HTTPAuth で認証機能を付ける

機能拡張として、Flask-HTTPAuthBasic 認証を施してみます。

Flask-HTTPAuth は Flask のための認証機構を提供するための第三者モジュールで、Basic, Digest 認証を提供します。これも pip でインストールしておきます:

$ pip install flask-httpauth

このモジュールを使って、先ほどの HelloWorld に Basic 認証を施してみます。簡単のため、ユーザー名は 'user', パスワードは 'pass' の場合のみ認証させています:

# -*- coding: utf-8 -*-

from flask import Flask
from flask.ext import restful
from flask.ext.httpauth import HTTPBasicAuth

app = Flask(__name__)
api = restful.Api(app)

class HelloWorld(restful.Resource):
    auth = HTTPBasicAuth()

    @staticmethod
    @auth.verify_password
    def verify_password(username, password):
        return username == 'user' and password == 'pass'

    @auth.login_required
    def get(self):
        return {'hello': 'world'}

api.add_resource(HelloWorld, '/')

if __name__ == '__main__':
    app.run(debug=True)

パスワード認証を @staticmethod でデコレートしているのは、@auth.verify_password でデコレートした際に、username, password が変数として与えられるのですが、暗黙的な第一引数の self に変数が渡らずにエラーになってしまうためです。同様の理由で、@classmethod も動きません。ちょっと妙ですが、static メソッドで困ることも今のところないのであまり調べていません。。

上記スクリプトpython コマンドで実行し、curl コマンドで動作確認してみます:

$ curl http://127.0.0.1:5000
Unauthorized Access
$ curl http://127.0.0.1:5000 --user user:pass
{
    "hello": "world"
}

参考

Flask 公式ページ(英語)

Flask-RESTful 公式ページ(英語)

Flask-HTTPAuth 公式ページ(英語)

miguelgrinberg.com: RESTful Authentication with Flask
"Flask Web Development" の著者のブログです。Basic, Digest, Token 認証の方法についてまとまっています。