Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
クロスオリジンでログイン状態を継続させるように見せるテクニック
Search
おdd
March 02, 2018
Programming
1
910
クロスオリジンでログイン状態を継続させるように見せるテクニック
in YAPC::Okinawa(2018) 前夜祭LT
おdd
March 02, 2018
Tweet
Share
More Decks by おdd
See All by おdd
学歴マイノリティの皆様に贈る布石の打ち方のススメ
oddmutou
1
320
Other Decks in Programming
See All in Programming
Jakarta EE meets AI
ivargrimstad
0
650
タクシーアプリ『GO』のリアルタイムデータ分析基盤における機械学習サービスの活用
mot_techtalk
4
1.4k
Flutterを言い訳にしない!アプリの使い心地改善テクニック5選🔥
kno3a87
1
190
PHP でアセンブリ言語のように書く技術
memory1994
PRO
1
170
TypeScriptでライブラリとの依存を限定的にする方法
tutinoko
3
690
Duckdb-Wasmでローカルダッシュボードを作ってみた
nkforwork
0
130
リアーキテクチャxDDD 1年間の取り組みと進化
hsawaji
1
220
3 Effective Rules for Using Signals in Angular
manfredsteyer
PRO
1
100
TypeScript Graph でコードレビューの心理的障壁を乗り越える
ysk8hori
2
1.1k
ピラミッド、アイスクリームコーン、SMURF: 自動テストの最適バランスを求めて / Pyramid Ice-Cream-Cone and SMURF
twada
PRO
10
1.3k
役立つログに取り組もう
irof
28
9.6k
Hotwire or React? ~アフタートーク・本編に含めなかった話~ / Hotwire or React? after talk
harunatsujita
1
120
Featured
See All Featured
Unsuck your backbone
ammeep
668
57k
VelocityConf: Rendering Performance Case Studies
addyosmani
325
24k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
26
2.1k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
6
410
GraphQLとの向き合い方2022年版
quramy
43
13k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
246
1.3M
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
0
96
Teambox: Starting and Learning
jrom
133
8.8k
The Straight Up "How To Draw Better" Workshop
denniskardys
232
140k
5 minutes of I Can Smell Your CMS
philhawksworth
202
19k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
250
21k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
16
2.1k
Transcript
クロスオリジンで ログイン状態を継続させる ( ようにみせる ) テクニック not SSO with perl(sledge)
and JS(jquery) 2018/03/02 YAPC::Okinawa 前夜祭 Nao Muto (@oddmutou)
自己紹介 氏名生年月日ハンドル 武藤 尚 Muto Nao (1996/06/25) Twitter 等 :
@oddmutou CPAN: MUTO 所属等 シーサー株式会社 社員 ( したらば掲示板, SesaaWiki , BoomAppGames , etc.) 東京デザインテクノロジーセンター専門学校 非常勤講師 東京通信大学 学生 ( 春から )( 第一期生予定 )( ネタ入学で差をつけろ )
とある新規サービス 仕様策定・設計等 他社競合 ? を見ると表示側はサブドメインを沢山つくってるしうちもそうしよう → 「そのほうがかっこよさそう ! 」( SEO
的にはどうなんかよくしらんけど) dev.to 流行ってるし CDN で爆速配信!目標の月間 ? 億 PV に耐えれるインフラも ! → 「やるぞ ! 」 (dev.to が話題になるあたりに始めて年内リリース済みの爆速開発 ) (インフラ設計も俺) SNS 連携 / 会員登録的な機能も作ろう → 「テンション上がってきた ! 」「まぢ卍」
雑な構成図 なんとか .sample.com user.sample.com 新規登録 / ログイン / ログアウト アカウント設定
アカウントへの通知なども - A.sample.com - B.sample.com - C.sample.com … 表示がメイン 裏側で使うようの何か .sample.com DB (記事データ等)や KVS (セッション等) ◦ 各 にはそれぞれ別のアプリが (マイクロサービス化的なことやってみたかったんです)
主なページは CDN でゴリゴリキャッシュさせるから静的 しかし右上にログイン状態を表示させたい ! github や twitter とかによくある,非ログイン時ならログインや新規登録へのリンクが,ロ グイン時ならアイコンがでるやつ。
→JS で取れるようにユーザー情報管理サーバーにログイン状態取得 API を作る →REST API? そんなのしらないヨ ということでセッションクッキーを見ちゃう $.ajax({ url:
‘https://user.sample.com’, type: 'GET', dataType: 'json', xhrFields: { withCredentials: true } }).done(function(response){ 以下略 「 xhrFields: {withCredentials: true} 」で cookie 送ってくれるのかーなるほどー
複数ドメイン間 (A.example.com → user.example.com) で API 叩くには Access- Control-Allow-Origin が必要というのはわかっていた。
また,今回はログイン状態を取るだけであるため,厳しく設定する必要もないので,「 * 」に する。 $self->r->header_out('Access-Control-Allow-Origin' => ‘*’);
> クロスオリジン要求をブロックしました : 同一生成元ポリシーによ り、 https://user.sample.com にあるリモートリソースの読み込みは拒否されます ( 理由 :
CORS ‘ ヘッダー Access-Control-Allow-Credentials’ ‘ は true’ である べき ) 。 ドメインが異なる API のときは「 Access-Control-Allow-Origin: * 」ってつけてれば良い ことは知っていたが, Cookie 送るときはまた別のものが要るらしい。 $self->r->header_out('Access-Control-Allow-Origin' => ‘*’); $self->r->header_out('Access-Control-Allow-Credentials' => "true");
> クロスオリジン要求をブロックしました : 同一生成元ポリシーにより https://user.example.com にあるリモートリソースの読み込みは拒否されます ( 理 由 :
CORS ‘ ヘッダー Access-Control-Allow-Origin’ ‘ が *’ である場合、認証情 報はサポートされない ) 。 Cookie 送るときは「 Access-Control-Allow-Origin: * 」だと怒られるらしいので,もう無 … 理やり 。 とりあえずこれで取得できて,超いい感じに表示できた。 $self->r->header_out('Access-Control-Allow-Origin' => $self->r->header_in('Origin')); $self->r->header_out('Access-Control-Allow-Credentials' => "true");
毎回 API 叩くのは負担になるからブラウザ側でキャッシュしたい ! →sessionStorage に保管する →sessionStorage は KVS なので出し入れ時に
JSON にデコード / エンコードする。 → 普段 SSR なサービスしか触ってないと知らないことだったけど,かんたん。 sessionStorage.setItem('login_status', JSON.stringify(response)); JSON.parse(sessionStorage.getItem('login_status')));
キャッシュクリアのタイミングどうする ? → sessionStorage なのでウィンドウ閉じればクリアされるが,それ以外に も, user.example.com でのログイン時・ログアウト時にキャッシュをクリアする必要があ る。 →
cookie のように「 *.example.com 」のようにスコープにワイルドカードを使いたいが, sessionStorage のスコープは「発生元のオリジン」 ( スキーム & ドメイン & ポート ) で固 定されており, user.example.com から A.example.com の sessionStorage を操作す ることはできない。
革命的発案 *.example.com な cookie に「ログイン状態の最終更新日時」を保管し,それを読んで sessionStorage を操作する &API を叩いて更新すればよい user.example.com
ログイン,ログアウト時に cookie を更新 $.cookie('update_time', 今の時間 , {path: '/', domain: '*.example.com'}); A.example.com ログイン,ログアウト時に cookie を更新 last_time = localStorage.getItem(‘last_time’;) time = $.cookie('update_time'); if (time > last_time) { localStorage のキャッシュを使う } else { API 叩く &localStorage のキャッシュを更新 localStorage.setItem(‘last_time’, 今の時間 ); } ↑ 「時間」の中身は端折りましたが,私は unix 秒 ( 整数値 ) を使いました。また jquery.cookie.js を使っていま
全く別ドメインのサービスでもユーザー情報使いたい ! → 敗北宣言 :iframe 使います user.example.com ログイン・ログアウトページ iframe 内の
hogehoge.com $.cookie('update_time', 今の時間 , {path: '/', domain: 'hogehoge.com'}); hogehoge.com 先ほどの A.example.com と同様に, cookie の update_time を見て localStorage のキャッシュを使うか, API 叩いて更新するかします。
ぼく「クロスオリジン,気が狂いそうです〜 ( 普段単純な SSR しかやらないので ) 」 先輩「広告やさんっぽいことやってるね〜」
似た話が別サービス(以下サービス A とします) で湧いてきた
ユーザーで独自ドメインが設定できるサービス A ↓ 記事ページにもログインしてコメントのフォームが欲しい ! ユーザーの独自ドメイン 適用ページ - トップページ -
記事ページ 等表示だけのページ & サーバー側でキャッシュも効いている 独自ドメイン 非適用ページ - コメントページ 等ログインして書き込みとかできるページ
サービス A において,静的ページでもログイン状態を表示したい場合は,セッション用の cookie が存在すれば API を都度叩く,という実装が既にあった。 ( 想定アクセス数的にキャッシュするほどでもないが,クローラーや一見さんの閲覧時に 無駄に
API 叩かれるのは怖いため。 ) ↓ 独自ドメインの場合はセッションが無いので,別途ログインするユーザーか見分ける印を 付ける必要がある。 そして歴史あるサービスであるため,深く弄りだすと年が暮れるので避けたい。
〜サービス A のログイン時の挙動〜 独自ドメインページ(ユーザーのドメイン)の「ログイン」リンクをクリック ↓ サービス A のデフォルトドメイン(弊社のドメイン) ↓ リダイレクト
弊社の複数サービスで使っているアカウントサーバー ↓ リダイレクト サービス A のデフォルトドメイン ↓ リダイレクト 独自ドメイン(「ログイン」リンクがあったページに戻る)
〜サービス A のログイン時の挙動〜 独自ドメインページ(ユーザーのドメイン)の「ログイン」リンクをクリック ↓ サービス A のデフォルトドメイン(弊社のドメイン) ↓ リダイレクト
弊社の複数サービスで使っているアカウントサーバー ↓ リダイレクト サービス A のデフォルトドメイン ↓ リダイレクト 独自ドメイン(「ログイン」リンクがあったページに戻る) ここにログインしていることを示す SessionStorage 保管する処理を追加
〜サービス A のログイン時の挙動〜 独自ドメインページ(ユーザーのドメイン)の「ログイン」リンクをクリック ↓ サービス A のデフォルトドメイン(弊社のドメイン) ↓ リダイレクト
弊社の複数サービスで使っているアカウントサーバー ↓ リダイレクト サービス A のデフォルトドメイン ↓ リダイレクト 独自ドメインで Cookie を操作 ↓ リダイレクト 独自ドメイン(「ログイン」リンクがあったページに戻る)
〜サービス A のログイン時の挙動〜 独自ドメインページ(ユーザーのドメイン)の「ログイン」リンクをクリック ↓ サービス A のデフォルトドメイン(弊社のドメイン) ↓ リダイレクト
弊社の複数サービスで使っているアカウントサーバー ↓ リダイレクト サービス A のデフォルトドメイン ↓ リダイレクト 独自ドメインで Cookie を操作 ↓ リダイレクト 独自ドメイン(「ログイン」リンクがあったページに戻る)
まとめ - クソにクソの上塗りをするのはいつも悔しい - どこでローカルに仕込むとか考えるのなんだかんだで楽しい! - Perl で単純に SSR なサービスしか書かないマン,たまにこういうことやると楽しい!