LastaFluteでアクセス権限管理

LastaFluteプロジェクトでアクセス権限管理をしてみます。
会員マスタに権限管理用のカラムを追加し、区分値とアノテーションを利用して判定する方法でやります。

開発環境:
LastaFlute(1.0.0)
MySQL(5.7)

広告

下準備

会員権限マスタ

会員権限区分値用のマスタを追加します。
マスタを用意せず、手書きで区分値を追加してもいいかと思います。

今回は、以下の3つの権限を作成しました。

会員権限コード(PK)
MEMBER_AUTHORITY_CODE
会員権限名称
MEMBER_AUTHORITY_NAME
説明
DESCRIPTION
CMN Common 一般
MNG Manager 管理者
SYS System manager システム管理者

会員マスタ

会員マスタに会員権限コードを追加し、会員権限マスタを外部キー定義します。

会員ID(PK)
MEMBER_ID
会員名称
MEMBER_NAME
会員アカウント
MEMBER_ACCOUNT
会員権限コード(FK)
MEMBER_AUTHORITY_CODE
1 一般会員 M1 CMN
2 システム管理者 M2 SYS

区分値(CDef)

作成した会員権限マスタを区分値で使えるようにします。

# classificationDefinitionMap
; MemberAuthority = list:{
    ; map:{
        ; topComment=会員権限; codeType=String
    }
    ; map:{
        ; table=MEMBER_AUTHORITY
        ; code=MEMBER_AUTHORITY_CODE; name=MEMBER_AUTHORITY_NAME
        ; comment=DESCRIPTION
    }
}

アノテーション

アクセス権限管理用のアノテーションを作成します。
※今回は、Actionクラスにアノテーションを付ける想定です。

// java
/** アクセス権限 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Accessible {
    public MemberAuthority[] auth();
}

実装

Mainという名前のアプリにアクセス権限を実装していきます。

UserBean

MainUserBeanに会員権限を追加します。

// MainUserBean
 
// メンバに会員権限を追加する
// ※コンストラクタでの設定と、getterも追加
protected final MemberAuthority memberAuthority;

Actionクラスにアノテーションを追加

今回は、アノテーションがあるActionのみアクセス権限管理の対象にするようにします。

画面A:アクセス権限管理対象外
画面B:管理者とシステム管理者のみアクセス可

/** 画面AのActionClass */
 
// アクセス権限管理対象外なので、アノテーションなし
 
public class AuthorityAAction extends MainBaseAction {
    @Execute
    public HtmlResponse index() {
        return asHtml(path_Authority_AuthorityAHtml);
    }
}
/** 画面BのActionClass */
 
// ManagerとSystemManagerのみアクセス可にするアノテーションを追加
@Accessible(auth = { MemberAuthority.Manager, MemberAuthority.SystemManager })
 
public class AuthorityBAction extends MainBaseAction {
    @Execute
    public HtmlResponse index() {
        return asHtml(path_Authority_AuthorityBHtml);
    }
}

アクセス権限判定処理

Actionに設定されたアノテーションを読み取り、アクセス権限を判定する処理を作成します。

MainLoginAssist クラスで、 checkPermission メソッドをオーバーライドします。

// java
// MainLoginAssist

@Override
protected void checkPermission(LoginHandlingResource resource) throws LoginRequiredException {
 
    // Actionクラスのアノテーション取得
    Accessible accessible = resource.getActionClass().getAnnotation(Accessible.class);
    if (accessible == null) {
        // Accessibleアノテーションがなければ、アクセス権限チェック対象外
        return;
    }
 
    // ログイン会員の会員権限を取得
    MainUserBean ub = getSavedUserBean().get();
    MemberAuthority memberAuth = ub.getMemberAuthority();
    for (MemberAuthority auth : accessible.auth()) {
        if (auth.equals(memberAuth)) {
            // ログイン会員の会員権限がアノテーションに定義してあればアクセス可
            return;
        }
    }

    // 上記処理で会員権限が該当しなかった場合、アクセス不可
    // LoginRequiredExceptionをスローします。(ログ出力内容の粒度はお好みで。)
    throw new LoginRequiredException(
        String.format("アクセス不可[%s, 権限:%s][会員ID:%d, 氏名:%s, 権限:%s]", resource.getActionClass().getSimpleName(),
            Arrays.asList(accessible.auth()), ub.getUserId(), ub.getMemberName(), ub.getMemberAuthority()));
}

動作確認

一般会員でログインし、画面Aを表示

表示されました。

一般会員でログインし、画面Bを表示。

アクセス権限がないので、マイページへ飛ばされました。

※以下のようにログが出力されます。

※抜粋

org.lastaflute.web.login.exception.LoginRequiredException: アクセス不可[AuthorityBAction, 権限:[MNG, SYS]][会員ID:1, 氏名:一般会員, 権限:CMN]

システム管理者でログインし、画面Aを表示

表示されました。

システム管理者でログインし、画面Bを表示

権限があるので表示されました。

最後に

今回はActionクラス単位で判定しましたが、作り方次第でメソッド単位での判定も可能です。
また、アノテーションを利用しなくてもクラス名とユーザーの権限で判定してしまう事も可能です。(良いか悪いかは…どうなんでしょう)
他にもシステム管理者は無条件でアクセス可にしたり。などなど。

要するに、プロジェクトに合わせた色々な実装方法があると思うので、この記事がひとつの参考になれば嬉しいです。

広告

シェアする

フォローする