「react router v6 の Object-based Routes」を使うと Reactのルーティング周りがいい感じに書けて良い
最初こっちに書いてたけどQiitaに出来そうだったのでコンバート。 またこのパターン。
React Router v6 の Object-based Routes をキメると、ルーティング実装が気持ちよくなる(かもしれない)ので紹介させてほしい - Qiita
Reactアプリのログインチェック機能がまぁまぁ上手くできた話
React(SPA)でログインチェック機能がまぁまぁ上手く出来たので軽くメモを残す。
認証済みを表す状態をグローバルで保持する必要があるかと思ったが、特にそんなことはなかった。
その代わり"ログインチェック"済みかどうかを表す状態を保持することにした。
満たすべき要件
- アプリケーションにアクセスした際、認証済みかどうかをチェックする(ログインチェック)
- 認証済みの場合はホームページ(任意)に、そうでない場合はログインページに飛ばす
- ログインチェックが終わるまではページを表示しない。もしくはローディング画面を表示する。
ログインチェック
- ログインチェック用のAPIを用意する。
- useLoginCheckというhooksを作成しAppで呼び出す。
- useLoginCheckでは用意したAPIを叩き結果を取得する
- 処理結果に関わらず処理は継続したいので、catchもしっかりと設定して例外で落ちないようにする。
参考
useLoginCheck
zaik/useLoginCheck.ts at 0e40fbd78e6bb14eb3f4a374babe6421da8682b4 · takahiromasui001/zaik · GitHub
App
zaik/App.tsx at 0e40fbd78e6bb14eb3f4a374babe6421da8682b4 · takahiromasui001/zaik · GitHub
ログインチェック用API(def show)
zaik/sessions_controller.rb at 0e40fbd78e6bb14eb3f4a374babe6421da8682b4 · takahiromasui001/zaik · GitHub
ログインチェック後のページ遷移
- useLoginCheckでAPIを叩いた結果ログインしていないことが判明したら(200OKでなかったら)、login画面に飛ばす
- 200OKの場合はそのまま。結果的にURLで指定された任意のページが表示される。
参考
useLoginCheck
zaik/useLoginCheck.ts at 0e40fbd78e6bb14eb3f4a374babe6421da8682b4 · takahiromasui001/zaik · GitHub
ログインチェック中のローディング画面。
- ログインチェック実行済みか否かを示す、グローバルなステート(loginChecked)を用意。初期値false。
- loginCheckedがfalseの場合、ローディング画面(ローディング用のコンポーネント)を表示するようにAppコンポーネントを修正
- useLoginCheckでAPIを叩いた後にloginCheckedをfalseにする。
参考
大方針はこのページのやり方を参考にした
ReactでAPI通信をしている間Loading画面を表示する | Fintan
authSlice
zaik/authSlice.ts at 0e40fbd78e6bb14eb3f4a374babe6421da8682b4 · takahiromasui001/zaik · GitHub
App
zaik/App.tsx at 0e40fbd78e6bb14eb3f4a374babe6421da8682b4 · takahiromasui001/zaik · GitHub
備考
loginChecked ステートは loading ステートに名称を変更して、もう少し汎用的に使える形にした方が良いかもしれない。
React Router v6 移行作業で引っかかった箇所のメモ
Qiitaに記載。(果たしてこれでいいのか。。。逆では?)
React + Rails(API)で tokenを用いたCSRF対策の基礎(のメモ)
cookieを利用した認証を採用した場合、必然的にCSRFの対策を行う必要がある。 Railsのようなモノリシックなフレームワークを用いている場合、デフォルトでCSRF対策が入っている(ことが多い)ためCSRFの考慮する必要はないが、 React + RailsのようなSPA環境では、CSRF対策に関してもある程度自分で手を加える必要がある。 試しにやってみたので、軽くメモ。 とりあえず動く程度のメモなので、セキュリティ的に色々不都合はあるかもしれない。今後要調査。
やったこと
API側
(準備) - CSRF用の機能を有効化する - include ActionController::RequestForgeryProtection(in application_controller.rb) - apiモードだとデフォルトで含まれていない様子なので、includeが必要そう
(tokenの生成) - ログイン時/ログイン確認時に、csrf tokenを生成 & レスポンスヘッダ(X-CSRF-Token)にcsrf tokenを挿入 - form_authenticity_token(ActionController::RequestForgeryProtectionの機能)を利用 - corsの設定で、expose: ['X-CSRF-Token']を追加(X-CSRF-Tokenヘッダをexposeする)
(tokenのチェック) - RailsでCSRF tokenの確認を有効にする。 - protect_from_forgery with: :exception(in application_controller.rb, ActionController::RequestForgeryProtectionの機能) - ログイン時 のみCSRF tokenの確認を無効化 - skip_before_action :verify_authenticity_token, only: :create - verify_authenticity_tokenはprotect_from_forgeryの中で利用されている
フロント側
実装例(github)
csrf api側 · takahiromasui001/spa_session_cookie_auth_trial@9c4017a · GitHub
csrf front側 · takahiromasui001/spa_session_cookie_auth_trial@5ee4a48 · GitHub
備考
- 調査に時間はかかったが、実装はかなりシンプルになった。
- セッション作成&セッションの確認毎にcsrf tokenを更新している。その点ではやや妥協。
- ログイン時のcsrfも考慮していない。この辺りは今後の要改善点
参考にした情報
RailsのCSRF保護を詳しく調べてみた(翻訳)|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社 Railsそのもののtoken機能に関する詳しい説明。
Rails API mode+deviseなSPAでtokenによるCSRF対策をする - Qiita
方針の説明含め一番わかりやすい。サンプルコードもあり。
だいたいこれをパクった。
Cross-Site Request Forgery Prevention - OWASP Cheat Sheet Series
OWASPのCSRFに関する説明および対策を解説した資料。一通り目を通すだけでもCSRFの概略は掴める。
今回の実装ではここで示されている、synchronizer token pattern(を少し簡略化したもの)を採用
RailsでCORSのAccess-Control-Expose-Headersを設定する - Qiita
Rails APIにCORSアクセスした場合は、reseponseのヘッダーに表示する情報をあらかじめ設定しておく必要がある、という話。
AjaxにおけるCSRF攻撃対策 - バカンス駆動開発
Twitterのソース(?)をみた話とかが書いてある。csrf tokenはセッション単位で発行しているらしい。本記事もこれに倣った。
Rails(API)でcookieを使ったログイン機能実装のメモ
「Rails(API)でcookieを使ったログイン機能実装」にあたり、微妙に引っかかった点のメモ。 人が読むことを全く意識していない。
Userモデル作成
bin/rails g model user name:string email:string password_digest:string
has_secure_password
- Userモデルにhas_secure_password追加
- gemfileにbcrypt
sessions_controller: login(create)
has_secure_password関連のメソッドの利用方法
-
- Rails6のAPI使用でCookieを有効にする - Qiita
- 以下2点を加える。
- config.middleware.use ActionDispatch::Cookies
- config.middleware.use ActionDispatch::Session::CookieStore
- cors.rbにcredentials: trueも必要
ローカル環境(localhost)におけるRails APIのhttps対応 & Chromeデフォルト環境でエラーなく動作するための証明書作成
「ローカルの開発環境(localhost)でRails APIをhttps化」してみたので手順を残す。 (正直勘違いからのスタートだったので、用途を言及できないが。。。)
Railsのhttps化
基本的に以下の記事をそのまま利用。記事の実装は開発環境のみで動く形になっているので、本番環境以降時に変な影響を受けることがないのが安心ポイント
自己署名証明書の作成
上で作成した証明書は、このままだとブラウザから見て信頼できないものになるので、Chromeでエラー(ERR_CERT_AUTHORITY_INVALID)が発生する。そのためオレオレ証明書を作成しブラウザにインポートする必要がある。 またChromeの場合、ドメイン名のチェックをCommon Name(通称CN)ではなくSubject Alternative Names(通称SAN)を参考するようになったため、 SANが含まれていない場合エラー(NET::ERR_CERT_COMMON_NAME_INVALID)が発生する。 そのためSubject Alternative Namesを含んだ自己署名サーバ証明書を利用する必要もある。
自己証明書の作成
Chromeで使えるオレオレ証明書を作成する方法 - Qiita
上の記事で紹介されているツール(self-sign-cert)を利用することで容易に署名付き証明書を作成できる(感謝)。
証明書のブラウザへのインポート
Google Chromeへ証明書ファイルをインポートするには | サポート・お申し込みガイド | GMOグローバルサイン【公式】
作成した証明書を上の手順に従ってブラウザにインポートする。
Railsのデフォルトのcookieを用いたセッション管理における、セッション情報の保管場所について
Railsでセッション管理を行う場合は、"session"メソッドを利用するのが基本になる。 Railsのデフォルト動作ではこの"session"メソッドを用いた際cookieを用いてセッション情報を管理する事は知っていたが、 具体的に何をしているかに関してはあまりよく理解していなかった。
調査をしてみてある程度理解できたので備忘録代わりに記載する。
概要
- セッション情報はcookieに(暗号化の上で)埋め込まれて各クライアント(ブラウザ)で保持される
- サーバ側ではセッションに関する情報は一切保持していない (セッション情報の作成(?)や暗号化はする)
らしい。(多分合ってる)
参考にしたサイト
https://railsguides.jp/security.html#%E3%82%BB%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%B9%E3%83%88%E3%83%AC%E3%83%BC%E3%82%B8
https://oauth.jp/blog/2013/09/26/rails-session-cookie/
https://www.slideshare.net/carotene4035/sessionrailscookie-store
備考
セッションってサーバー側で保持されるようなイメージだったが、cookieってクライアント側で保持するよなぁという点がいまいち納得できていなかった。 cookieに入れる情報の作成&暗号化及び復号はサーバー(Rails)側で行うためセッション情報を管理しているのはサーバ側と表現するのも間違っていないかもしれない。 ただセッション情報の保管はクライアントがcookieを所持する形で行なっているということになるのかね。