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_subject
permissionはsubjectモデルの追加に伴って作成されたもの)。
なお、上記例のadd_subject
permissionを例にとると、この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についてはとりあえずはここまでにします。
必要があれば随時追加していきます。