web-dev-qa-db-ja.com

MVCインターセプターvsスプリングセキュリティフィルターvs何か他のもの...?

WebアプリケーションにSpringSecurityでSpring-MVCを使用しています。ユーザー登録ページとプライベートユーザーパネルが含まれています。現在、次のURLパターンで設定しています。

  • _whatever/myapp/login_ユーザーログイン
  • _whatever/myapp/register?step=1_登録を開始
  • _whatever/myapp/account/**_プライベートエリアビュー(ページ)
  • _whatever/myapp/pending_ビューは登録後のプロセスの完了中に表示されます
  • _whatever/myapp/blocked_アカウントのブロックされたビュー
  • _whatever/myapp/register/retry_登録に失敗した場合は、再試行を許可します

基本的に、以下のこれらのURLにはユーザー認証が必要です。つまり、ログインが必要です。

  • _whatever/myapp/account/**_(プライベートエリアページ)
  • _whatever/myapp/pending_(このページには/ account/homeにリダイレクトするように設定されたタイマーがあります)
  • _whatever/myapp/register/retry_

これは、Springセキュリティを使用して実現するのは非常に簡単です。ただし、Springセキュリティによるユーザー認証に関係なく、ユーザーの現在のアカウントステータス(DBに保存されている)に応じて、プライベートエリアページにアクセスできるかどうかが決まります。

具体的には、ユーザーがプライベートエリア(_/account/**_)内の何かにアクセスしようとすると、ステータスに応じて適切なビュー(適切なページにリダイレクト)が表示されます。私はこれらのステータスを定義しています:

  • suspended-保留中のビューに関連します
  • enabled-フルアクセスを許可する
  • disabled-ここでは関係ありません
  • _retry_allowed_-再試行ビューに関連します
  • blocked-アカウントに関連-ブロックされたビュー

現在、MVCインターセプターを_/account/**_に設定して、ユーザーステータスを確認し、適切なページにリダイレクトしていますが、奇妙なことに直面しているため、これは実際には理想的または適切なソリューションではないように感じます。複数のコントローラー呼び出しのような動作...また、preHandle()メソッド内でtrue/falseをいつ返すかはよくわかりません。インターセプターからのコードスニペットは次のとおりです。

_@Override
public boolean preHandle(
    HttpServletRequest request, 
    HttpServletResponse response,
    Object arg2) 
    throws Exception {

IPanelUser pUser =  (IPanelUser) SecurityContextHolder.getContext()
        .getAuthentication().getPrincipal();

// check principal first and then load from DB
// "suspended" is initial status upon registration
if(pUser.getCustomer().getStatus() == CustomerStatus.Suspended.getCode()) {

    // if suspended, load from DB and update status
    Customer customer = this.customerService.getUserByUsername(pUser.getUsername());
    if(customer != null)
        pUser.getCustomer().setStatus(customer.getStatus());

    // still suspended? redirect to pending
    if(pUser.getCustomer().getStatus() == CustomerStatus.Suspended.getCode()) {
        response.sendRedirect("../pending");
        return false;
    }
}

if(pUser.getCustomer().getStatus() == CustomerStatus.Blocked.getCode()) {

    // redirect to blocked page
    response.sendRedirect("../blocked");
    SecurityContextHolder.clearContext();
    return false;
}

if(pUser.getCustomer().getStatus() == CustomerStatus.AllowRetry.getCode()) {

    // redirect to CC submission page
    response.sendRedirect("../register/retry");
    return false;
}

if(pUser.getCustomer().getStatus() == CustomerStatus.Enabled.getCode() ||
   pUser.getCustomer().getStatus() == CustomerStatus.Disabled.getCode()) {

    // do nothing
}

return true;
}
_

これは有効なアプローチですか?代替案はありますか?

14
Less

すべてのオプションが有効です。必要な抽象化のレベルによって異なります。

Filterでは、HttpServletRequestオブジェクトとHttpServletResponseオブジェクトにしかアクセスできないため、ServletAPIと非常に密接に関連しています。また、レンダリングするビューやResponseEntityを返すなど、Springの優れた機能すべてに(直接)アクセスすることはできません。

HandlerInterceptorでも、ほぼ同じです。 ModelAndViewにアクセスできないpreHandle()で直接リダイレクトまたはリクエスト処理を行うか、postHandle()でチェックインするフラグを設定できます。 ModelAndViewにはアクセスできますが、他のSpringMVC機能にはアクセスできません。

Spring Securityは良い代替手段ですが、あまり好きではない構成がたくさんあることがわかりました。

私が最も気に入っている最後の選択肢の1つは、AOPを使用することです(これは、Spring SecurityまたはShiroでも実行できます)。 @Privateのようなアノテーションを作成し、@Controllerハンドラーメソッドにアノテーションを付けます。 AOPを使用して、これらの方法をアドバイスします。アドバイスは基本的に、いくつかのセッションまたは要求属性でフラグ(許可されているかどうか)をチェックします。許可されている場合はハンドラーメソッドの実行を続行し、許可されていない場合はUnauthorizedException(または同様のもの)をスローします。次に、応答の生成方法をほぼ完全に制御できる例外に対して @ExceptionHandler を宣言します:ModelAndView(および関連)、ResponseEntity、ハンドラーに@ResponseBodyの注釈を付けたり、応答を直接書き込んだりします。必要に応じて、より詳細に制御できるようになります。

21