Flutter: Firebase auth から twitter サインインを行う。AndroidとiPhone

1.ながれ

Flutterアプリ用の部品集めバックエンドは、Firebaseを使用する

Google サインインを実現したので、twitterを試す。

firebase_auth プラグイン で全部行けるかと思ったら、Firebaseにかかる部分のみで、twitterからアクセストークンをもらうあたりの処理は範囲外のよう。

flutter_twitter_login プラグインを試したが、内部で非推奨のjava apiを利用しているというログが出ることと、公式プラグインでないことから、対処をググる中で、Stackoverflowのコメントを参考に処理を実装することとする。

動いたところ(Android/iPhone)

2.準備

2.1 twitter

以下のサイトから、アプリの登録を行い、アプリケーションの詳細 – Key and Tokens から、API key と API secret key を発行する。

Twitter Developer

twitter_dev_api_key

2.2 Firebase Console

Firebaseが、アプリケーションのバックエンドとして、リダイレクト先のURLやらを準備してくれる。

プロジェクトから、Authentication 、Sign in method から twitter を選択

twitter_firebase_auth01

2.1で取得した、API Key と API secret  key を登録、有効にする。

twitter_firebase_auth02

3.実装

3.1 呼び出し側

  1. Tiwtter Sign In ボタン押下で、上記2で取得したAPIキーを、TwitterSiginInPageに引き渡す
  2. 画面遷移を終え、戻ってくると、credential に、トークンが含まれている
  3. 取得したトークンをFirebase authに渡して、ユーザー情報を取得し画面表示

lib\firebase_auth.dart

import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';

import './twitter_sign_in.dart';

class FirebaseAuthPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => FIrebaseAuthPageState();
}

enum Menu {
  twitter_sign_in,
  item2,
}
class FIrebaseAuthPageState extends State<FirebaseAuthPage> {
  final FirebaseAuth _auth = FirebaseAuth.instance;
  String _userAvatarUrl = '';
  String _userDisplayName = '';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Firebase Auth Sample"),
      ),
      body: Column(
        children: <Widget>[
          PopupMenuButton(
            onSelected: popupMenuSelected,
            itemBuilder: (BuildContext context) =>
            <PopupMenuEntry<Menu>>[
              const PopupMenuItem( child: const ListTile( leading:Icon(Icons.account_box),
                  title:Text("Twitter Sign In")), value: Menu.twitter_sign_in),
              const PopupMenuItem( child: const ListTile( leading:Icon(Icons.account_circle),
                  title:Text("item2")), value: Menu.item2),
            ],
          ),
          ListTile(leading :
            CircleAvatar(
              backgroundImage: NetworkImage(_userAvatarUrl),
            ),
            title:Text(_userDisplayName ?? ''),),
        ],
      ),
    );
  }
  void popupMenuSelected(Menu selectedMenu){
    switch(selectedMenu) {
      case Menu.twitter_sign_in:
        _pushTwitterPage(context);
        break;
      default:
        break;
    }
  }

  void _pushTwitterPage(BuildContext context) async {
    Widget page = TwitterSignInPage(
            consumerKey: "***** your api key ****",
            consumerSecret: "***** your api secret key ****",
            oauthCallbackHandler: "https://**** firebase call back url ****");

    final credential = await Navigator.of(context).push(
        MaterialPageRoute<AuthCredential>(builder: (_) => page)
    );

    FirebaseUser user;
    if (credential != null) {
      user = (await _auth.signInWithCredential(credential)).user;
    }
    setState(() {
      if (user != null) {
        _userAvatarUrl = user.photoUrl;
        _userDisplayName = user.displayName;
      } else {
        _userDisplayName = 'Failed to sign in with Twitter. ';
      }
    });
  }

//  void _twitterSignOut() async {
//    _auth.signOut();
//  }

}

3.2 twitter ログイン主処理

5年ほど前5年ほど前にも、Djangoで同じことをやっていた。以下を参考にSTEP1~3を実装

https://stackoverflow.com/questions/60461547/how-to-sign-in-with-twitter-using-firebase-auth-with-flutter

Login with twitter ガイド

STEP1

twitter_login_mechanism

STEP2

twitter_login_mechanism_step2

STEP3

twitter_login_mechanism_step3

lib/twitter_sign_in.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
import 'package:oauth1/oauth1.dart';
import 'package:firebase_auth/firebase_auth.dart';

///
/// https://stackoverflow.com/questions/60461547/how-to-sign-in-with-twitter-using-firebase-auth-with-flutter
///
class TwitterSignInPage extends StatefulWidget {

  final twitterPlatform = Platform(
    'https://api.twitter.com/oauth/request_token', // temporary credentials request
    'https://api.twitter.com/oauth/authorize', // resource owner authorization
    'https://api.twitter.com/oauth/access_token', // token credentials request
    SignatureMethods.hmacSha1, // signature method
  );

  final ClientCredentials clientCredentials;
  final String oauthCallbackHandler;

  TwitterSignInPage({
    @required final String consumerKey,
    @required final String consumerSecret,
    @required this.oauthCallbackHandler,
  }) : clientCredentials = ClientCredentials(consumerKey, consumerSecret);

  @override
  State<StatefulWidget> createState() => TwitterSignInPageState();
}

enum Menu {twitter_sign_in, twitter_sign_out}

class TwitterSignInPageState extends State<TwitterSignInPage> {
  final flutterWebviewPlugin = FlutterWebviewPlugin();

  Authorization _oauth;

  @override
  void initState() {
    super.initState();

    // Twitter OAuth の初期化
    _oauth = Authorization(widget.clientCredentials, widget.twitterPlatform);

    flutterWebviewPlugin.onUrlChanged.listen((url) {
      // STEP2のコールバックを、STEP3へ移動するために監視
      if (url.startsWith(widget.oauthCallbackHandler)) {
        final queryParameters = Uri.parse(url).queryParameters;
        final oauthToken = queryParameters['oauth_token'];
        final oauthVerifier = queryParameters['oauth_verifier'];
        if (null != oauthToken && null != oauthVerifier) {
          _twitterLogInFinish(oauthToken, oauthVerifier);
        }
      }
    });
    _twitterLogInStart();
  }

  @override
  void dispose() {
    flutterWebviewPlugin.dispose();
    super.dispose();
  }

  Future<void> _twitterLogInStart() async {
    assert(null != _oauth);

    // STEP1:リクエストトークンの入手
    //    oauth/request_tokenをPOST送信することで、リクエストトークンを入手
    //    oauth_callbackは、STEP2が成功したときにリダイレクトされるURL
    final requestTokenResponse =
        await _oauth.requestTemporaryCredentials(widget.oauthCallbackHandler);

    // STEP2: 認証ページへのリダイレクト
    //   oauth/authenticate のGETリクエストに、STEP1で入手したトークンを、oauth_tokenとして渡す
    final authorizationPage = _oauth.getResourceOwnerAuthorizationURI(
        requestTokenResponse.credentials.token);

    flutterWebviewPlugin.reloadUrl(authorizationPage);
  }

  Future<void> _twitterLogInFinish(
      String oauthToken, String oauthVerifier) async {

    // STEP3: リクエストトークンをアクセストークンに変換
    //     リクエストトークンをアクセストークンに書換えるのに、アプリケーションはPOST oauth/access_token へ STEP2で入手した、
    //     oauth_verifier POSTリクエストを送信する必要がある。
    //     リクエストトークンは、oauth_token ヘッダーにも渡されるが、これは署名プロセスに追記される
    final tokenCredentialsResponse = await _oauth.requestTokenCredentials(
        Credentials(oauthToken, ''), oauthVerifier);

    final result = TwitterAuthProvider.getCredential(
      authToken: tokenCredentialsResponse.credentials.token,
      authTokenSecret: tokenCredentialsResponse.credentials.tokenSecret,
    );
    print("result $result");

    Navigator.pop(context, result);
  }

  @override
  Widget build(BuildContext context) {
    return WebviewScaffold(
      appBar: AppBar(title: Text("Twitter Login")),
      url: "https://twitter.com",
    );
  }
}

以上。

Follow me!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です