Permissionとは
Permissionとはdjangoアプリケーションに実装されている概念であり、ユーザーの行動に制限をかけるために用いられる。
例えばdjangoアプリの管理者サイトへのログインはsuperuserでないとできないが、これはsuperuserにis_staffというpermissionが付与されていることによる(逆に言えばこの権限さえ与えてしまえばどのユーザーでも管理者サイトに入れるようになる)。
permissionは管理者サイトのような組み込みのシステムだけでなく、アプリケーション内に実装した機能の利用に制限をかける際にも使用可能。
アプリの独自機能に制限をかける場合にはMixinを用います。
そちらについては以下の記事をどうぞ。
Permissionの付与の仕組み
Permissionの付与の仕方には、ユーザーに直接付与する方法とあるグループを作ってそこに付与し、そのグループにユーザーを追加するという方法の2種類がある。
また、Permissionの実態はauth_permissionというテーブルのレコードであり、ユーザー及びグループにPermissionが付与されているのかどうかは、アプリ名_customuser_user_permissionsテーブルとauth_group_permissionsテーブルという二つの中間テーブルによって管理されている。
具体的なpermission操作のコードは以下の通り。
# "Can Change Item"というpermissionの付与・剥奪を行う場合。
permission = Permission.objects.get(name="Can change Item")
# ユーザーにpermissionを付与
user.user_permissions.add(permission)
# 以下の書き方でも可
user.user_permissions.set([permission])
# permissionの剥奪
user.user_permissions.remove(permission)
# permissionの全権剥奪
user.user_permission.clear()
# groupの場合は以下のように対応(add以外についてもuserと同様)
group.permissions.add(permission)
# ユーザーとグループの紐付けも同じようにして行う
user1.groups.add(group1)
# 以下でも同じ内容
group1.users.add(user1)
auth_permissionテーブルについて
スキーマ及びレコードについては以下の通り(レコードは一部を抜粋しています)。
sqlite> .schema auth_permission
CREATE TABLE IF NOT EXISTS "auth_permission" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "content_type_id" integer NOT NULL REFERENCES "django_content_type" ("id") DEFERRABLE INITIALLY DEFERRED, "codename" varchar(100) NOT NULL, "name" varchar(255) NOT NULL);
CREATE UNIQUE INDEX "auth_permission_content_type_id_codename_01ab375a_uniq" ON "auth_permission" ("content_type_id", "codename");
CREATE INDEX "auth_permission_content_type_id_2f476e4b" ON "auth_permission" ("content_type_id");
sqlite> select * from auth_permission;
1|1|add_logentry|Can add log entry
2|1|change_logentry|Can change log entry
3|1|delete_logentry|Can delete log entry
4|1|view_logentry|Can view log entry
5|2|add_permission|Can add permission
6|2|change_permission|Can change permission
7|2|delete_permission|Can delete permission
8|2|view_permission|Can view permission
# ...中略...
29|8|add_emailaddress|Can add email address
30|8|change_emailaddress|Can change email address
31|8|delete_emailaddress|Can delete email address
32|8|view_emailaddress|Can view email address
# ...中略...
49|13|add_subject|Can add subject
50|13|change_subject|Can change subject
51|13|delete_subject|Can delete subject
52|13|view_subject|Can view subject
permissionレコードのcondename(左から3番目のカラム)については操作名(add, changeなど)と操作対象(emailやpermissionなど)を組み合わせたものになっている。
ほとんどは初回のマイグレーション時に作成されるほか、新たなモデルを定義した場合にはそれに合わせたpermissionも追加される(上記例の末尾にあるxxx_subjectpermissionはsubjectモデルの追加に伴って作成されたもの)。
なお、上記例のadd_subjectpermissionを例にとると、このpermissionがなければsubjectモデルのインスタンスを追加できないという意味ではない。
permissionを用いて特定の操作に対して制限をかけたい場合には、PermissionRequiredMixinを用いて必要なpermissionを指定する必要がある。
あくまでその際にわかりやすいように、djangoの側で組み込みのpermissionが用意されているという理解で問題ない。
PermissionRequiredMixinにおけるpermissionの指定方法
PermissionRequiredMixinにおいてpermission_requiredという属性値を用いて必要なpermissionを指定する場合には、対象permissionのcontent_typeのapp_label.対象permissionのcodenameという形式を用いる。
例えば上記のid=52のpermissionを指定したい場合には、app_labelはsubject, codenameはview_subjectなので以下のようになる。
class TestView(PermissionRequiredMixin, TemplateView):
permission_required = ["subject.view_subject"]
というのが厳密な定義らしいですが、content_typeのapp_labelは基本的にそのモデルを定義しているアプリケーション名という認識で大丈夫そうです。
不安であれば、django_content_typeというテーブルから確認可能です。
sqlite> .schema django_content_type
CREATE TABLE IF NOT EXISTS "django_content_type" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "app_label" varchar(100) NOT NULL, "model" varchar(100) NOT NULL);
CREATE UNIQUE INDEX "django_content_type_app_label_model_76bd3d3b_uniq" ON "django_content_type" ("app_label", "model");
sqlite> select * from django_content_type
...> ;
1|admin|logentry
2|auth|permission
3|auth|group
4|contenttypes|contenttype
5|sessions|session
6|user|customuser
7|sites|site
8|account|emailaddress
9|account|emailconfirmation
10|socialaccount|socialaccount
11|socialaccount|socialapp
12|socialaccount|socialtoken
13|subject|subject
例えばcodename=view_subjectのpermissionはcontent_type_id(左から2番目のカラム)の値が13なのでdjango_content_typeテーブルのid=13のレコードを確認すると、app_label(左から2番目のカラム)がsubjectとなっています。
終わりに
Permissionについてはとりあえずはここまでにします。
必要があれば随時追加していきます。