Spring Securityのメソッド認可でちょっと複雑なロジックで認可したい場合、任意のbeanのメソッドを呼び出すことが出来ます。
ちなみにカスタム認証を正しく追加したい場合は PermissionEvaluator を実装するのが恐らく正当なアプローチです。
PermissionEvaluatorの実装についてはこちらの記事が分かりやすく詳しかったです。
拡張フレームワーク開発などで汎用的なEvaluatorを追加したい場合はこちらがよいでしょう。
https://www.codeflow.site/ja/article/spring-security-create-new-custom-security-expression
今回はもうちょっとお手軽な方法でも書けるよという手順です。
Controller側のPreAuthorize定義
@PreAuthorize("@customPreAuthorizer.belongGroup(#groupId, authentication.principal)")
@RequestMapping("/group/{groupId}/list")
public String list(Model model, @PathVariable("groupId") Long groupId) {
}
Bean定義
@Component
public class CustomPreAuthorizer {
public boolean belongGroup(Long groupId, UserDetails userDetails) {
// ここで独自認可を実装。実行を許可する場合にtrueを返す。
return true;
}
}
解説
PreAuthorizeのexpression内でBean名の先頭に@をつけることで、コンポーネント登録されたBeanを参照出来ます。
@customPreAuthorizer
認証ユーザのユーザ情報はauthentication.principal
で引数に渡すことが出来ます。
PreAuthorizeで引数に渡すのが記述として冗長であれば、メソッド内でSecurityContextを呼んでも同じものが取得できるので、メソッド内で取り出すことも可能です。
@Component
public class CustomPreAuthorizer {
public boolean belongGroup(Long groupId) {
var userDetails = (UserDetails)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return true;
}
}
あとはUserDetailsを拡張して必要な情報をログイン時に持たせておけば、拡張した独自認可を実装して提供できます。