Flutterでシングルサインオン(SSO)

投稿者: | 2024年6月18日

シングルサインオン(SSO:Single Sign On)はユーザーにとって同じような情報を個別のサイトに記載する手間が省ける便利な手法で、ユーザー数を増やしたいサービスにとっても実装したい機能の一つである。

Flutterでもを簡単に実装するためのさまざまなライブラリが提供されている。以下は、Google、Discord、およびGitHubのSSOをFirebase認証とともにFlutterアプリケーションで実装する方法についてのガイドである。

FlutterのSSO用ライブラリ

  1. Googleサインイン: google_sign_in
  2. OAuth2: flutter_appauth
  3. Firebase認証: firebase_auth

Firebaseプロジェクトのセットアップ

  1. Firebaseプロジェクトを作成する:
  • Firebaseコンソールにアクセスする。
  • 新しいプロジェクトを作成するか、既存のプロジェクトを選択する。
  • FirebaseプロジェクトにFlutterアプリを追加する。
  • google-services.json(Android用)およびGoogleService-Info.plist(iOS用)をダウンロードし、プロジェクトに追加する。
  1. 認証方法を有効にする:
  • Firebaseコンソールで「Authentication」セクションに移動する。
  • 必要な認証方法(Google、Discord、GitHubのOAuthプロバイダー)を有効にする。

Googleサインイン

  1. 依存関係を追加する:
    dependencies:
     flutter:
       sdk: flutter
     firebase_core: latest_version
     firebase_auth: latest_version
     google_sign_in: latest_version
    
  2. Firebaseを初期化する:
    import 'package:firebase_core/firebase_core.dart';
    import 'package:flutter/material.dart';
    
    void main() async {
     WidgetsFlutterBinding.ensureInitialized();
     await Firebase.initializeApp();
     runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
     @override
     Widget build(BuildContext context) {
       return MaterialApp(
         title: 'Flutter Demo',
         theme: ThemeData(
           primarySwatch: Colors.blue,
         ),
         home: SignInPage(),
       );
     }
    }
    
  3. Googleサインインを実装する:
    import 'package:firebase_auth/firebase_auth.dart';
    import 'package:flutter/material.dart';
    import 'package:google_sign_in/google_sign_in.dart';
    
    class SignInPage extends StatelessWidget {
     final FirebaseAuth _auth = FirebaseAuth.instance;
     final GoogleSignIn _googleSignIn = GoogleSignIn();
    
     Future<User?> _signInWithGoogle() async {
       try {
         final GoogleSignInAccount? googleUser = await _googleSignIn.signIn();
         if (googleUser == null) {
           return null;
         }
    
         final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
         final AuthCredential credential = GoogleAuthProvider.credential(
           accessToken: googleAuth.accessToken,
           idToken: googleAuth.idToken,
         );
    
         final UserCredential userCredential = await _auth.signInWithCredential(credential);
         return userCredential.user;
       } catch (e) {
         print(e);
         return null;
       }
     }
    
     @override
     Widget build(BuildContext context) {
       return Scaffold(
         appBar: AppBar(
           title: Text('Sign In'),
         ),
         body: Center(
           child: ElevatedButton(
             onPressed: () async {
               User? user = await _signInWithGoogle();
               if (user != null) {
                 // サインインに成功した、UIを更新する
               }
             },
             child: Text('Sign in with Google'),
           ),
         ),
       );
     }
    }
    

DiscordおよびGitHubサインインのOAuth2を使用する

  1. 依存関係を追加する:
    dependencies:
     flutter:
       sdk: flutter
     firebase_core: latest_version
     firebase_auth: latest_version
     flutter_appauth: latest_version
     http: latest_version
    
  2. Firebaseを初期化する:

    (Googleサインインセクションでカバー済み)

  3. DiscordおよびGitHubのOAuth2を設定する:
    import 'package:firebase_auth/firebase_auth.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter_appauth/flutter_appauth.dart';
    import 'package:http/http.dart' as http;
    
    final FlutterAppAuth appAuth = FlutterAppAuth();
    final FirebaseAuth _auth = FirebaseAuth.instance;
    
    Future<User?> _signInWithOAuth(String provider) async {
     String clientId;
     String redirectUrl;
     String authorizationEndpoint;
     String tokenEndpoint;
     String scopes;
    
     if (provider == 'discord') {
       clientId = 'YOUR_DISCORD_CLIENT_ID';
       redirectUrl = 'YOUR_DISCORD_REDIRECT_URI';
       authorizationEndpoint = 'https://discord.com/api/oauth2/authorize';
       tokenEndpoint = 'https://discord.com/api/oauth2/token';
       scopes = 'identify email';
     } else if (provider == 'github') {
       clientId = 'YOUR_GITHUB_CLIENT_ID';
       redirectUrl = 'YOUR_GITHUB_REDIRECT_URI';
       authorizationEndpoint = 'https://github.com/login/oauth/authorize';
       tokenEndpoint = 'https://github.com/login/oauth/access_token';
       scopes = 'user repo';
     } else {
       throw ArgumentError('Unknown provider');
     }
    
     final AuthorizationTokenResponse? result = await appAuth.authorizeAndExchangeCode(
       AuthorizationTokenRequest(
         clientId,
         redirectUrl,
         serviceConfiguration: AuthorizationServiceConfiguration(
           authorizationEndpoint,
           tokenEndpoint,
         ),
         scopes: scopes.split(' '),
       ),
     );
    
     if (result == null) {
       return null;
     }
    
     final AuthCredential credential = OAuthProvider(provider).credential(
       accessToken: result.accessToken,
       idToken: result.idToken,
     );
    
     final UserCredential userCredential = await _auth.signInWithCredential(credential);
     return userCredential.user;
    }
    
    class SignInPage extends StatelessWidget {
     @override
     Widget build(BuildContext context) {
       return Scaffold(
         appBar: AppBar(
           title: Text('Sign In'),
         ),
         body: Center(
           child: Column(
             mainAxisAlignment: MainAxisAlignment.center,
             children: [
               ElevatedButton(
                 onPressed: () async {
                   User? user = await _signInWithOAuth('discord');
                   if (user != null) {
                     // サインインに成功した、UIを更新する
                   }
                 },
                 child: Text('Sign in with Discord'),
               ),
               ElevatedButton(
                 onPressed: () async {
                   User? user = await _signInWithOAuth('github');
                   if (user != null) {
                     // サインインに成功した、UIを更新する
                   }
                 },
                 child: Text('Sign in with GitHub'),
               ),
             ],
           ),
         ),
       );
     }
    }
    

まとめ

google_sign_influtter_appauth、およびfirebase_authのようなFlutterライブラリを使用することで、Google、Discord、およびGitHubのSSOをFirebase認証とともに簡単に実装できる。これらのライブラリは、OAuth2フローの処理、安全なトークン管理、Firebase認証との統合を扱い、ユーザーエクスペリエンスとアプリケーションロジックに集中することができる。

上記の例に従うことで、FlutterアプリにSSOを設定し、異なるプロバイダー間で一貫した安全な認証プロセスを確保できる。

この例ではFirebaseをベースのログイン機構に利用しているが、他の場合でもほぼ同様の流れで実装できる。

コメントを残す