Google App Engine用フレームワークKayのRESTfull APIの機能(RESTViewGroup)でアクセス制限を行う方法 その2

Google App Engine用フレームワークKayのRESTfull APIの機能(RESTViewGroup)でアクセス制限を行う方法の続き。

前回までのまとめ。

  • Google App Engine用フレームワークKayにはRESTViewGroupというRESTfull APIを簡単に実装するための機能が用意されています。
  • RESTViewGroupでアクセス制限を行うにはauthorizeメソッドをオーバーライドします。
  • authorizeメソッドで例外kay.exceptions.NotAuthorizedをraiseすることでアクセスを拒否できます。
  • authorizeメソッドの引数operationをチェックすることで、処理内容を確認できます。
    • operationがとる値は、OP_LIST, OP_SHOW, OP_CREATE, OP_UPDATE, OP_DELETEのいずれか。

authorizeメソッドの定義

from kay.generics import (OP_LIST, OP_SHOW, OP_CREATE, OP_UPDATE, OP_DELETE)
from kay.exceptions import NotAuthorized

class MyRESTViewGroup(RESTViewGroup):
    models = ['myapp.models.MyModel']
    def authorize(self, request, operation, obj=None, model_name=None,
                  prop_name=None):
        '''アクセス制限
           @param request: リクエスト
           @param operation: 処理(OP_LIST, OP_SHOW, OP_CREATE, OP_UPDATE, OP_DELETE)
           @param obj: 処理対象のオブジェクト(OP_SHOW, OP_UPDATE, OP_DELETEのときのみ)
           @param model_name: モデル名
           @param prop_name:
           @raise e: アクセスを許可しないときは kay.exceptions.NotAuthorized を投げる
        '''
        return True

今回は、URLに付与したユーザー名とパスワードで認証する方法を紹介します。
その後、Basic認証による認証方法を紹介します。

次のようなURLによるアクセスで認証します。

http://~/rest/MyMode?user_name=ユーザー名&password=パスワード

URLに付与されたパターメータはrequest.value.get(パラメータ名)で取得することが出来ます。

user_name = request.values.get('user_name')
password=request.values.get('password'))

指定されたユーザー名とパスワードでログインできるかどうかを調べるには、kay.auth.login()を使用します。

from kay.auth import login
result = login(request, username=ユーザー名, password=パスワード)
# ログインに失敗したときはアクセスを認めない
if not result: raise NotAuthorized

ログインに成功した場合、request.userのis_adminやis_anonymous()で、権限を検証することが出来ます。

# 管理者権限がないときはアクセスを認めない
if not request.user.is_admin:
    raise NotAuthorized

全体のソースコードは次のようになります。

myapp/urls.py

from kay.routing import (ViewGroup, Rule)
from kay.generics.rest import RESTViewGroup

class MyRESTViewGroup(RESTViewGroup):
    models = ['myapp.models.MyModel']
    def authorize(self, request, operation, obj=None, model_name=None,
                  prop_name=None):
        '''アクセス制限
           @param request: リクエスト
           @param operation: 処理(OP_LIST, OP_SHOW, OP_CREATE, OP_UPDATE, OP_DELETE)
           @param obj: 処理対象のオブジェクト(OP_SHOW, OP_UPDATE, OP_DELETEのときのみ)
           @param model_name: モデル名
           @param prop_name:
           @raise e: アクセスを許可しないときは kay.exceptions.NotAuthorized を投げる
        '''
        from kay.auth import login
        from kay.exceptions import NotAuthorized
        # ログインできるか
        result = login(request,
                       user_name=request.values.get('user_name'),
                       password=request.values.get('password'))
        # ログインに失敗したときはアクセスを認めない
        if not result: raise NotAuthorized
        # 管理者権限がないときはアクセスを認めない
        if not request.user.is_admin: raise NotAuthorized

        return True

view_groups = [
    MyRESTViewGroup(),
    ViewGroup(
        Rule('/', endpoint='index', view='myapp.views.index'),
    )
]

開発サーバーでアクセスします。

http://localhost:8080/rest/MyModel?user_name=ユーザー名&password=パスワード

管理者権限を持つユーザーのユーザー名とパスワードでアクセスすれば表示されます。

次にユーザー名とパスワードをURLに付与するのではなく、Basic認証で送信するように変更します。

Google App EngineによるBasic認証は「Google App Engine でBasic認証を実装 改 – すぎゃーんメモ」を参考にさせていただきました。

ヘッダーの情報はrequest.headers.get(ヘッダ名)で取得することが出来ます。

auth_header = request.headers.get('Authorization')
if not auth_header: raise NotAuthorized

取得した情報からユーザー名とパスワードを取得します。

(scheme, base64str) = auth_header.split(' ')
if scheme != 'Basic': raise NotAuthorized
(username, password) = base64.b64decode(base64str).split(':')

後は先ほどと同じ。

result = login(request, user_name=username, password=password)
# ログインに失敗したときはアクセスを認めない
if not result: raise NotAuthorized
# 管理者権限がないときはアクセスを認めない
if not request.user.is_admin: raise NotAuthorized

全体のソースコードは次のようになります。

class MyRESTViewGroup(RESTViewGroup):
    models = ['myapp.models.MyModel']
    def authorize(self, request, operation, obj=None, model_name=None,
                  prop_name=None):
        from kay.auth import login
        from kay.exceptions import NotAuthorized
        import base64

        # ヘッダーから認証情報を取得する
        auth_header = request.headers.get('Authorization')
        if not auth_header: raise NotAuthorized

        # 取得した情報からユーザー名とパスワードを取得する
        (scheme, base64str) = auth_header.split(' ')
        if scheme != 'Basic': raise NotAuthorized
        (username, password) = base64.b64decode(base64str).split(':')

        result = login(request, user_name=username, password=password)
        # ログインに失敗したときはアクセスを認めない
        if not result: raise NotAuthorized
        # 管理者権限がないときはアクセスを認めない
        if not request.user.is_admin: raise NotAuthorized
        return True

動作を検証するためのテストコードです。

# -*- coding: utf-8 -*-
import urllib2
import base64

username = 'username'
password = 'password'
url = 'http://localhost:8080/rest/metadata'

base64string =  base64.encodestring('%s:%s' % (username, password))[:-1]
authheader = 'Basic %s' % base64string

req = urllib2.Request(url)
req.add_header("Authorization", authheader)
handle = urllib2.urlopen(req)
print handle.read()

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です