asp.net MVC 既存の認証にロール(権限)を追加する

関西は絶賛梅雨に突入しています。蒸し暑いです。

今回は既存の認証処理をしているところに追加でロールの概念を追加します。

現状、DBテーブルからユーザ情報引っ張ってきて、単一のアカウントに対し、ログインを許可しています。普通です。

だがしかし!追加でロール(権限)をユーザに付与して機能を制限したい、となったら…?

  • 既存では、asp.net MVC、Identityで認証処理をしている。(新規プロジェクトで勝手にできるアレ)
  • 独自のユーザテーブルを参照するようにカスタマイズ済み。
  • ログイン処理もカスタマイズ。とりあえずユーザ用のモデルを作ってセッション管理している。
  • 上記に加え、コントローラ単位でロールごとに制限を設けたい。と、追加要望。

Identityの情報があまりなくて、とにかくこのあたりちょっと手間がかかったので今更手を加えたくないということです。

次項、カスタムフィルタを作って解決です。

カスタム属性フィルタリングでFA

Identityでコントローラでの制御で、[Authorize]属性があるので、

これと似たようなことを後付けでしたいな、と、自前で属性作ってやればいいのでは?

まあ、そういう経緯で試しにやってみると簡単でした。

[vs2015]プロジェクトの上で右クリック→[追加]→クラスを追加する

    /// <summary>
    /// ユーザ権限によってアクセスを制御するフィルタを定義
    /// ※実装例ですので適当な部分あります。
    /// </summary>
    public class ApplicationRoleFilterAttribute : FilterAttribute, IAuthorizationFilter
    {
        // ロールの比較対象値
        public MyAccessRole role_value { get; set; }
        
        // フィルタ実装
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            var session = filterContext.HttpContext.Session;
            // ログインユーザ情報を取得
            var user_info = session["user"] as UserModel;
            // 管理者はOK
            if (user_info.role == 99)
            {
                return;
            }
            // 権限判定
            if ((byte)role_value > user_info.role)
            {
                // メニューへリダイレクト。
                filterContext.Result = new RedirectResult("/Menu/index/");
                return;
            }
        }
    }

判定のため列挙型も用意

  /// <summary>
    /// ログインユーザロール判定用列挙型
    /// </summary>
    public enum MyAccessRole : byte
    {
        Admin = 99,     // 管理者
        Reporter = 2,   // 報告者
        Economy = 1     // 閲覧のみ(DL)
    }

なんかクラス名に命名規則あるのかな?と思いましたが任意の命名でいいみたいです。(…Attributeは無視される?不明)

「IAuthorizationFilter」というインターフェースを実装します。

ほかにもいろいろありますが認証前のフィルタリングの呼び出しになります。

使用例

コントローラ単位なのでクラスに対し属性を付与します。

  [Authorize]
    [ApplicationRoleFilter(role_value = MyAccessRole.Reporter)]
    public class SampleController : Controller
    {

  ・・・・・・

[Authorize]は、Identityの認証属性です。

それプラス、先ほどの「ApplicationRoleFilter」を追加します。

プロパティの「role_value」に必要な権限を指定しています。

以上!終わり!なかなかうまくいった。

まとめ

今回はイメージ通りにうまくいきました。

cakephpのフィルターみたいに、コントローラ共通とか任意指定できるとかやりたいと思っていた処理がカスタム属性でできますね。これは便利ですね。ただフレームワークにあってもいいと思いますがないものねだりですね。