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
1k
クロスオリジンでログイン状態を継続させるように見せるテクニック
in YAPC::Okinawa(2018) 前夜祭LT
おdd
March 02, 2018
Tweet
Share
More Decks by おdd
See All by おdd
学歴マイノリティの皆様に贈る布石の打ち方のススメ
oddmutou
1
340
Other Decks in Programming
See All in Programming
Swift Updates - Learn Languages 2025
koher
2
490
パッケージ設計の黒魔術/Kyoto.go#63
lufia
3
440
知っているようで知らない"rails new"の世界 / The World of "rails new" You Think You Know but Don't
luccafort
PRO
1
170
速いWebフレームワークを作る
yusukebe
5
1.7k
Android端末で実現するオンデバイスLLM 2025
masayukisuda
1
160
そのAPI、誰のため? Androidライブラリ設計における利用者目線の実践テクニック
mkeeda
2
320
アルテニア コンサル/ITエンジニア向け 採用ピッチ資料
altenir
0
110
JSONataを使ってみよう Step Functionsが楽しくなる実践テクニック #devio2025
dafujii
1
540
AIと私たちの学習の変化を考える - Claude Codeの学習モードを例に
azukiazusa1
10
4.3k
「待たせ上手」なスケルトンスクリーン、 そのUXの裏側
teamlab
PRO
0
550
2025 年のコーディングエージェントの現在地とエンジニアの仕事の変化について
azukiazusa1
24
12k
🔨 小さなビルドシステムを作る
momeemt
4
680
Featured
See All Featured
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
131
19k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
120k
It's Worth the Effort
3n
187
28k
Gamification - CAS2011
davidbonilla
81
5.4k
Six Lessons from altMBA
skipperchong
28
4k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
9
810
Making Projects Easy
brettharned
117
6.4k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.4k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
22k
Embracing the Ebb and Flow
colly
87
4.8k
GraphQLの誤解/rethinking-graphql
sonatard
72
11k
Scaling GitHub
holman
463
140k
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 なサービスしか書かないマン,たまにこういうことやると楽しい!