前提
こちらのページでReact-Adminの全体像や各機能の解説をしていますので、ぜひそちらもご覧ください(https://qiita.com/shino_gono/items/22397f340bfb2038587d)
- この記事ではReact-Adminの導入は済んでいる前提で話を進めます。
- 認証にはfirebaseを用います。
- ドキュメントの認証周りが書かれているページ
- https://marmelab.com/react-admin/Authentication.html
React-Adminでの認証について
- React-Adminでの認証は基本的にauthProviderというプロバイダーを作成して実装を行います。
- こちらはそのほかのデータ操作で使うdataProviderとは切り分けられて扱われるので、その点はご注意ください。
- デフォルトではReact-Adminは認証を必要としていません。
- つまり、特定の設定を加えてやる必要があります。
- まずはApp.jsでAdminコンポーネントに追加してあげましょう。
// in src/App.ts
import authProvider from './authProvider';
export default function App() {
return (
<Admin authProvider={authProvider}>
...
</Admin>
);
}
- これで認証機能の実装が可能になります。
サポートされているバックエンド
React-Aminでは下記のバックエンドが公式にサポートされているので、こちらのバックエンドを使用している場合は非常に簡単に認証が実装できます。
-
Azure Active Directory (MSAL を使用) marmelab/ra-auth-msalチュートリアル
-
Firebase Auth (Google、Facebook、GitHub など) benwinding/react-admin-firebase
!https://marmelab.com/react-admin/img/backend-logos/firebase.png
authProviderを実装する
- 個人的にauthProviderは下記のようにディレクトリにすることを推奨します。
📂authProvider
┗ 📜authProvider.ts
┗ 📜index.ts
- というのも、認証にfirebaseの設定を組み込む際などに、その部分が切り分けられていると見やすいなと思うからです。
- React-Adminには
- なので、
index.ts
はこんな感じになります。
import { FirebaseAuthProvider } from 'react-admin-firebase';
import createAuthProvider from './authProvider';
import { firebaseConfig } from '../firebaseConfig';
const firebaseAuthProvider = FirebaseAuthProvider(firebaseConfig, {});
const authProvider = createAuthProvider();
export default authProvider;
authProvider.ts
-
authProvider.ts
ではcreateAuthProvider
を定義する必要があります。 -
createAuthProvider
では下記のメソッドが必須で必要になり、定義しないと型エラーなどがうるいさいので、使わないものも定義します。
import { AuthProvider } from "react-admin";
const createAuthProvider = (): AuthProvider => ({
login: () => {},
logout: () => {},
checkError: () => {},
checkAuth: () => {},
getPermissions: () => {},
getIdentity: () => {},
setIdentity: () => {},
});
export default createAuthProvider;
- これらのメソッドはPromiseを返すので使わないものはrejectでも返しておけばいいと思います。
// 例:
checkError: () => Promise.resolve(),
loginメソッド
- ログインの処理を記述します。
login: async ({ username, password }) => {
try {
await signInWithEmailAndPassword(auth, username, password);
const user = auth.currentUser;
if (user) {
const result = await fetchWithAuth("/user.getBySelfToken");
localStorage.setItem("user", JSON.stringify(result));
return true;
}
} catch {}
return Promise.reject();
},
- ヘッダーにトークンを載せないといけない場合を想定してfetchWithAuth関数とか作っておくといいですね
async function fetchWithAuth(endpoint: string): Promise<User> {
try {
const user = auth.currentUser;
if (!user) {
return await Promise.reject();
}
const idToken = await user.getIdToken();
const response = await fetch(`適切なURL`, {
method: "GET",
headers: {
// 適当な設定
},
});
if (!response.ok) {
return await Promise.reject();
}
const data = await response.json();
return data;
} catch (error) {
return Promise.reject();
}
}
logoutメソッド
- ログアウトの処理を記述します。
- ログイン状態の確認はchackAuthメソッドで管理しており、今回はローカルストレージに情報があるか否かを見ているので、このようにローカルストレージからユーザー情報を削除してあげればよいです
logout: () => {
localStorage.removeItem("user");
return Promise.resolve();
},
checkAuthメソッド
- 現在のユーザーが存在するかを確認します
checkAuth: () =>
localStorage.getItem("user") ? Promise.resolve() : Promise.reject(),
getIdentityメソッド
- ユーザー情報を取得する処理
- これを設定しておかないと、ユーザー情報を表示させるページなどでユーザー情報が取得しにくくなるので、必ず設定します
- 今回は単にローカルに保存されたものをそのまま使います
getIdentity: () => {
const identity = localStorage.getItem("user");
return Promise.resolve(identity);
},
setIdentityメソッド
- ユーザー情報を更新するメソッド
setIdentity: async () => {
try {
const storedUser = localStorage.getItem("user");
const user = storedUser ? JSON.parse(storedUser) : {};
localStorage.setItem("user", JSON.stringify(user));
} catch (error) {
return Promise.reject();
}
return Promise.resolve();
},
エラーハンドリングなど
- 上記のコードでrejectにエラーメッセージなどを渡していません。
- React-Adminでは特に設定しなくてもAPIからのエラーを解釈してエラーメッセージが表示されるようになっています。
- そのため、このようにrejectに引数を渡さなくても問題がありません。
- 逆に言うと、この仕様のためエラーメッセージを上書きするのがまぁまぁ面倒なので、これは特にいじらないのが無難なきがします。