はじめに
余談からになりますが、「達人に学ぶDB設計」を再読しており、実装が遅れました。
改善としては、既読管理テーブルと参加者テーブルはひとつにできそうだなと思いました。
また、パフォーマンスというのも全ての実装ができてからの話と思うので、あまり深追いはせず、インデックスについては考えるのみ留めました。
今のところ、インデックスを付与したいのは、ログ取得テーブルです。日時検索、チャット内容の曖昧検索だとカーディナリティが高くなりそうと考えました。
しかし、奥が深い。理解が及ばない範囲については、試験的に動かして過ちが判明すると思うので、楽しみにしておきたいです。
さて、今回のテーマの前に最終目標から。
最終目標は、Webセキュリティ式によって、各部屋の認可処理をSpring Security側で行う事です。
そこで今回は、二年前にも少し触れたRoleから認可の流れを、BaeldungとSpringドキュメントを元に触れていきます。前回と違うのは権限とロールの階層です。
目標は、ロールと権限それぞれで特定のURLやオブジェクトへのアクセスを制御する事です。
抜けている知識や疑問点についても逐一、記載します。
昨日の就職活動の面接にて、JPAに頼らずSQLに触れるという事は大事とアドバイス頂いて、ちょうど旬な話題でした。(全然関係ない話になりますが、雇用形態によって就職・転職活動と表現が変わるのかなと悩んで、就職活動と表記していましたが、普通に転職活動でした。)
設計
ADMIN:Delete
USER:Read,Write
とします。権限は今後の実装で、新しいロールと共に必要になるため動作確認兼ねて実装予定。その際に、USERのReadも修正予定。
内容
今回はこちらを参考に進める。
Spring Security - Roles and Privileges | Baeldung
ポイント
・ユーザー、ロール、権限の関係はそれぞれ多対多で構成する。
・ContextRefreshedEventを用いてApplicationContextが初期化、リフレッシュされた時にロールと権限をセットアップする。...※1
・UserDetailsService内でロールと権限を付与する。GrantedAuthorityに含める。...※2
・役割に階層を持たせる事で、複数の役割を付与しないで済む。RoleHierarchyで設定。...※3
テーブル設計
>As we can see, we're considering both the User <-> Role as well as the Role <-> Privilege relationships to be many-to-many bidirectional
多対多で双方向
spring-data-jpaを使った場合の単方向と双方向について - だらだらと思いついたこととか書くブログ
mappedByでも良さそう...
@JoinTable自体はJoinColumnsとInverseJoinColumnsでリレーションが一目でわかるので、User <-> Role <-> Privilege の多対多がわかりやすいというのがあるのだろうか(未解決)
※1 ContextRefreshedEventを使用した処理について
イベントについて理解が曖昧になっているため再度整理。
①ApplicationContextとは?
Spring Framework コアテクノロジー - リファレンス
SpringのDIコンテナの動作イメージ(雰囲気)を掴もう - Qiita
DIについては上記参照。
DIコンテナ を構成するのが、BeanFactoryとApplicationContext。ApplicationContextは構成フレームワークと基本機能の提供するBeanFactoryの上位互換。
Beanのインスタンス化、構成、組み立てをする。
②ここでのイベント処理とは?
ApplicationContextのイベント処理は、ApplicationListenerでApplicationEventを登録。
今回は、ContextRefreshedEventが登録されている。
これが、ApplicationContextが初期化された際に発行できる仕組み。
あとは、onApplicationEventにてイベント処理をするという流れ。
※2 GrantedAuthorityの仕組みついて(※3の認可処理メモ参照)
RoleVoterについてSpring Security Referenceにて
>ConfigAttribute
が ROLE_
プレフィックスで始まるかどうかを投票します。ROLE_
プレフィックスで始まる 1 つ以上の ConfigAttributes
と正確に等しい String
表現(getAuthority()
メソッドから)を返す GrantedAuthority
がある場合、アクセスを許可することに投票します。ROLE_
で始まる ConfigAttribute
の完全一致がない場合、RoleVoter
はアクセスを拒否するために投票します。ConfigAttribute
が ROLE_
で始まらない場合、投票者は棄権します。
...ConfigAttributeって何だろう
Spring Security 使い方メモ 認証・認可 - Qiita
ConfigAttribute (spring-security-docs API) - Javadoc
セキュリティ設定が入っていて、これと照らし合わせて認可するとの事。
権限についてはどうかというと
上記Qiita記事にて、WebExpressionVoterについての記載が...
現在はWebExpressionAuthorizationManagerで、指定された式を評価し認可するとの事
その式がhasAuthority()。
つまり、ロールも権限もそれぞれのVoterがチェックするのでまとめて入れているという事がわかった。AccessDecisionManagerに引き渡すためにGrantedAuthorityを使用すると。
※3 設定したロールの階層について(未解決)
認可アーキテクチャ :: Spring Security - リファレンス
この階層についてはSpring Web Expressionsに含める必要があるので、WebSecurityExpressionHandlerにRoleHierarchyのインスタンスを追加する。
WebSecurityExpressionHandlerはWebSecurityConfigurationに含まれる。
WebSecurityConfigurationはFilterChainProxyを作成するWebSecurityをカスタマイズするためのクラスだから、そのままの意味で設定自体に組み込む(自由に定義できる)という解釈でいいのだろうか...(Spring Web Expressionsが検索してもでてこない....)
--余談--
ロールに関わる認可について整理
AccessDecisionManagerにてGrantedAuthorityを読み取るが、この内部のAccessDecisionManager→AccessDecisionVoter→RoleVoterで認可を行う。
上記を呼び出すAuthorizationManagerはRoleHierarchyVoterを呼び出す。
Collection<? extends GrantedAuthority>について
[Java] ジェネリクス 境界ワイルドカード型のご紹介 - Qiita
境界ワイルドカードにすると、OAuth2UserAuthorityにも使えて便利。
OAuth2...試してみたい。
感想
ドキュメントに書かれているので、何が何を呼び出して認可しているというのを学習するには良い機会になりました。
今回の最終目標にも十分近づけたのではないかと思います。
ただ、もっと深掘りできる部分は多々あったので、時間の確保ができ次第、学習の修正はしていきたいです。
イベント処理を辿るとDIの話に、DIの話からBeanのスコープ等もっと深みのある話に...時間が足りなさ過ぎて触れられず、以前にカスタムイベント実装した時の復習みたいになってしまったのが悔しい。
SpringのDIコンテナの動作イメージ(雰囲気)を掴もう - Qiita
>「Beanのスコープ」「Beanの優先順位」「初期化処理/破棄処理」「AOP(Proxy)」「プロファイル」などの仕組みに関する知識
設計の分野になるのだろうか、到達点としては、すごく憧れがある。そして、とにかく深い。
このような分野をチームでコミュニケーション取って、理解し実装していく過程を想像すると、とても楽しいだろうなと思いました。
全然関係のない話
気付くと年末です。
2021年、2022年はムエタイのアマチュア大会の出場や就業先を通したコンクールの参加で、人間的に成長できた年でありました。
2023年は、どのような形であれ、技術と成果に重きを置いた年にしたいと思います。