OAuth
これをやりたかったのである。
コールバック先として本番環境のホスト名が必要になる予感がしたので、昨日までDigitalOcean
で仮想マシン作ったり、ついでにGithubActions
でCI化したり、FirebaseHosting
に配置したりしてたのである。
しかしながら実際やってみたらコールバック先はFirebaseに集約されるっぽいので先回りする必要はなかったのかもしれない。
FirebaseとGithubの設定
-
Firebaseのコンソールから
Authentication
->Sign-in method
を選択して一覧からGithub
を選択。
-
認証コールバックURLをコピーしておく
-
Githubの設定->
Developer Settings
->OAuth Apps
を選択してRegister a new aplication
ボタンを押下。
-
Generate a new lient secret
ボタンを押下
-
ClientID
とClientSecret
をコピーしておく
-
Authorization callback URL
に手順2でコピーしたURLを貼り付け
※その他は適当に入力する
※ダークモードになってるのはSS撮り忘れてた為 -
Firebaseコンソールに戻って手順5でコピーした
ClientID
とClientSecret
を貼り付け
-
アプリからログインするとユーザ一覧に追加されることが確認できる。
Flutterクライアント(Web)の修正
-
firebaseコンソールから追加したWebアプリを選択し、
CDN
タブに表示されるタグをコピー -
./web/index.html
にfirebaseに必要なスクリプトを追加
<body>
<!-- ★ここから -->
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/8.4.3/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.4.3/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.4.3/firebase-firestore.js"></script>
<!-- TODO: Add SDKs for Firebase products that you want to use
https://firebase.google.com/docs/web/setup#available-libraries -->
<script src="https://www.gstatic.com/firebasejs/8.4.3/firebase-analytics.js"></script>
<script>
// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
var firebaseConfig = {
apiKey: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
authDomain: "XXXXXXXXXXX.firebaseapp.com",
projectId: "XXXXXXXXXX",
storageBucket: "XXXXXXXXXXX",
messagingSenderId: "XXXXXXX",
appId: "1:XXXXXXXXXXXXX:web:XXXXXXXXXX",
measurementId: "G-XXXXXX"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
firebase.analytics();
</script>
<!-- ★ここまで -->
<!-- This script installs service_worker.js to provide PWA functionality to
application. For more information, see:
https://developers.google.com/web/fundamentals/primers/service-workers -->
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('flutter-first-frame', function () {
navigator.serviceWorker.register('flutter_service_worker.js');
});
}
</script>
<script src="main.dart.js" type="application/javascript"></script>
</body>
pubspec.yml
に以下を追加
firebase_auth: ^1.1.2
- 認証処理を実装
flutterのGoogle認証のサンプルを参考に実装
import 'dart:async';
import 'package:clientapp/resources/authentication_repository/authentication_repository.dart';
import 'package:firebase_auth/firebase_auth.dart' as firebase_auth;
class SignUpFailure implements Exception {}
class LogInWithEmailAndPasswordFailure implements Exception {}
class LogInWithGithubFailure implements Exception {}
class LogOutFailure implements Exception {}
class AuthenticationRepository {
AuthenticationRepository({
CacheClient? cache,
firebase_auth.FirebaseAuth? firebaseAuth,
}) : _cache = cache ?? CacheClient(),
_firebaseAuth = firebaseAuth ?? firebase_auth.FirebaseAuth.instance;
final CacheClient _cache;
final firebase_auth.FirebaseAuth _firebaseAuth;
static const userCacheKey = '__user_cache_key__';
Stream<User> get user {
return _firebaseAuth.authStateChanges().map((firebaseUser) {
final user = firebaseUser == null ? User.anonymous : firebaseUser.toUser;
_cache.write(key: userCacheKey, value: user);
return user;
});
}
/// Returns the current cached user.
/// Defaults to [User.anonymous] if there is no cached user.
User get currentUser {
return _cache.read<User>(key: userCacheKey) ?? User.anonymous;
}
Future<void> signUp({required String email, required String password}) async {
try {
await _firebaseAuth.createUserWithEmailAndPassword(
email: email,
password: password,
);
} on Exception {
throw SignUpFailure();
}
}
Future<void> logInWithEmailAndPassword({
required String email,
required String password,
}) async {
try {
await _firebaseAuth.signInWithEmailAndPassword(
email: email,
password: password,
);
} on Exception {
throw LogInWithEmailAndPasswordFailure();
}
}
Future<void> logInWithGithub() async {
try {
final provider = firebase_auth.GithubAuthProvider();
// provider.addScope('repo');
provider.setCustomParameters({
'allow_signup': 'false',
});
await _firebaseAuth.signInWithPopup(provider);
} on Exception {
throw LogInWithGithubFailure();
}
}
Future<void> logOut() async {
try {
await Future.wait([
_firebaseAuth.signOut(),
// _githubSignIn.signOut(),
]);
} on Exception {
throw LogOutFailure();
}
}
}
extension on firebase_auth.User {
User get toUser {
return User(id: uid, email: email, name: displayName, photo: photoURL);
}
}
おじさんの感想
Githubアカウント持ってる一般の方は少ない気がするのでGoogleとかも追加しておくべき。
サーバ側はどう絡むのかと言うと、クライアントが取得したUIDを受け取ってFirebaseに問い合わせてユーザ情報を得るっぽい。
Firebaseって必須の知見なのでは?(2回目)
ちなみにローカルDebug環境でも認証できたので先に本番サーバを用意する必要は全然なかったです。