Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ニコニコ漫画と認可

fusagiko
September 29, 2020

 ニコニコ漫画と認可

Gotanda.rb#46 "管理画面/権限" https://gotanda-rb.connpass.com/event/187557/ にて発表した内容です。

fusagiko

September 29, 2020
Tweet

Other Decks in Programming

Transcript

  1. ニコニコ漫画と認可
    2020/9/29
    株式会社トリスタ
    フサギコ(髙﨑 尚人)

    View Slide

  2. 自己紹介
    • 名前:フサギコ
    • Twitter :fusagiko
    • GitHub :takayamaki
    • 本名 :髙﨑 尚人
    • 主な分野:Ruby(Rails), Terraform(AWS)
    • 他に :TypeScript, React, Ansible
    • Ruby:2.1.2~
    • 大学院生の時に修士論文用のシミュレータを
    Pure Rubyフルスクラッチで書いたのが最初
    • 趣味:アイドルマスター
    • 全作品、それぞれ楽しんでるタイプ

    View Slide

  3. 自己紹介(OSS活動)
    • マストドン
    • 本家(tootsuite/mastodon)コントリビュータ
    • 2年弱PR送れてないけどまだcommit数37位らしい
    • imastodon.net構築、運用、管理人
    • アイドルマスターのファン向け非公式マストドン
    • 2017年4月開設
    • アカウント数4817、アクティブ数500/週程度
    • 本家に独自改造が入っている
    • 完全に袂を分かったわけではないのでVariety(変種)と自称
    • 追従は遅れ気味…

    View Slide

  4. 自己紹介(仕事)
    • ~ 2016/3 工学院大学大学院
    • 修士(工学) 修論:情報指向ネットワーク
    • 2016/4~2017/7 NHN テコラス株式会社
    • 2017/8~2019/6 株式会社ドワンゴ
    • friends.nico
    • ドワンゴ公式マストドン (サービス終了)
    • N Air
    • ニコニコ生放送向け 配信ソフト
    • 2019/7~現在 株式会社トリスタ
    • 読書メーター
    • 読書愛好家コミュニティサイト
    • ニコニコ漫画
    • UGC/PGC漫画連載プラットフォーム

    View Slide

  5. 自己紹介(仕事)
    • ~ 2016/3 工学院大学大学院
    • 修士(工学) 修論:情報指向ネットワーク
    • 2016/4~2017/7 NHN テコラス株式会社
    • 2017/8~2019/6 株式会社ドワンゴ
    • friends.nico
    • ドワンゴ公式マストドン (サービス終了)
    • N Air
    • ニコニコ生放送向け 配信ソフト
    • 2019/7~現在 株式会社トリスタ
    • 読書メーター
    • 読書愛好家コミュニティサイト
    • ニコニコ漫画
    • UGC/PGC漫画連載プラットフォーム

    View Slide

  6. ニコニコ漫画と認可
    2020/9/29
    株式会社トリスタ
    フサギコ(髙﨑 尚人)

    View Slide

  7. ニコニコ漫画
    ニコニコ漫画

    View Slide

  8. ニコニコ漫画
    UGC/PGC漫画連載
    プラットフォーム

    View Slide

  9. ニコニコ漫画
    多くの編集部様から
    ご連載頂いています

    View Slide

  10. ニコニコ漫画はRailsで…
    ニコニコ漫画は
    Railsで作られている…

    View Slide

  11. ニコニコ漫画はRailsで…
    ニコニコ漫画は
    Railsで作られている…

    View Slide

  12. ニコニコ漫画はRailsではない
    現行はPHP
    かつ
    モノリシック

    View Slide

  13. ニコニコ漫画はPHP
    静画の派生として
    漫画が始まってから10年超え
    2010/8/27に特設ページ扱いで開始…らしい
    by Wikipedia

    View Slide

  14. ニコニコ漫画はPHP
    コード構造が結構厳しい

    View Slide

  15. ニコニコ漫画はPHP
    テストが
    十分でない

    View Slide

  16. Railsでリプレイスしよう
    ビジネスロジックを
    Rails APIサーバとして
    切り出し・リプレイスしよう

    View Slide

  17. Railsでリプレイスしよう
    現行のPHPは
    Backends For Frontends的
    立ち位置に寄せていく

    View Slide

  18. Railsでリプレイスしよう
    そのRails APIサーバにおける
    認可機構の話をします

    View Slide

  19. その前に
    と、その前に

    View Slide

  20. 認証と認可
    認証と認可
    それぞれの意味について
    念のため確認

    View Slide

  21. 認証と認可
    認証 authentication 認可 authorization
    “それ”が誰であるかを
    確かめること
    to prove that something
    is real
    “それ”に許可を
    与えること
    to give permission for
    something

    View Slide

  22. このように
    認可と認証は
    異なる行為

    View Slide

  23. 認証と認可
    認可
    しない する





    何もわからないし
    何もさせない
    誰であるかは
    自己申告を信じ、
    操作を許可する


    それが誰かわかるが、
    何もさせない
    それが誰かを識別し、
    誰であるかによって
    操作を許可する

    View Slide

  24. 認可 と 認証が間違われるのは
    全部TwitterのOAuthが悪い
    いわゆるログイン連携がしたいだけなら
    認証(”それ”の識別)さえできれば良かったはずなのに

    View Slide

  25. 全部TwitterのOAuthが悪い
    閑話休題

    View Slide

  26. ニコニコ漫画における権限とは
    ニコニコ漫画で
    権限管理が
    最も必要な場所

    View Slide

  27. ニコニコ漫画で権限管理が必要な場所
    編集部様からの
    作品原稿の納入
    作品・各話のメタ情報編集
    公開期間の設定
    など

    View Slide

  28. ニコニコ漫画で権限管理が必要な場所
    他編集部の
    公開前の作品が見えたり、
    編集できたりしてはならない

    View Slide

  29. 他編集部の作品が弄れてはならない
    これを実現するために
    権限に基づく認可を行う

    View Slide

  30. Rubyにおける権限管理のgemの選択肢
    Rubyにおける
    権限管理のgemの選択肢

    View Slide

  31. Rubyにおける権限管理のgem
    •CanCanCan
    •Pundit
    •Banken

    View Slide

  32. CanCanCan
    • ユーザを中心に、何へどのアクションを認可するか
    DSL的に記述
    • can 【アクション】, 【対象】, 【各種条件】
    • 対象にはActive Record継承したClassも指定できる
    • クエリインターフェイスに統合した形で使えて便利
    • Active Recordに関係ない対象はシンボルで表現
    • can? 【アクション】, 【対象】で判定
    • => Boolean
    • 対象がActive Recordモデルの場合
    • Article.accessible_by(current_ability) とかできる

    View Slide

  33. Pundit
    • 認可系gemとしてはおそらくもっとも有名か
    • モデルを中心に、誰にどのアクションを
    認可するか記述
    • ActiveRecordモデルに対する操作タイミングで認
    可を行う
    • 複雑になってきたRailsアプリケーションではモ
    デルとコントローラが一対一ではなくなりがち
    • コントローラごとに認可条件を変えたい場合詰む

    View Slide

  34. Banken
    • コントローラのアクションメソッドと認可条件
    を紐づける
    • アクションを中心に、誰に許可するか記述
    • コントローラのアクションメソッドと対応付ける
    ので対象リソースは自ずと導き出せるはず

    View Slide

  35. 認可系gemの概観
    権限記述の中心 判定タイミング
    Pubdit モデル モデルへの操作
    Banken アクション コントローラのアクション
    CanCanCan ユーザ
    モデルへの操作
    OR
    任意タイミング

    View Slide

  36. ニコニコ漫画は
    権限判定に
    どのgemを使ったか

    View Slide

  37. ニコニコ漫画は
    どれも採用しなかった

    View Slide

  38. どの認可系gemも使わなかった
    • 現行PHPとDBを共有しながらの順次リプレイス
    • 現行が不完全なレベルベースの認可
    • モデルと必要権限が一対一で対応しない
    • 特定カラムの更新だけ上位権限が要る場合がある
    • アクションメソッドと必要権限も対応しない
    • 「このカラムの更新には上位権限が要る」といった知識を
    BFFに流出させてはならない
    • バルク(一括)操作がある
    • 唯一可能性があったのはCanCanCanだが…
    • どう考えても大規模になるのでメンテしづらそう
    • ユーザの権限情報のDB上の表現からCanCanCanの
    DSLに落とし込める確信が持てなかった

    View Slide

  39. gemを使わない…というか使えない
    前述の通り、
    新ニコニコ漫画は
    既にRails的でない部分がある

    View Slide

  40. 決めた方針
    更なるRails的でない構造や
    大きな変更が襲来しても
    耐えられるようにしたい

    View Slide

  41. そのために
    インターフェイスを決めて
    コードの独立性を保ち、
    変更の影響範囲を狭める
    後続処理と重複したSELECTが多くなるのは妥協、許容する

    View Slide

  42. 認可によって知りたいのは
    誰が
    どのような操作を
    どれに対して行えるか

    View Slide

  43. 認可の最小限のインターフェイス
    authorize
    (主体, 操作, 対象)
    => boolean

    View Slide

  44. 認可の最小限のインターフェイス
    authorize
    (user_id, action, target_ids)
    => boolean

    View Slide

  45. 具体的利用例
    エピソード無料公開期間の
    作成を例として
    処理を追いかける
    エピソード:第一話、第二話前半、単行本告知など
    ニコニコ漫画上での公開単位

    View Slide

  46. 具体例:無料公開期間を作成するとき
    Api::V1::FreeViewingTermsController#create

    View Slide

  47. 具体例:無料公開期間を作成するとき
    ざっくりとした各処理の区分
    バリデーション
    認可
    DB書き込み
    ビューモデル & ビュー

    View Slide

  48. 具体例:無料公開期間を作成するとき
    ここで認可部を呼んでいる

    View Slide

  49. 認可部のエントリポイント
    authorize!がauthorizeを呼ぶ

    View Slide

  50. 認可部のエントリポイント
    authorize!がauthorizeを呼ぶ

    View Slide

  51. 認可部のエントリポイント
    target_idsが単体な場合もKernel.#Arrayでカバー

    View Slide

  52. 認可部のエントリポイント
    targetによって各Authorizerに分岐

    View Slide

  53. 認可部のエントリポイント
    targetの種類はactionから導ける

    View Slide

  54. 認可部のエントリポイント
    無料公開期間のAuthorizerへ

    View Slide

  55. 無料公開期間のAuthorizer
    各Authorizerの中でまたactionで分岐

    View Slide

  56. 無料公開期間のAuthorizer
    各Authorizerの中でまたactionで分岐

    View Slide

  57. 無料公開期間のcreate権限判定

    View Slide

  58. 無料公開期間のcreate権限判定
    まずEpisodeを引く

    View Slide

  59. 無料公開期間のcreate権限判定
    Episodeを不足なく
    取得できたか

    View Slide

  60. 無料公開期間のcreate権限判定
    公式連載でない作品の
    エピソードが混ざって
    いないか

    View Slide

  61. 無料公開期間のcreate権限判定
    権限付与の単位は作品なので
    エピソードが属するComicを
    Comic::OfficialComicとして引きなおす
    (ここ微妙ポイント)

    View Slide

  62. 無料公開期間のcreate権限判定
    ユーザの権限情報を
    DBから引いてくる

    View Slide

  63. 無料公開期間のcreate権限判定
    全作品対象の権限が
    あったら早期return

    View Slide

  64. 無料公開期間のcreate権限判定
    権限の付与範囲ごとに
    認可された作品を
    Arrayから取り除いていく

    View Slide

  65. 無料公開期間のcreate権限判定
    最終的に空ならば
    全て認可されている

    View Slide

  66. Authorizer.authorize!に戻ってきて
    認可されたならばraiseされないので後続処理へ

    View Slide

  67. 以上が最も基本的な
    認可の仕組み

    View Slide

  68. ところでDRYにはしたい
    他のアクションと
    判定基準が同じ場合も
    当然ある

    View Slide

  69. 権限判定の移譲
    アクションだけ差し替えて
    移譲先Authorizerのauthorizeメソッドを呼ぶ

    View Slide

  70. ここで疑問
    Actionごとに渡すべき
    IDの種類が違うのでは?

    View Slide

  71. Actionごとに渡すべきIDの種類が違う
    Actionごとに渡すべきIDの種類が違うのでは?

    View Slide

  72. Actionごとに渡すべきIDの種類が違う
    Actionごとに渡すべきIDの種類が違うのでは?
    無料公開期間は
    エピソードに対して
    作るのでepisode_id

    View Slide

  73. Actionごとに渡すべきIDの種類が違う
    Actionごとに渡すべきIDの種類が違うのでは?
    無料公開期間は
    エピソードに対して
    作るのでepisode_id
    無料公開期間を消すときは
    free_viewing_term_id

    View Slide

  74. Actionごとに渡すべきIDの種類が違う
    Actionごとに渡すべきIDの種類が違うのでは?
    無料公開期間は
    エピソードに対して
    作るのでepisode_id
    無料公開期間を消すときは
    free_viewing_term_id
    episode_id
    free_viewing_term_id
    free_viewing_term_id

    View Slide

  75. IDの種類が混ざらないのはなぜか
    様々な種類のIDをどうやって
    区別しているのか

    View Slide

  76. IDの種類を判別するしくみ
    • 各アクションのinterface class的なものを作る
    • 引数になりうるIDをインスタンス変数として持つ
    • attr_readerで読めるようにする
    • ID種別が非互換ならNo such methodで死ぬ
    • つまりダックタイピング

    View Slide

  77. 引数になるID種別が移譲先と違う場合
    移譲先のID種別に詰め替える
    eql?とhashを実装すると
    uniqできる

    View Slide

  78. 未実装な機能
    • ユーザがINDEXできるものだけINDEXする機能
    • 現状、絞り込みのクエリパラメータが必ず付いて
    いるのでそれを起点に許可、拒否が決定できる
    • 現状、権限を持っている対象だけを絞ってINDEX
    したいという要求がまだないので困っていない
    • それが来たときにどう実現するかは要検討
    • モデルのpublicメソッドにする?
    • どうにかしてActiveRecordスコープを作る?
    • CanCanCanのaccessible_byが参考になりそうか?

    View Slide

  79. まとめ
    • ニコニコ漫画の現行はモノリシックなPHP
    • ビジネスロジックのRails APIモードへのリプレイスが進行中
    • 現行PHPはBFF的立ち位置に寄せていく
    • 認証と認可の定義
    • ニコニコ漫画では公式連載の原稿納入、公開期間設定などが認可の
    対象
    • Rubyの権限管理系gem 3種概観
    • 検討した結果、いずれも使わなかった
    • ニコニコ漫画の認可機構はどのように実装をしているか
    • 無料公開期間の作成を例とした具体的流れ
    • 判定基準が同じアクションは判定を移譲している
    • 多数あるIDの種類をどうやって区別しているか
    • 今後の課題
    • ユーザがINDEXできるものだけINDEXする機能

    View Slide

  80. 付録 ユーザの権限情報のDB上の表現
    Watch: 作品・エピソードのINDEXとSHOW, 公開期間のINDEX
    Publish: 公開期間のCREATE, UPDATE, DESTROY
    Edit: 作品・エピソードのUPDATE, DESTROY

    View Slide