認証と認可

本章は Eric Rasmussen によって寄稿されました。

Pyramid にはハンドラアクションを簡単に制限するための内蔵の認証および 認可の機能があります。これは、一般的に行う必要のあるステップの概観です:

  1. モデルの中に allow/deny ディレクティブとグループおよびパーミッション を関連付ける root ファクトリを作る。
  2. モデルの中にユーザとグループを作る。
  3. ユーザー ID に基づいてユーザが所属するグループのリストを検索する ためのコールバック関数を作成する。
  4. Forbidden 例外が上げられた時に起動される “forbidden view” を作成する。
  5. ユーザー名/パスワードをチェックして、成功すればユーザを remember する ログインアクションを作成する。
  6. @view_config に permission=’somepermission’ 引数を渡すことで ハンドラアクションへのアクセスを制限する。
  7. 設定中でそれらすべてを結びつける。

モデルにインポート文とカスタム root ファクトリを加えることで始めます:

1
2
3
4
5
6
7
8
9
from pyramid.security import Allow, Everyone

class RootFactory(object):
    __acl__ = [ (Allow, Everyone, "everybody"),
                (Allow, "basic", "entry"),
                (Allow, "secured", ("entry", "topsecret"))
              ]
    def __init__(self, request):
        pass

カスタム root ファクトリは、ウェブアプリケーションに送られたリクエスト のコンテキストとして使用されるオブジェクトを生成します。 root ファクトリ の最初の属性は ACL つまりアクセスコントロールリストです。それは、 (Allow または Deny のような) リクエストを扱うディレクティブ、リソースへの アクセスが許可されるか拒否されるグループ、そしてそのグループに関連する パーミッション (オプションでパーミッションのタプル) を含むタプルのリスト です。

上記の例のアクセスコントロールリストは、全員が ‘everybody’ パーミッションで ページを見ること、 basic グループのメンバーが ‘entry’ パーミッション で制限されたページを見ること、そして secured グループのメンバーが ‘entry’ あるいは ‘topsecret’ パーミッションのいずれかで制限されたページ を見ることを許可すると示しています。特別な principal ‘Evenryone’ は内蔵 の機能で、サイトを訪れた人 (これは principal として知られる) なら誰でも、 与えられたリソースへのアクセスを許可します。

ユーザがログインするために、フォームによって送信されたログインおよび パスワード (あるいは任意の追加の基準) を有効にするハンドラを作成することが できます。典型的には次のインポートを加えると良いでしょう:

from pyramid.httpexceptions import HTTPFound
from pyramid.security import remember, forget

モデルに対してユーザのログインおよびパスワードを一旦検証すれば、ヘッダー にユーザの ID を「覚えさせる」 (“remember”) ことができます。そして、ユーザを ホームページまたは彼らがアクセスしようとした url にリダイレクトさせることが できます:

# retrieve the userid from the model on valid login
headers = remember(self.request, userid)
return HTTPFound(location=someurl, headers=headers)

remember 関数の呼び出しでは、ユーザー ID を渡していることに注意して ください。それはデータベースから検索されて、変数 ‘userid’ (例としてここで 使われている任意の名前) に格納されています。しかし、より簡単に、ユーザー 名あるいは他のユニークな識別子を渡すことで同じことができます。 remember するために決定すべきものは、ユーザが所属するグループのリストを返す groupfinder コールバック関数に渡されるものです。 authenticated_userid (それはハンドラアクションでユーザ情報を検索する便利な方法です) をインポート すれば、それは “remember” するためにヘッダーに設定するための情報を返します。

ユーザをログアウトさせるためには、それらを「忘れ」て (“forget”)、 HTTPFound を使用して別の url にリダイレクトします:

headers = forget(self.request)
return HTTPFound(location=someurl, headers=headers)

ハンドラアクションをパーミッションによって制限する前に、ユーザー ID が 所属するグループのリストを返すコールバック関数を必要とするでしょう。これは モデルの中でそれを実装する一つの方法です。この場合、 groupname 属性を持つ Group オブジェクトと、 Group との mygroups 関係を持った User オブジェクト があることを仮定しています:

def groupfinder(userid, request):
    user = Users.by_id(userid)
    return [g.groupname for g in user.mygroups]

例として、ここでパーミッションによって制限するために @action デコレータを、 リクエストからユーザ ID を検索するために authenticated_userid を、 インポートして使用することができます:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from pyramid_handlers import action
from pyramid.security import authenticated_userid
from models import Users

class MainHandler(object):
    def __init__(self, request):
        self.request = request

    @action(renderer="welcome.html", permission="entry")
    def index(self):
        userid = authenticated_userid(self.request)
        user = Users.by_id(userid)
        username = user.username
        return {"currentuser": username}

これは、ハンドラアクションを制限して、さらにユーザに関する情報を得る ための非常に簡単な方法です。この例では、 Users クラスがあり、それが user オブジェクトを返すための by_id と呼ばれる便利クラスメソッドを 持っていると仮定しています。その後、モデルに定義されたオブジェクトの 任意の属性 (ユーザー名、電子メールアドレス、など) にアクセスし、 return 文でそれらを辞書の key/value としてテンプレートに渡すことができます。

forbidden 例外が上げられた時に特定のハンドラアクションを呼び出してほしければ、 forbidden ビューを加える必要があります。これは、以前にカバーされていますが、 完全性のために:

1
2
3
4
5
@view_config(renderer='myapp:templates/forbidden.html',
             context='pyramid.exceptions.Forbidden')
@action(renderer='forbidden.html')
def forbidden(request):
    ...

最後のステップは、 auth ポリシーを使用するために __init__.py を構成する ことです。確実にこれらのインポートを加えてください:

from pyramid.authentication import AuthTktAuthenticationPolicy
from pyramid.authorization import ACLAuthorizationPolicy
from .models import groupfinder

main 関数では auth ポリシーを定義して、それらを Configurator への呼び出しに 含めると良いでしょう:

1
2
3
4
5
6
7
8
authn_policy = AuthTktAuthenticationPolicy('secretstring',
   callback=groupfinder)
authz_policy = ACLAuthorizationPolicy()
config = Configurator(settings=settings,
   root_factory='myapp.models.RootFactory',
   authentication_policy=authn_policy,
   authorization_policy=authz_policy)
config.scan()

Pyramid における認証と認可に関する機能は、 Pylons や repoze.what を使う場合 と比較して始めるのが非常に簡単です。その利点は、共通のタスクを扱うコード および内蔵の方法をメンテナンスするのがより簡単なことです。共通のタスクには、 ユーザを remember または forget する、パーミッションをセットする、 自分のモデルで動かすために groupfinder コールバックを簡単に修正すること、 などが含まれます。 root ファクトリで前もってパーミッションを設定して、個々のハンドラアクション を制限することが管理可能な場合には、これは一方でモデルを通して頑健なユーザ およびグループ管理能力を提供しながらも、運用することが断然単純な方法です。

しかしながら、アプリケーションが (グループ所属による単なるアクセスでは なく) パーミッションを作成/編集/削除する能力を要求するか、高度な述語の 使用を要求する場合、自分の auth システムを構築するか (詳細に関しては Pyramid ドキュメントを参照) 、あるいは repoze.what のような既存のシステ ムを統合することができます。

さらに、 “repoze.who” を Pyramid の認証システムと共に使用することも (もし Who の認証と設定を使いたければ) できます。

Previous topic

デプロイ

Next topic

他の Pyramid 機能