この記事はLITALICO Engineers Advent Calendar 2023 カレンダー1 の 3日目の記事です
はじめに
- Flutterで生体認証を使うパッケージとしては、local_authが有名
-
記事もいっぱい書かれている
- 参考になりました、ありがとうございます
-
記事もいっぱい書かれている
- ただ、local_authは生体認証で認証できた/できなかったまでしか提供してくれない
- サーバサイドと連携するアプリで活用することを考えると、サーバサイド側で保持しているユーザ情報とどう紐づけるか考える必要がある
- 調べてみたところ、そこまで書かれている記事がないなと思ったので、まとめてみようと思った
概要図
注)今回のサンプルでは概要を説明するために、passwordをflutter_secure_storageに保持しているが、トークンやその他、資格情報を保持し、passowrdを直接保持しないなどを適宜検討してください
使用するパッケージ
- local_auth
- 生体認証の利用、これを使うと、スマホの指紋認証、FaceIDなどを使った認証ができる
- flutter_secure_storage
- アプリ側でのID/パスワードの保持用
- firebase_auth
- サーバサイドの認証サンプル用
コードサンプル
Flutter PJ全体の環境設定
pubspec.yaml
dependencies:
local_auth: ^2.1.7
flutter_secure_storage: ^9.0.0
firebase_auth: ^4.14.0
iOS向けの設定
info.plist
<key>NSFaceIDUsageDescription</key>
<string>生体認証を使用する目的を記述</string>
Android向けの設定
MainActivity.kt
import io.flutter.embedding.android.FlutterFragmentActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity: FlutterFragmentActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine)
}
}
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app">
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
<manifest>
ユーザ登録
必要なパッケージの読み込み
regist_user.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
ユーザ登録
regist_user.dart
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
final _storage = new FlutterSecureStorage();
/** 省略 **/
Future<void> registUser(String email, String password) async {
// まず、Firebaseでユーザ登録を行う
try {
UserCredential _userCredential = await _firebaseAuth.createUserWithEmailAndPassword(
email: email,
password: password,
);
} on FirebaseAuthException catch (e) {
debugPrint('debug: cannot regist: $e');
//ToDo:エラーハンドリング
return
}
// 次に、Firebaseで作成したユーザをSecureStorageに保存する
await _storage.write(key: 'email', value: email);
await _storage.write(key: 'password', value: password);
}
生体認証
必要なパッケージの読み込み
authenticate_user.dart
import 'package:local_auth/local_auth.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
利用可能な生体認証の確認
authenticate_user_with_biometric.dart
LocalAuthentication _localAuth = LocalAuthentication();
/** 省略 **/
Future<List<BiometricType>> _getAvailableBiometricTypes() async {
List<BiometricType> availableBiometricTypes;
try {
availableBiometricTypes = await _localAuth.getAvailableBiometrics();
} on PlatformException catch (e) {
debugPrint('debug: cannot get availavle biometrics: $e');
}
return availableBiometricTypes;
}
生体認証を実地する
authenticate_user_with_biometric.dart
LocalAuthentication _localAuth = LocalAuthentication();
/** 省略 **/
Future<bool> _authenticateWithBiometric() async {
bool authenticate = false;
List<BiometricType> availableBiometricTypes = await _getAvailableBiometricTypes();
try {
if (availableBiometricTypes.contains(BiometricType.face)
|| availableBiometricTypes.contains(BiometricType.fingerprint)) {
authenticate = await _localAuth.authenticateWithBiometrics(localizedReason: "認証してください");
}
} on PlatformException catch (e) {
debugPrint('debug: cannot authenticate with biometrics: $e');
}
return authenticate;
}
生体認証を通過後、保持していたID/パスワードで認証する
authenticate_user_with_biometric.dart
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
final _storage = new FlutterSecureStorage();
/** 省略 **/
Future<void> _loginWithBiometric() async {
bool authenticate = await _authenticateWithBiometric();
if (authenticate) {
String email = await _storage.read(key: 'email');
String password = await _storage.read(key: 'password');
try {
final credential = await _firebaseAuth.signInWithEmailAndPassword(
email: email,
password: password
);
} on FirebaseAuthException catch (e) {
debugPrint('debug: cannot login: $e');
}
// ToDo: ログイン後処理
}
}
あとがき
配布するアプリで考えると、他にも下記のように色々やらないといけないことがあります
- View(ユーザ登録画面、ログイン画面)の作成
- エラーハンドリング
- 認証情報の保持方法(JWTやセッションなど)
ただ、大まかな流れは確認いただけるかなと思います
簡単な動作検証しかしておりませんが、2時間くらいでやりたかったことが概ね確認できるのは、Flutter本当に良いなと思います
明日は、@tjinjinさんの記事です!おたのしみに〜!