概要
やりたいこと
- Auth0を用いたアプリケーション、正しくはAPIでユーザー毎にできることを切り分けたい。
- ユーザーを管理者(admin)と通常メンバー(ordinary-member)に分けて管理したい。
このような管理をRBAC (Role-Based Access Control)と呼ぶらしい。
例えば、Auth0にordinary-memberに設定された者は、メンバー情報の(一覧)取得と更新ができる。admin に設定された者 は、加えてメンバー情報の作成と削除ができるなど。
これらの設定はAuth0の管理画面からおこなうことができます。
RBACを使用できるようにする
- 管理画面のApplications → APIs に[+ Create API]で追加済の当該APIのSettingsを開きます。
- 以下の両方のトグルスイッチをONにします。
- Enable RBAC
- If this setting is enabled, RBAC authorization policies will be enforced for this API. Role and permission assignments will be evaluated during the login transaction.
- この設定を有効にすると、この API に対して RBAC認可ポリシーが適用されます。ロールとパーミッションの割り当ては、ログイン処理中に評価されます。
- Add Permissons in the Access Token
- If this setting is enabled, the Permissions claim will be added to the access token. Only available if RBAC is enabled for this API.
- この設定を有効にすると、アクセストークンにパーミッションクレームが追加されます。このAPIでRBACが有効になっている場合のみ利用できます。
- Enable RBAC
ロールを設定する
管理画面のUser Management→ Roles の[+ Create Role]から次のロールを作成してみました。
Name | Description |
admin | なんでもできる。 |
ordinary-member | メンバーの一覧の取得とメンバー情報の更新ができる |
※ロールなし | メンバーの一覧の取得だけができる |
パーミッションを設定する
- 管理画面のApplications → APIs に追加済のAPIを選択する。
- Permissions タブでここでは次のようなパーミッションを追加します。
Permission (Scope) | Description |
list:members | メンバの一覧を取得 |
create:members | メンバ情報を作成 |
update:members | メンバ情報を更新 |
delete:member | メンバ情報の削除 |
ロールへのパーミッションの割当
- 管理画面のUser Management→ Roles の各ロールについて[View Detail]を選択して編集をおこなう。
- Permissionsタブで[Add permissions]によりAPIのパーミッションの割当をおこなう。
APIに渡されたBearerトークンの確認
APIに渡されてきたBearerトークンをjwt.ioで分解すると、次のように
参考までに以下はNetlify Functionsに渡されてきたeventのevent.headersを引数に取り、アクセストークン部分を切り出す関数です。
const getAccessTokenFromHeaders = (headers) => {
const rawAuthorization = headers.authorization;
if (!rawAuthorization) {
return null;
}
const authorizationParts = rawAuthorization.split(' ');
if (authorizationParts[0] !== 'Bearer' || authorizationParts.length !== 2) {
return null;
}
return authorizationParts[1]; ← ★ここで戻す値が上図のトークン
};
アプリからロールやパーミッションを取得する
フロントエンドのコードでロールやパーミッションを取得するには、まずトークンを取得します。
:
import { useAuth0 } from '@auth0/auth0-react';
import {
getPermissionsFromToken,
isAdmin,
isOrdinaryMember,
isNoRole,
} from '../utils/permission';
:
// このあとコンポーネントのコード
const { isAuthenticated, user, getAccessTokenSilently } = useAuth0();
useEffect(async () => {
if (isAuthenticated) {
const token = await getAccessTokenSilently();
console.table(getPermissionsFromToken(token));
:
if (isAdmin(token)) {
// 管理者の場合の処理
} else if (isOrdinaryMember(token)) {
setRole('一般メンバ');
} else if (isNoRole(token)) {
// メンバ登録未完了の場合の処理
} else {
// 不明なロールの場合の処理
}
} else {
// 認証されていない場合の処理
}
}, [user]);
上記の ../utils/permission の関数は次のように実装してみました。
import jwt_decode from 'jwt-decode';
export const getPermissionsFromToken = (token) => {
const decodedToken = jwt_decode(token);
return decodedToken.permissions;
};
export const isAdmin = (token) => {
const permissions = getPermissionsFromToken(token);
return permissions.includes('delete:member');
};
export const isOrdinaryMember = (token) => {
const permissions = getPermissionsFromToken(token);
if (permissions === null) {
return false;
} else if (isAdmin(token)) {
return false;
} else if (
permissions.includes('list:members') &&
permissions.includes('update:members')
) {
return true;
} else {
return false;
}
};
export const isNoRole = (token) => {
const permissions = getPermissionsFromToken(token);
return (permissions.length === 0);
}
この後の記事では、React Router v6でページを保護する方法について書いてみたいと思います。