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
fusagiko
September 29, 2020
Programming
1
590
ニコニコ漫画と認可
Gotanda.rb#46 "管理画面/権限"
https://gotanda-rb.connpass.com/event/187557/
にて発表した内容です。
fusagiko
September 29, 2020
Tweet
Share
Other Decks in Programming
See All in Programming
「今のプロジェクトいろいろ大変なんですよ、app/services とかもあって……」/After Kaigi on Rails 2024 LT Night
junk0612
5
2.1k
アジャイルを支えるテストアーキテクチャ設計/Test Architecting for Agile
goyoki
9
3.3k
Content Security Policy入門 セキュリティ設定と 違反レポートのはじめ方 / Introduction to Content Security Policy Getting Started with Security Configuration and Violation Reporting
uskey512
1
520
카카오페이는 어떻게 수천만 결제를 처리할까? 우아한 결제 분산락 노하우
kakao
PRO
0
110
役立つログに取り組もう
irof
28
9.6k
よくできたテンプレート言語として TypeScript + JSX を利用する試み / Using TypeScript + JSX outside of Web Frontend #TSKaigiKansai
izumin5210
6
1.7k
LLM生成文章の精度評価自動化とプロンプトチューニングの効率化について
layerx
PRO
2
190
ECS Service Connectのこれまでのアップデートと今後のRoadmapを見てみる
tkikuc
2
250
Less waste, more joy, and a lot more green: How Quarkus makes Java better
hollycummins
0
100
3 Effective Rules for Using Signals in Angular
manfredsteyer
PRO
0
100
Jakarta EE meets AI
ivargrimstad
0
580
最新TCAキャッチアップ
0si43
0
140
Featured
See All Featured
Being A Developer After 40
akosma
86
590k
Fantastic passwords and where to find them - at NoRuKo
philnash
50
2.9k
Testing 201, or: Great Expectations
jmmastey
38
7.1k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
27
840
Git: the NoSQL Database
bkeepers
PRO
427
64k
Measuring & Analyzing Core Web Vitals
bluesmoon
4
120
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
31
2.7k
How To Stay Up To Date on Web Technology
chriscoyier
788
250k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
665
120k
We Have a Design System, Now What?
morganepeng
50
7.2k
Build The Right Thing And Hit Your Dates
maggiecrowley
33
2.4k
A Tale of Four Properties
chriscoyier
156
23k
Transcript
ニコニコ漫画と認可 2020/9/29 株式会社トリスタ フサギコ(髙﨑 尚人)
自己紹介 • 名前:フサギコ • Twitter :fusagiko • GitHub :takayamaki •
本名 :髙﨑 尚人 • 主な分野:Ruby(Rails), Terraform(AWS) • 他に :TypeScript, React, Ansible • Ruby:2.1.2~ • 大学院生の時に修士論文用のシミュレータを Pure Rubyフルスクラッチで書いたのが最初 • 趣味:アイドルマスター • 全作品、それぞれ楽しんでるタイプ
自己紹介(OSS活動) • マストドン • 本家(tootsuite/mastodon)コントリビュータ • 2年弱PR送れてないけどまだcommit数37位らしい • imastodon.net構築、運用、管理人 •
アイドルマスターのファン向け非公式マストドン • 2017年4月開設 • アカウント数4817、アクティブ数500/週程度 • 本家に独自改造が入っている • 完全に袂を分かったわけではないのでVariety(変種)と自称 • 追従は遅れ気味…
自己紹介(仕事) • ~ 2016/3 工学院大学大学院 • 修士(工学) 修論:情報指向ネットワーク • 2016/4~2017/7
NHN テコラス株式会社 • 2017/8~2019/6 株式会社ドワンゴ • friends.nico • ドワンゴ公式マストドン (サービス終了) • N Air • ニコニコ生放送向け 配信ソフト • 2019/7~現在 株式会社トリスタ • 読書メーター • 読書愛好家コミュニティサイト • ニコニコ漫画 • UGC/PGC漫画連載プラットフォーム
自己紹介(仕事) • ~ 2016/3 工学院大学大学院 • 修士(工学) 修論:情報指向ネットワーク • 2016/4~2017/7
NHN テコラス株式会社 • 2017/8~2019/6 株式会社ドワンゴ • friends.nico • ドワンゴ公式マストドン (サービス終了) • N Air • ニコニコ生放送向け 配信ソフト • 2019/7~現在 株式会社トリスタ • 読書メーター • 読書愛好家コミュニティサイト • ニコニコ漫画 • UGC/PGC漫画連載プラットフォーム
ニコニコ漫画と認可 2020/9/29 株式会社トリスタ フサギコ(髙﨑 尚人)
ニコニコ漫画 ニコニコ漫画
ニコニコ漫画 UGC/PGC漫画連載 プラットフォーム
ニコニコ漫画 多くの編集部様から ご連載頂いています
ニコニコ漫画はRailsで… ニコニコ漫画は Railsで作られている…
ニコニコ漫画はRailsで… ニコニコ漫画は Railsで作られている…
ニコニコ漫画はRailsではない 現行はPHP かつ モノリシック
ニコニコ漫画はPHP 静画の派生として 漫画が始まってから10年超え 2010/8/27に特設ページ扱いで開始…らしい by Wikipedia
ニコニコ漫画はPHP コード構造が結構厳しい
ニコニコ漫画はPHP テストが 十分でない
Railsでリプレイスしよう ビジネスロジックを Rails APIサーバとして 切り出し・リプレイスしよう
Railsでリプレイスしよう 現行のPHPは Backends For Frontends的 立ち位置に寄せていく
Railsでリプレイスしよう そのRails APIサーバにおける 認可機構の話をします
その前に と、その前に
認証と認可 認証と認可 それぞれの意味について 念のため確認
認証と認可 認証 authentication 認可 authorization “それ”が誰であるかを 確かめること to prove that
something is real “それ”に許可を 与えること to give permission for something
このように 認可と認証は 異なる行為
認証と認可 認可 しない する 認 証 し な い 何もわからないし
何もさせない 誰であるかは 自己申告を信じ、 操作を許可する す る それが誰かわかるが、 何もさせない それが誰かを識別し、 誰であるかによって 操作を許可する
認可 と 認証が間違われるのは 全部TwitterのOAuthが悪い いわゆるログイン連携がしたいだけなら 認証(”それ”の識別)さえできれば良かったはずなのに
全部TwitterのOAuthが悪い 閑話休題
ニコニコ漫画における権限とは ニコニコ漫画で 権限管理が 最も必要な場所
ニコニコ漫画で権限管理が必要な場所 編集部様からの 作品原稿の納入 作品・各話のメタ情報編集 公開期間の設定 など
ニコニコ漫画で権限管理が必要な場所 他編集部の 公開前の作品が見えたり、 編集できたりしてはならない
他編集部の作品が弄れてはならない これを実現するために 権限に基づく認可を行う
Rubyにおける権限管理のgemの選択肢 Rubyにおける 権限管理のgemの選択肢
Rubyにおける権限管理のgem •CanCanCan •Pundit •Banken
CanCanCan • ユーザを中心に、何へどのアクションを認可するか DSL的に記述 • can 【アクション】, 【対象】, 【各種条件】 •
対象にはActive Record継承したClassも指定できる • クエリインターフェイスに統合した形で使えて便利 • Active Recordに関係ない対象はシンボルで表現 • can? 【アクション】, 【対象】で判定 • => Boolean • 対象がActive Recordモデルの場合 • Article.accessible_by(current_ability) とかできる
Pundit • 認可系gemとしてはおそらくもっとも有名か • モデルを中心に、誰にどのアクションを 認可するか記述 • ActiveRecordモデルに対する操作タイミングで認 可を行う •
複雑になってきたRailsアプリケーションではモ デルとコントローラが一対一ではなくなりがち • コントローラごとに認可条件を変えたい場合詰む
Banken • コントローラのアクションメソッドと認可条件 を紐づける • アクションを中心に、誰に許可するか記述 • コントローラのアクションメソッドと対応付ける ので対象リソースは自ずと導き出せるはず
認可系gemの概観 権限記述の中心 判定タイミング Pubdit モデル モデルへの操作 Banken アクション コントローラのアクション CanCanCan
ユーザ モデルへの操作 OR 任意タイミング
ニコニコ漫画は 権限判定に どのgemを使ったか
ニコニコ漫画は どれも採用しなかった
どの認可系gemも使わなかった • 現行PHPとDBを共有しながらの順次リプレイス • 現行が不完全なレベルベースの認可 • モデルと必要権限が一対一で対応しない • 特定カラムの更新だけ上位権限が要る場合がある •
アクションメソッドと必要権限も対応しない • 「このカラムの更新には上位権限が要る」といった知識を BFFに流出させてはならない • バルク(一括)操作がある • 唯一可能性があったのはCanCanCanだが… • どう考えても大規模になるのでメンテしづらそう • ユーザの権限情報のDB上の表現からCanCanCanの DSLに落とし込める確信が持てなかった
gemを使わない…というか使えない 前述の通り、 新ニコニコ漫画は 既にRails的でない部分がある
決めた方針 更なるRails的でない構造や 大きな変更が襲来しても 耐えられるようにしたい
そのために インターフェイスを決めて コードの独立性を保ち、 変更の影響範囲を狭める 後続処理と重複したSELECTが多くなるのは妥協、許容する
認可によって知りたいのは 誰が どのような操作を どれに対して行えるか
認可の最小限のインターフェイス authorize (主体, 操作, 対象) => boolean
認可の最小限のインターフェイス authorize (user_id, action, target_ids) => boolean
具体的利用例 エピソード無料公開期間の 作成を例として 処理を追いかける エピソード:第一話、第二話前半、単行本告知など ニコニコ漫画上での公開単位
具体例:無料公開期間を作成するとき Api::V1::FreeViewingTermsController#create
具体例:無料公開期間を作成するとき ざっくりとした各処理の区分 バリデーション 認可 DB書き込み ビューモデル & ビュー
具体例:無料公開期間を作成するとき ここで認可部を呼んでいる
認可部のエントリポイント authorize!がauthorizeを呼ぶ
認可部のエントリポイント authorize!がauthorizeを呼ぶ
認可部のエントリポイント target_idsが単体な場合もKernel.#Arrayでカバー
認可部のエントリポイント targetによって各Authorizerに分岐
認可部のエントリポイント targetの種類はactionから導ける
認可部のエントリポイント 無料公開期間のAuthorizerへ
無料公開期間のAuthorizer 各Authorizerの中でまたactionで分岐
無料公開期間のAuthorizer 各Authorizerの中でまたactionで分岐
無料公開期間のcreate権限判定
無料公開期間のcreate権限判定 まずEpisodeを引く
無料公開期間のcreate権限判定 Episodeを不足なく 取得できたか
無料公開期間のcreate権限判定 公式連載でない作品の エピソードが混ざって いないか
無料公開期間のcreate権限判定 権限付与の単位は作品なので エピソードが属するComicを Comic::OfficialComicとして引きなおす (ここ微妙ポイント)
無料公開期間のcreate権限判定 ユーザの権限情報を DBから引いてくる
無料公開期間のcreate権限判定 全作品対象の権限が あったら早期return
無料公開期間のcreate権限判定 権限の付与範囲ごとに 認可された作品を Arrayから取り除いていく
無料公開期間のcreate権限判定 最終的に空ならば 全て認可されている
Authorizer.authorize!に戻ってきて 認可されたならばraiseされないので後続処理へ
以上が最も基本的な 認可の仕組み
ところでDRYにはしたい 他のアクションと 判定基準が同じ場合も 当然ある
権限判定の移譲 アクションだけ差し替えて 移譲先Authorizerのauthorizeメソッドを呼ぶ
ここで疑問 Actionごとに渡すべき IDの種類が違うのでは?
Actionごとに渡すべきIDの種類が違う Actionごとに渡すべきIDの種類が違うのでは?
Actionごとに渡すべきIDの種類が違う Actionごとに渡すべきIDの種類が違うのでは? 無料公開期間は エピソードに対して 作るのでepisode_id
Actionごとに渡すべきIDの種類が違う Actionごとに渡すべきIDの種類が違うのでは? 無料公開期間は エピソードに対して 作るのでepisode_id 無料公開期間を消すときは free_viewing_term_id
Actionごとに渡すべきIDの種類が違う Actionごとに渡すべきIDの種類が違うのでは? 無料公開期間は エピソードに対して 作るのでepisode_id 無料公開期間を消すときは free_viewing_term_id episode_id free_viewing_term_id free_viewing_term_id
IDの種類が混ざらないのはなぜか 様々な種類のIDをどうやって 区別しているのか
IDの種類を判別するしくみ • 各アクションのinterface class的なものを作る • 引数になりうるIDをインスタンス変数として持つ • attr_readerで読めるようにする • ID種別が非互換ならNo
such methodで死ぬ • つまりダックタイピング
引数になるID種別が移譲先と違う場合 移譲先のID種別に詰め替える eql?とhashを実装すると uniqできる
未実装な機能 • ユーザがINDEXできるものだけINDEXする機能 • 現状、絞り込みのクエリパラメータが必ず付いて いるのでそれを起点に許可、拒否が決定できる • 現状、権限を持っている対象だけを絞ってINDEX したいという要求がまだないので困っていない •
それが来たときにどう実現するかは要検討 • モデルのpublicメソッドにする? • どうにかしてActiveRecordスコープを作る? • CanCanCanのaccessible_byが参考になりそうか?
まとめ • ニコニコ漫画の現行はモノリシックなPHP • ビジネスロジックのRails APIモードへのリプレイスが進行中 • 現行PHPはBFF的立ち位置に寄せていく • 認証と認可の定義
• ニコニコ漫画では公式連載の原稿納入、公開期間設定などが認可の 対象 • Rubyの権限管理系gem 3種概観 • 検討した結果、いずれも使わなかった • ニコニコ漫画の認可機構はどのように実装をしているか • 無料公開期間の作成を例とした具体的流れ • 判定基準が同じアクションは判定を移譲している • 多数あるIDの種類をどうやって区別しているか • 今後の課題 • ユーザがINDEXできるものだけINDEXする機能
付録 ユーザの権限情報のDB上の表現 Watch: 作品・エピソードのINDEXとSHOW, 公開期間のINDEX Publish: 公開期間のCREATE, UPDATE, DESTROY Edit:
作品・エピソードのUPDATE, DESTROY