Djangoで権限管理ってどうやっていますか?
Django自体が持つGroupやPermissionはイマイチ業務では使えないというのが実際のところなのではと思います。
そんな悩みを解決するために django-keeper というライブラリーを作りました。
こんな悩みに:
- DBで権限を管理したくない
- 権限を見通しの良いリストやマッピングで定義したい
- ModelやUserに依存しない グローバルで汎用的な権限も扱いたい
- ViewやTemplateでも使いたい
django-keeperって?
以下のようにACL(AccessControlList)というメソッドによって「権限」を決定します。
from django.conf import settings from keeper.security import Allow from keeper.operators import Everyone, Authenticated, IsUser class Issue(models.Model): author = models.ForeignKey(settings.AUTH_USER_MODEL) ... def __acl__(self): return [ (Allow, Everyone, 'view'), (Allow, Authenticated, 'add_comment'), (Allow, IsUser(self.author), 'edit'), ]
これで、以下のような権限を決定します。
- すべてのリクエストには
"view"
権限 - 認証ユーザーには
"add_comment"
権限 - この
Issue
のauthor
で認証している場合は"edit"
権限
というように __acl__
メソッドによって、リクエストがこのモデルに持つ権限を決められます。
Viewで使おう
以下のようにViewで使います。
@keeper
デコレーターを適用- 第一引数: 必要な権限
- model=引数: Viewの対象のモデル
- mapper=引数: モデルを取得する上限を返す関数
- 引数: View関数と同じ引数
- 戻り値:
objects.get(id=issue_id)
のようにキーワード引数として渡す辞書
from keeper.views import keeper # Model Permissions @keeper( 'view', model=Issue, mapper=lambda request, issue_id: {'id': issue_id}, ) def issue_detail(request, issue_id): request.k_context # 取得したModelが取れます。 ...
これで @keeper
が自動で Issue
のインスタンスを取得して、リクエストが "view"
権限を持つかをチェックします。
権限が無い場合は403となります(@keeper
の on_fail=
引数で権限が無い場合の挙動も変更できます)。
また、 request.k_context
で @keeper
が取得したオブジェクトが取れます。
Operator
ACLに設定した Authenticated
などはOperatorというもので、リクエストがこの条件を満たすときに権限を追加したりできます。
例えば、リクエストが認証済みの場合 "view"
を付与。
(Allow, Authenticated, "view"),
このOperatorというものは keeper.operators
内にいくつかあります。
自作のOperator
自作する場合も簡単で、Operatorは単に Callable[[HttpRequest], bool]
なのですぐ作れます。
例えばIPアドレスからのアクセスかどうかを判定するOperatorはこうなります。
class IsIP: def __init__(self, ip): self.ip = ip def __call__(self, request): return request.META.get('REMOTE_ADDR') == self.ip
この自作OperatorもACL内で使えます。 自社のIPアドレスからアクセスした場合に強い権限を与えるようにしておくなどできそうです。
MY_IP = "..." class Issue(models.Model): def __acl__(self): return [ (Allow, Everyone, 'view'), (Allow, IsIP(MY_IP), 'edit'), ]
このように django-keeper
はUserに依存しない条件(今回はIPアドレス)なども使って権限の管理ができます。
また、Operatorという形で「リクエストが何者かを判別する処理」と「権限」を分離できるので変更に強いですし、見通しも良いです。
他にも
django-keeper
は他にも
- モデルに依存しないグローバルな権限を扱えます
- テンプレート内でも
has_permission
という条件を使えます - 権限のないリクエストの場合の処理を変更できます
- 権限のDenyも設定できます
詳しくは以下から見てみてください。
PyConJP2017で発表します
来る PyConJP 2017 でも django-keeper を交えた発表をします。
発表の内容:
をします。 以下の日程ですのでぜひ来てください。
- プロダクト開発して分かったDjangoの深~いパーミッション管理の話
- 9月8日 金曜日 3:40 p.m.–4:10 p.m.
- Room 203 #pyconjp_203
要注意
django-keeper はまだベータというレベルのライブラリーです。
本番環境にガッツリ導入するというのは避けたほうがいいです 。
導入する場合は、権限チェック周りのテストをちゃんと書くことをオススメします。 ちょっと使ってみて、不備があったり足りない機能があれば教えてください。 まだ自分としても「実験段階」、「こんなものがあったらいいなぁ」という段階なので、何かあれば教えてください PyConJPのパーティーなどで権限周りの定石や悩みを共有できたら良いなぁとも思っています。
おわりに
まだまだ作っている段階のライブラリーですが、僕自身が仕事をしていて欲しかったものを考えて作っています。 他にも良い方法や機能の提案、バグ報告や他オススメのライブラリーがあればぜひ教えてください。
できれば、ぜひPyConJP 2017でお会いしましょう。