Serverpodの認証周りを調べてみた
はじめに
Serverpodを軽く触ってみました。
Serverpodの特徴として、認証周りの機能もついているので触ってみます。
標準で組み込まれている認証の種類
メールアドレス&パスワード
Googleアカウント連携
Appleアカウント連携
今回は「メールアドレス&パスワード」をやってみようと思います。
基本的には以下の記事を参考にしていきます。
Get started
1. Project作成と準備
※ 前提としてserverpodはインストール済み、Dockerを起動しておく。
以下のコマンドでServerpodのプロジェクトを作成。
(mypodは任意の名前)以降、mypodという名称を付けたという前提で書いていきます。
serverpod create mypod
Dockerのセットアップをする。
cd mypod/mypod_server
docker-compose up --build --detach
authパッケージを取得する
mypod_server
とmypod_client
内にあるpubspec.yaml
にserverpod_auth_xxxx: ^1.1.x
を追加する
バージョンはserverpodのバージョンと合わせています。
dependencies:
serverpod: ^1.1.1
serverpod_auth_server: ^1.1.1
dependencies:
serverpod_client: ^1.1.1
serverpod_auth_client: ^1.1.1
生成設定ファイルにauth用のセットを追加する。
config/generator.yaml
に以下を追加。
modules:
serverpod_auth:
nickname: auth
generator.yamlに追加したことで、コマンドを実行すると必要なファイルが自動生成されます。
dart pub get
serverpod generate
次にDBまわりの用意をしていきます。
mypod_server
にあるgenerated
にtables-serverpod-auth.pgsql
を新規ファイルとして作成。
こちらのファイルのファイル全体をコピーします。
(参考にしたGet Startedの記事内にあるマイグレーションファイルのリンクが切れているため、それっぽい別の場所にあるマイグレーションファイルを使っています。)
docker ps
を実行し、mypod_server-postgres-1
があることを確認します。
その後、terminal上でgeneratedフォルダに移動した後にDBを反映させるDBコマンドを実行します。
cd generated
docker cp ./tables-serverpod-auth.pgsql mypod_server-postgres-1:/docker-entrypoint-initdb.d/tables-serverpod-auth.pgsql
docker exec -u postgres mypod_server-postgres-1 psql mypod postgres -f /docker-entrypoint-initdb.d/tables-serverpod-auth.pgsql
ただ、👆をすると自分の環境だと途中からエラーになり、sqlファイルが最後まで実行できなかった。
(一回でもサーバーを起動するとデフォルトのsqlファイルのデータがDBに反映されてしまって、既にtableが存在しているというエラー?🤔)
BEGIN
CREATE TABLE
CREATE INDEX
...(略
CREATE INDEX
CREATE INDEX
psql:/docker-entrypoint-initdb.d/tables-serverpod-auth.pgsql:110: ERROR: relation "serverpod_auth_key" already exists
psql:/docker-entrypoint-initdb.d/tables-serverpod-auth.pgsql:113: ERROR: current transaction is aborted, commands ignored until end of transaction block
とりあえずは一度mypodに関するテーブルを全て削除し、もう一度上記のコマンドを実行すると成功するようになりました。
次にDBViewer的なアプリを利用してDBの内部を見てみます。
接続情報はdevelopment.yaml
とpasswords.yaml
にあるので、必要なデータを入力していきます。
以下のテーブルが存在していればOKかと思います。
これで下準備は完了で、次にクライアント(Flutter)側のセットアップをしていきます。
2. Flutterのセットアップ
mypod_flutter
のpubspec.yaml
に二つのパッケージを追加します。
その後、flutter pub get
を実行しておきます。
serverpod_flutter: ^1.1.1
serverpod_auth_email_flutter: ^1.1.1
serverpod_auth_shared_flutter: ^1.1.1
とりあえずこの時点でサーバーの起動および、Flutterアプリからのアクセスができているかを確認してみます。
サーバー側の起動
cd mypod_server
dart bin/main.dart
Flutterアプリの起動(open -a Simulator
でiOS Simulatorを起動してから、Flutterアプリを起動します)
open -a Simulator
cd mypod_flutter
flutter run
以下の画面で「Send to Server」をタップした時に「Enter your name」に入力した文字が「Hello [入力した文字]」と表示されれば、サーバーとの接続が正常にできています。
(サーバーとの接続が失敗すると、SocketException等何かしらのエラーが表示され、「No Server response yet.」と表示している部分が赤色に変わります。)
サーバーとの接続が確認できたところで、Flutterアプリ上からログインやサインインをできるよう実装していきます。
2.1 認証のセットアップ
mypod_flutter/lib/main.dart
のMyHomePage
を以下のように修正します。
SignInWithEmailButton
はserverpod_auth_email_flutter
のパッケージが提供しているWidgetなので、とりあえず以下丸コピで動作できるかと思います。
class MyHomePage extends StatelessWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(title)),
body: Center(
child: SignInWithEmailButton(
caller: client.modules.auth,
),
),
);
}
}
以下の画面が表示されると思います。
UI側の設定が終わったので、SessionManager
というものをセットアップしていきます。
main.dart
の一番上の方にあるClient
にauthenticationKeyManager
を追加します。
var client = Client(
'http://localhost:8080/',
)..connectivityMonitor = FlutterConnectivityMonitor();
↓
var client = Client(
'http://localhost:8080/',
authenticationKeyManager: FlutterAuthenticationKeyManager(),
)..connectivityMonitor = FlutterConnectivityMonitor();
SessionManager
をvar client
の下に宣言して、main
関数で初期化します。
var client = Client(
'http://localhost:8080/',
authenticationKeyManager: FlutterAuthenticationKeyManager(),
)..connectivityMonitor = FlutterConnectivityMonitor();
late SessionManager sessionManager;
void main() async {
sessionManager = SessionManager(caller: client.modules.auth);
await sessionManager.initialize();
runApp(const MyApp());
}
次にサーバー側の設定をしていきます。
mypod_server
のlib/server.dart
のrun
関数に次のコードを追加します。
final pod = Serverpod(
args,
Protocol(),
Endpoints(),
);
// auth[ここを追加します。]
auth.AuthConfig.set(auth.AuthConfig(
sendValidationEmail: (session, email, validationCode) {
print('Validation code: $validationCode');
return Future.value(true);
},
sendPasswordResetEmail: (session, userInfo, validationCode) {
print('Validation code: $validationCode');
return Future.value(true);
},
));
...
今、追加したコードでアカウント登録時やパスワードリセットの際にメール等に認証番号をprintで確認できるようになります。
コード的には準備完了なので、アカウントを作成していきます。
2.2 アカウントの準備
サーバーを起動して、Flutterアプリも起動していきます。
サーバー起動
cd mypod_server
dart bin/main.dart
Flutterアプリ起動
cd mypod_flutter
flutter run
Flutterアプリ上のSign in with Email
というボタンをタップ。
以下のようなポップアップが表示されるのでそれぞれの項目を入力して「Create Account」をタップします。
「Create Account」をタップすると、認証番号を入力する画面が表示されます。
そうすると、サーバーを動作しているコンソールに以下のようにログ出力されるのでこの番号をアプリに入力します。
Validation code: 62529545
認証コードを入力して、「Sign In」をタップするとアカウント作成完了です。
DBViewerのツールで確認してみます。
serverpod_user_info
のテーブルに以下のように入力した内容のデータが登録できていれば、アカウント登録完了です。
試しに、作成したアカウントでログインをしてみます。
手順としては以下になります。
- Flutterアプリで「Sign in with Email」をタップ
- 「I have an account」をタップ
- メールアドレスとパスワードを入力して「Sign In」をタップ
先ほど登録したメールアドレスをパスワードでログインをすると通常にログインできます。
また、それ以外の組み合わせのメールアドレス、パスワードを入力すると「Incorrect password」と表示され、エラーになります。
Flutterアプリにてログインしているアカウントの情報はSessionManager
でみることができます。
print(sessionManager.isSignedIn);
print(sessionManager.signedInUser);
flutter: true
flutter: {"id":1,"userIdentifier":"example@example.com","userName":"user","fullName":null,"email":"example@example.com","created":"2023-12-07T21:23:03.927547Z","imageUrl":"http://localhost:8080/serverpod_cloud_storage?method=file&path=serverpod%2Fuser_images%2F1-1.jpg","scopeNames":[],"blocked":false}
printした情報を見るに既存のままだとユーザーを識別するIDにおいてはデフォルトの設定では存在しないようなので、また別途アカウント情報を作成する必要があるかもでした。
userIdentifier
のパラメータがUUIDなどになればいいのですが、、、
また、ログアウトをするにはSessionManagerのsignOutで実行できます。
TextButton(
onPressed: () {
sessionManager.signOut();
},
child: const Text('Logout'),
),
アカウントの連携をするだけであればFirebaseの方が利用しやすかったりする気が若干しますが、Serverpodも簡単に認証だったりの実装ができました。
Discussion