Slide 1

Slide 1 text

3rd Party API on Rails
 Kaigi on Rails 2022
 2022.10.21 - 22
 @internet(online)
 株式会社ZOZO
 ブランドソリューション開発本部 バックエンド部
 ディレクター
 諏訪 智大(@tsuwatch) Copyright © ZOZO, Inc. 1

Slide 2

Slide 2 text

© ZOZO, Inc. 株式会社ZOZO
 ブランドソリューション開発本部 バックエンド部
 ディレクター 諏訪 智大
 2015年ドワンゴ入社、2021年4月ZOZO入社
 WEAR開発責任者
 
 Twitter/GitHub: @tsuwatch
 2

Slide 3

Slide 3 text

© ZOZO, Inc. https://wear.jp/
 3 ● ファッションコーディネートアプリ
 ● 1,600万ダウンロード突破、コーディネート投稿総数は1,300万件以上 (2022年6月末時点)
 ● ピックアップタグから最新のトレンドをチェック
 ● コーディネート着用アイテムを公式サイトで購入可能
 ● WEAR公認の人気ユーザーをWEARISTAと認定。モデル・タレント・デザ イナー・インフルエンサーといった各界著名人も参加


Slide 4

Slide 4 text

© ZOZO, Inc. 4 今日お話しすること


Slide 5

Slide 5 text

© ZOZO, Inc. 5 APIの公開
 ● WEARのコーディネートデータを広く活用し、他サービスを通じてファッションの悩みを解決
 ○ コーディネート検索APIを提供
 ■ Yahoo!天気
 ● 現在の天気からおすすめのコーディネート
 ■ Yahoo! BEAUTY
 ● 髪型に合っているコーディネート
 ■ ZOZOTOWN PayPayモール店
 ● 販売している服を使用したコーディネート
 背景
 ※ 実際のYahoo! 天気アプリでの表示

Slide 6

Slide 6 text

© ZOZO, Inc. 6 APIの公開
 ● 実現したいこと
 ○ 利用できるクライアントを限定
 ○ 利用できるエンドポイントをクライアントごとに限定
 ○ セキュアに提供
 どう公開するか?


Slide 7

Slide 7 text

© ZOZO, Inc. 7 APIの公開
 ● OAuth2.0
 ○ サードパーティーアプリケーションによるHTTPサービスへの限定的なアクセスを可能にする認可フレームワー ク
 ○ スコープによってリソースへのアクセスを制御
 ○ 安全
 
 どう公開するか?


Slide 8

Slide 8 text

© ZOZO, Inc. 8 アプリケーションの構成
 ● WEAR
 ○ API
 ■ WEARアプリ用既存API
 ○ 3rd Party API
 ■ 3rd Party用新規API
 ● リソースの取得、スコープの確認
 ● AuthZ Service
 ○ API
 ■ AccessTokenの発行、検証
 ■ 公開鍵の提供
 ○ Management Web
 ■ 開発者用管理画面
 ● クライアントIDの発行


Slide 9

Slide 9 text

© ZOZO, Inc. 9 スコープの設計
 ● 仕様
 ○ 大文字と小文字を区別しない
 ○ スペース区切りのリストで表現
 ○ 省略した場合無効とするかデフォルト値とする
 ○ https://www.rfc-editor.org/rfc/rfc6749#section-3.3
 ● 例
 ○ Twiiter
 ■ tweet.read
 ● TwitterのツイートをGETする系のAPIが使える
 とても自由度が高く、どう作るか自分たちで考える必要がある


Slide 10

Slide 10 text

© ZOZO, Inc. 10 スコープの事例
 ● スコープ例
 ○ repo
 ■ repo:status
 ■ repo:invite
 ○ write:packages
 ○ read:packages
 ○ admin:org
 ● コロンでネームスペースを区切ってうまく考えている印象
 ○ 権限:リソース、リソース指定だけで全権限
 ● スコープ指定なしでパブリックな情報へのアクセス権限付与
 GitHub OAuth Apps


Slide 11

Slide 11 text

© ZOZO, Inc. 11 スコープの事例
 ● スコープ例
 ○ https://www.googleapis.com/auth/youtube.readonly
 ■ YouTubeアカウントの表示
 ○ https://www.googleapis.com/auth/youtube.upload
 ■ YouTube動画のアップロード、管理
 ● URLの形式
 ○ text/plainでスコープ名がレスポンスされる
 ○ パスに権限が表現されている
 ○ 内部でこのURLにアクセスして動的になにかしら制御している?
 YouTube Data API


Slide 12

Slide 12 text

© ZOZO, Inc. 12 スコープの事例
 ● スコープ例
 ○ profile
 ○ profile%20openid%20email
 ● スペース区切りのリストで表現はされているが、特定の組み合わせのみサポート
 LINE 


Slide 13

Slide 13 text

© ZOZO, Inc. 13 スコープの事例
 ● スコープ例
 ○ tweet.read
 ○ tweet.write
 ○ users.read
 ○ follows.write
 ● GitHubと似ているドット区切りで指定
 ○ リソース.権限
 Twitter 


Slide 14

Slide 14 text

© ZOZO, Inc. 14 スコープの事例
 サービス
 スコープ例
 GitHub
 ● repo
 ○ repo:status
 ● write:packages
 ● admin:org
 YouTube
 ● https://www.googleapis.com/auth/youtube.readonly
 ● https://www.googleapis.com/auth/youtube.upload
 LINE
 ● profile
 ● profile%20openid%20email
 Twitter
 ● tweet.read
 ● users.read
 ● follows.write


Slide 15

Slide 15 text

© ZOZO, Inc. 15 スコープの設計
 ● リソースサーバが使用するフレームワークや提供するAPIによって変わりそう
 ○ 今回はRESTful APIへの認可
 ■ リソース単位で権限を付与
 ● RESTと相性がよく、明快
 ■ リソースに対するアクションで権限を分割
 ● リソースに対して何でもできるのは権限として大きすぎる


Slide 16

Slide 16 text

© ZOZO, Inc. 16 スコープの設計
 ● HTTPメソッドとリソースを組み合わせる
 ○ 権限
 ■ HTTPメソッド(GET、POST、PATCH)
 ○ リソース
 ■ パス
 ● 例
 ○ get:coordinates
 ○ post:coordinates
 RESTful APIとスコープ


Slide 17

Slide 17 text

© ZOZO, Inc. 17 スコープの設計
 ● Railsのコントローラは便利
 ○ action_name
 ■ メソッド名を取得可能
 ○ controller_name
 ■ コントローラ名を取得可能
 ● 例
 ○ create:coordinates
 ○ update:coordinates
 Ruby on Railsとスコープ


Slide 18

Slide 18 text

© ZOZO, Inc. 18 WEARで導入しているスコープ
 ● Ruby on Railsでエンドポイントごとにスコープを分割するのは簡単にできそう
 ○ 細かく分割しすぎるとスコープの管理コストがとても高い
 ○ 作成権限を付与して、更新権限がないというのはあまり考えられない
 ● 結論
 ○ read or write:controller_name
 ■ リソース名はcontroller_nameで取得しつつ、権限はもう少し大雑把にする
 ■ readとwriteで分割
 ● read
 ○ GET
 ● write
 ○ POST、PUT、PATCH、DELETE
 結局どうしたのか


Slide 19

Slide 19 text

© ZOZO, Inc. 19 スコープの検証
 def required_read_scope scope_name = "read:#{controller_name}" render_unauthorized unless current_access_token.scopes.include?(scope_name) end def required_write_scope scope_name = "write:#{controller_name}" render_unauthorized unless current_access_token.scopes.include?(scope_name) end 権限ごとにメソッドを実装


Slide 20

Slide 20 text

© ZOZO, Inc. 20 スコープの検証
 class CoordinatesController < ApplicationController before_action :required_read_scope, only: [:show] def show; end end before_actionで制御 


Slide 21

Slide 21 text

© ZOZO, Inc. 21 1st Partyでも利用したい
 ● ほぼほぼ全APIが利用可能
 ○ allというスコープを用意し、read、writeで制御しているスコープについて全権限付与
 def required_read_scope return if current_access_token.scopes.include?('all') scope_name = "read:#{controller_name}" render_unauthorized unless current_access_token.scopes.include?(scope_name) end def required_write_scope return if current_access_token.scopes.include?('all') scope_name = "write:#{controller_name}" render_unauthorized unless current_access_token.scopes.include?(scope_name) end

Slide 22

Slide 22 text

© ZOZO, Inc. 22 特定クライアント専用のAPIを提供したい
 ● 権限とリソースの組み合わせのスコープ
 ■ クライアント間でユニークなスコープではない
 ● 意図しないクライアントにも権限が付与されてしまう可能性
 
 
 ● zozotownなどのクライアント名をスコープとして追加
 ○ クライアント単位でユニークなスコープを作成
 ■ 特定のクライアントからのみ利用されることを保証


Slide 23

Slide 23 text

© ZOZO, Inc. 23 特定クライアント専用のAPIを提供したい
 ● クライアント名でスコープを作成
 ○ allを付与していても利用できなくすることが可能
 def required_specified_scope(custom_allow_scope) render_unauthorized unless (custom_allow_scope & current_access_token.scopes).present? end class CoordinatesController < ApplicationController before_action -> { required_specified_scope(‘zozotown’) }, only: [:show] def show; end end

Slide 24

Slide 24 text

© ZOZO, Inc. 24 実際に導入してみて
 ● controller_nameが同じになってしまい、意図せず権限を付与してしまうケース
 ○ 例:read:coordinates
 ■ GET v1/coordinates/:id(CoordinatesController#show)
 ● コーディネートの詳細
 ■ GET v1/companies/:id/coordinates(Companies::CoordinatesController#index)
 ● Companyのコーディネート一覧
 ○ 企業のコーディネート情報の権限は付与したくない場合の回避策
 ■ 新たな権限を設ける
 ● company:coordinates
 ■ スコープを意識したパスを考える
 ● read:company_coordinates
 ■ ネームスペースも含める
 ● read:companies::coordinates


Slide 25

Slide 25 text

© ZOZO, Inc. 25 実際に導入してみて
 ● スコープとAPIを同時に設計する必要がある
 ○ APIを実装したら半自動的にスコープ名も決定
 ■ 誰のためのどういうリソースなのかを考える必要があり、良い設計になりやすい
 ● ※APIを実装しようと思ったらすでに同名エンドポイントがあり、既存APIの処理内容に違和感があるとい うことが起こりにくくなりそう
 ● スコープ名を見ただけでどのエンドポイントが利用できるか影響範囲がわかりやすい


Slide 26

Slide 26 text

© ZOZO, Inc. 26 今後の課題
 1st Partyでの使用
 
 
● WEARのWEBサイトでも1st PatryとしてAPIを利用している
 ○ ログインしていない(アクセストークンが存在しない)ユーザーにもAPIを提供しなければならない
 
 
 
 
 ● 同じエンドポイントでもアクセストークンを検証する場合としない場合を制御する必要


Slide 27

Slide 27 text

© ZOZO, Inc. 27 今後の課題
 ● 各社制限のつけかたは十人十色
 ○ 全エンドポイント、エンドポイント単位、特定のグループ単位
 ● 一応RFCに仕様があるので従っておいたほうが良さそう
 ○ https://datatracker.ietf.org/doc/html/draft-polli-ratelimit-headers-01
 ○ レスポンスヘッダ
 ■ RateLimit-Limit: 単位時間内の割り当てられているリクエスト数
 ■ RateLimit-Remaining: 単位時間内に割り当てられている残りのリクエスト数
 ■ RateLimit-Reset: 割り当てがリセットされるまでの時間
 ○ リソースサーバでアプリケーションごとに実行回数をDBなどに保存してレスポンスするとか
 Rate Limit
 


Slide 28

Slide 28 text

© ZOZO, Inc. 28 まとめ
 ● Ruby on Railsで外部にAPIをOAuthで提供しました
 ○ スコープの設計が大切
 ■ controller_name、action_nameが便利
 ○ 良いAPIになりやすい
 ● まだまだやるべきことは残っている
 ● みなさんもAPIを公開していきましょう


Slide 29

Slide 29 text

No content