マジサッチャー4日目

Pnyompen
@pnyompen

はじめに

Firebase触ってみたいな〜と思い、誰も得しないようなWebアプリを作ってみました。

作ったサービス「マジサッチャー」

なんか錯覚を使った動画を自分でも作りたいなぁ...と思ったときにサッチャー錯視を使った動画が即座にできるアプリ。気持ち悪い錯覚体験を友達と共有だ!
https://maji-thatcher.tokyo

zjd7v-6409o.gif zjd7v-6409o.gif

こんな感じで、無性にサッチャー錯視を見たいときにでも使ってみてください。
そんなことないとは思いますが…
ログインしなくても動画作って楽しめるのでぜひ遊んでみてください。

https://maji-thatcher.tokyo

サッチャー錯視とは

サッチャー錯視は、顔を180度回転させた逆さまの状態では、顔のちょっとした変化に気づきにくくなるという現象です。

result.jpg result.jpg

イギリスの首相マーガレット・サッチャー氏の顔写真を使用して、サッチャー錯視の存在を証明したことにちなんで、サッチャー錯視と名付けられました。
このサッチャー氏の顔写真もこの状態ではそれほど不自然じゃないですが、ひっくり返すと…

あまりインパクトのない錯視らしく、説明しないとなかなかわからないようです!

全体構成

ページにほぼ動的な部分がないので、NuxtでGenerateして、Hostingで配信しています。
FunctionsだけPythonを使いたかったのでCloudFunctionsを使っています。

Paper.Work.1.png Paper.Work.1.png

Twitter投稿の流れ

普通のサーバーならすぐ終わるようなことでも、意外と回りくどいです。
今回の場合、もしかしたらFireStoreはいらなかったかもしれません…

Paper.Work.1 \(3\).png Paper.Work.1 \(3\).png

Twitterでログイン

ここら辺は公式ドキュメント見ればすぐにできちゃうのでスキップ
JavaScript で Twitter を使用して認証する

自分でプラグイン入れたり、callbackページ作ったりしなくていいなんてなんて便利なんでしょ
Firebaseバンザイ!

AccessToken・Secretの取得

クライアントサイドでTwitterログインするとToken・Secretもらえるので取り出します。

js
const result = await firebase.auth().signInWithPopup(provider) const token = result.credential.accessToken; const secret = result.credential.secret;

AccessToken・Secretの保存

Twitterへの投稿はCloudFunctions使ってサーバーサイドで行うので、FireStoreに保存しておきます。
ユーザーのログイン後にしか使わないようなら、VueのStoreに入れとくだけでも良いかもしれません。

js
const db = firebase.firestore() await db .collection('users') .doc(uid) .set( { twitterCredentials: { secret: secret, accessToken: token } }, { merge: true } )

FireStoreルールの設定

他人には見られたくないものなので、FireStoreのルールも追加します。
自分のユーザーIDのドキュメントには自分しか参照、変更できないように設定。
これで、他の人から見られたり変更される心配はありません!

firestore.rules
service cloud.firestore { match /databases/{database}/documents { match /users/{userID} { allow read, write: if request.auth.uid == userID; } } }

Functionsの設定

今回はPythonランタイムを使いたかったので、CloudFunctions使いました。
まだベータ版のため、コンパイルが必要なライブラリとかだとインストールできないこともあります。
とりあえずインストールできること確認してから使ったほうがいいかもしれません。

次のモジュールをインストールします。

  • python-twitter: Twitter投稿用の便利ライブラリ
  • firebase-admin: Firebaseの機能にアクセスするために必要

Python CloudFunctionsはPipenvに対応しているので、Pipenvでインストールすればオッケーです。
Pyenvを使う場合は、requirements.txtを書き出してスクリプトと同じディレクトリに置いておけばオッケー。

bash
$ pipenv install firebase-admin,python-twitter

インポートして初期化
firebase_adminは、認証情報を設定しなければ、自動でプロジェクトの認証情報で初期化されます。
便利ー

main.py
import firebase_admin from firebase_admin import firestore from firebase_admin import auth # FireBaseのプロジェクトにデプロイすれば勝手にプロジェクトの認証情報で初期化される firebase_admin.initialize_app() client = firestore.client()

Functionsでユーザー認証

Firebaseが発行するJWTを使ってユーザーを認証します。
JWTの有効期限は1時間と短いので、期限が切れたら、再発行して使う必要があります。
ID トークンを確認する

headerにJWTを付けてPOST

js
const token = await firebase.auth().currentUser.getIdToken() const config = { headers: { Authorization: token } } const response = await this.$axios.post( apiUrl, body, config )

CloudFunctionsをHttp経由で呼び出した場合Flaskとおんなじなので、こんな感じで。

受け取ったJWTを検証して、ユーザーを認証します。
JWTにはユーザーID情報が含まれているので、ユーザーIDからTwitter認証情報を取得。

main.py
def my_function(request): # JWTをデコードする、ここでTokenが正しいかどうかも検証される decoded_token = auth.verify_id_token(request.headers['Authorization']) # デコードされたDictの”sub”がユーザーID uid = decoded_token['sub'] # FireStoreからTwitter認証情報をとってくる users_ref = client.collection('users') user_doc_ref = users_ref.document(uid) user_doc = user_doc_ref.get().to_dict()

動画を投稿

Twitterを投稿するには、アプリケーションのトークンと、ユーザーのトークン両方が必要になります。
APIキーは環境変数へということなので、CloudFunctionsの環境変数にアプリケーションのトークンを設定します。
環境の構成

Deployの際のコマンドから設定する方法もあるのですが、いちいち大変なので、YAMLで書いて、Deployの際に環境変数に設定します。
.gitignoreへの設定もお忘れなく

bash
$ echo .env.yaml >> .gitignore
.env.yaml
TWITTER_CONSUMER_KEY: xxxxxxxxxxxxxx TWITTER_CONSUMER_SECRET: xxxxxxxxxxxxxxx

デプロイする際に環境変数を書いたYAMLを指定します

deploy.sh
GCF_NAME="my_function" GCF_REGION="asia-northeast1" gcloud functions deploy $GCF_NAME \ --runtime python37 \ --region $GCF_REGION \ --trigger-http \ --env-vars-file .env.yaml

動画付きツイートを投稿する

あとはToken, Secretを使って投稿するだけ

最初に動画を投稿すると、media_idが発行されるので、それを投稿につけて投稿すれば、動画付きツイートの完成です。

main.py
# base64でエンコードされた動画情報ならデコードしてioに入れる decoded = base64.b64decode(movie_base64) movie_io = io.BytesIO(decoded) # 本来はopen(PATH_TO_VIDEO, 'rb)を渡すためこのパラメータも設定しておく movie_io.mode = 'rb' movie_io.name = 'movie.mp4' # FireBaseから取ってきた認証情報とアプリの認証情報を使って初期化 api = twitter.Api( consumer_key=CK, consumer_secret=CS, access_token_key=ATK, access_token_secret=ATS ) # 先に動画を投稿 media_id = api.UploadMediaChunked( media=movie_io, media_category="tweet_video") # すぐにアクセスするとTwitter側のDBに動画が登録されていないことがあるので、少し時間をおいてからアクセスする time.sleep(1) #mediaと一緒に本文も投稿 api.PostUpdate(status=tweet_text, media=media_id)

まとめ

FireBaseはじめて触ったのですが、とっても簡単でびっくりしました。これからもりもりFirebase使っていらないものを作っていこうと思います!
ぜひ皆さんもFirebaseとNuxtで楽しいコーディングライフを〜

#終わりに
本記事をここまでお読みいただきありがとうございました。それ違うんじゃね?とか多分満載だと思うので、よかったらぜひTwitter(@Pnyompen) で絡んでくださいね。

WRITER
Pnyompen
@pnyompen
SERIES
この記事に連載はありません。
READ NEXT
COMMENTS
コメント機能は開発中です。実装完了まで今しばらくお待ちください。