メールアドレス認証してくれたユーザーに対してもTwitter認証できるようにしたいと思います。 色々なサービスで標準である機能なので作れれてよかった
この記事はReact Firebase入門シリーズです
1-1-1・ Firebase初期設定とFirebaseAuthのSignUp
1-1-2・ 「react-hook-form」を入れてみた
1-1-3・ AuthのSignUpの通信エラー対応
1-2 ・ FirebaseAuthのログイン処理
1-3 ・ FirebaseAuthのログイン認証とログアウト処理
1-4 ・ FirebaseAuthのパスワード初期化処理
1-5 ・ FirebaseAuthのメールアドレスの有効化
1-6 ・ FirebaseAuthのメールアドレスとパスワード変更
1-7 ・ FirebaseAuthの表示名変更
1-8 ・ FirebaseAuthの拡張項目追加
1-9-1 ・ FirebaseAuthのTwitter認証
1-9-2 ・ FirebaseAuthのTwitter認証(既存ユーザー向け)と解除 今ここ
2-1・ FirebaseStorageのファイルアップ:基礎
2-2・ FirebaseStorageのファイルアップ前に画像の切り抜き
2-3・ FirebaseStorageのファイルアップの移動
3-1・FirestoreのCRUD
3-2・Firestoreのデータ取得補足
3-3・Firestoreのページネーション処理
3-4・Firestoreのコレクション(テーブル)のJOIN
やりたい事
プログラムについて
修正箇所が多いので全部みたい人はブランチのリンクから参照してください
プロフィールの更新する画面の修正箇所
Twitterの処理用のファイルを作成
/src/firebaseprovider/Twitter.js
import React, { useState, useEffect } from "react"; import { useAuth } from "../../contexts/AuthContext" import firebase, {Twitter} from "../../firebase" import { useHistory} from "react-router-dom" import TwitterIcon from '@material-ui/icons/Twitter'; import { Button,} from '@material-ui/core'; import { createStyles, makeStyles, Theme } from "@material-ui/core/styles"; const useStyles = makeStyles((theme: Theme) => createStyles({ twitterBtn: { flexGrow: 1 }, twitterloginBtn: { marginTop: theme.spacing(2), flexGrow: 1 }, }) ); export const TwitterSingUpLogin = (props) => { const classes = useStyles();//Material-ui const history = useHistory() const [twitterMessage, setTwitterMessage] = useState("") async function handleTwitterSignup (event) { console.log("handleTwitterSignup") try { firebase .auth() .signInWithPopup(Twitter) .then((result) => { console.log(result); setTwitterMessage("認証に成功しました。ダッシュボードにリダレクトします") setTimeout(function(){ console.log("リダレクト処理") history.push("/dashboard") },1000); }); } catch (error) { switch (error.code) { case "auth/network-request-failed": setTwitterMessage("通信がエラーになったのか、またはタイムアウトになりました。通信環境がいい所で再度やり直してください。"); break; case "auth/credential-already-in-use": setTwitterMessage("他のユーザーでTwitter認証しているため、認証ができませんでした。"); break; case "auth/requires-recent-login": setTwitterMessage("別の端末でログインしているか、セッションが切れたので再度、ログインしてください。(ログインページにリダイレクトします)"); setTimeout(function(){ console.log("リダレクト処理") history.push("/login") },3000); break; default: //想定外 setTwitterMessage("失敗しました。通信環境がいい所で再度やり直してください。"); } } } return ( <> {twitterMessage && <div style={{ color: "red" }}>{twitterMessage}</div>} <Button fullWidth variant="contained" size="large" color="primary" className={classes.twitterloginBtn} onClick={handleTwitterSignup} > <TwitterIcon />{props.title} </Button> </> ) } export const TwitterLink = () => { const classes = useStyles();//Material-ui const [isTwitterLink, setIsTwitterLink] = useState(false) const [twitterMessage, setTwitterMessage] = useState("") const { currentUser, } = useAuth() const history = useHistory() useEffect(() => { async function fetchData() { //providerData Linkチェック setIsTwitterLink(false) currentUser.providerData.forEach(element => { if (element.providerId === "twitter.com" ){ setIsTwitterLink(true) } }); } fetchData(); },[currentUser]); function handleTwitterUnLink () { console.log("handleTwitterUnLink") setTwitterMessage("") currentUser.unlink("twitter.com").then(function() { setTwitterMessage("Twitterとのリンクを解除しました") setIsTwitterLink(false) }).catch(function(error) { console.log(error) switch (error.code) { case "auth/network-request-failed": setTwitterMessage("通信がエラーになったのか、またはタイムアウトになりました。通信環境がいい所で再度やり直してください。"); break; case "auth/credential-already-in-use": setTwitterMessage("他のユーザーでTwitter認証しているため、認証ができませんでした。"); break; case "auth/requires-recent-login": setTwitterMessage("別の端末でログインしているか、セッションが切れたので再度、ログインしてください。(ログインページにリダイレクトします)"); setTimeout(function(){ console.log("リダレクト処理") history.push("/login") },3000); break; default: //想定外 setTwitterMessage("失敗しました。通信環境がいい所で再度やり直してください。"); } }); } async function handleTwitterLinkWithPopup (event) { console.log("handleTwitterLinkWithPopup") setTwitterMessage("") currentUser.linkWithPopup(Twitter).then(function(result) { console.log("handleTwitterLinkWithPopup:result",result) setTwitterMessage("Twitterとリンクしました") setIsTwitterLink(true) }).catch(function(error) { // Handle Errors here. switch (error.code) { case "auth/network-request-failed": setTwitterMessage("通信がエラーになったのか、またはタイムアウトになりました。通信環境がいい所で再度やり直してください。"); break; case "auth/credential-already-in-use": setTwitterMessage("他のユーザーでTwitter認証しているため、認証ができませんでした。"); break; case "auth/requires-recent-login": setTwitterMessage("別の端末でログインしているか、セッションが切れたので再度、ログインしてください。(ログインページにリダイレクトします)"); setTimeout(function(){ console.log("リダレクト処理") history.push("/login") },3000); break; default: //想定外 setTwitterMessage("失敗しました。通信環境がいい所で再度やり直してください。"); } console.log(error) // ... }); } return ( <> {twitterMessage && <div style={{ color: "red" }}>{twitterMessage}</div>} {isTwitterLink && <> <TwitterIcon />Twitter:{' '}{' '}{' '}認証されています <Button fullWidth variant="contained" size="large" color="primary" className={classes.twitterBtn} onClick={handleTwitterUnLink} > 認証を解除する </Button> </> } {!isTwitterLink && <> <TwitterIcon />Twitter:{' '}{' '}{' '}認証されていません <Button fullWidth variant="contained" size="large" color="primary" className={classes.twitterBtn} onClick={handleTwitterLinkWithPopup} > >認証する </Button> </> } </> ) }
あとはプロフィール画面からコンポーネントを読んでいるだけです
+ <Typography className={classes.subtitle2} variant="subtitle2"> 外部アプリケーション認証</Typography> + <TwitterLink />
解説
currentUser.linkWithPopup(Twitter).then(function(result) {
は既存のユーザーに対して新しいプロバイダー(Twitter)を追加しています。 ログインと同じようにポップアップが表示されてGoogle先生がいい感じにやってくれます
currentUser.unlink("twitter.com").then(function() {
はユーザーのプロバイダーとのリンクを解除しています。 resultがないのがちょっと不安なんだけど・・・errorならエラー処理にいくのでいいかな
結果
- 認証されていない状態
- 認証ボタンを押したあとの状態
- Firebaseのコンソール画面
できていない事
- 1度ログインするとツイッターの認証画面が省略されてしまいます。複数のアカウントがある人むけに クリアしないといけないんですが。。。よくわからず 処理はいれてみたのですが・・・複数表示される事はなかった
Twitter.setCustomParameters({ prompt: 'select_account', // 追加 });
googleの認証を追加するときに検証しようと思う
- Twitter認証しかしていない人が認証をはずすと匿名アクセスになってしまう。このままログアウトになるとアクセスできなくなる。本番運用する場合は認証をはずすときに他のプロバイダーが登録されているのかをチェックするべきなんだけど・・・まだできていない
感想
既存のユーザーのリンク機能も追加された。メールアドレスとパスワードを入力しなくても済むので楽になった