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;
}
_
。
これは有効なアプローチですか?代替案はありますか?
すべてのオプションが有効です。必要な抽象化のレベルによって異なります。
Filter
では、HttpServletRequest
オブジェクトとHttpServletResponse
オブジェクトにしかアクセスできないため、Servlet
APIと非常に密接に関連しています。また、レンダリングするビューやResponseEntity
を返すなど、Springの優れた機能すべてに(直接)アクセスすることはできません。
HandlerInterceptor
でも、ほぼ同じです。 ModelAndView
にアクセスできないpreHandle()
で直接リダイレクトまたはリクエスト処理を行うか、postHandle()
でチェックインするフラグを設定できます。 ModelAndView
にはアクセスできますが、他のSpringMVC機能にはアクセスできません。
Spring Securityは良い代替手段ですが、あまり好きではない構成がたくさんあることがわかりました。
私が最も気に入っている最後の選択肢の1つは、AOPを使用することです(これは、Spring SecurityまたはShiroでも実行できます)。 @Private
のようなアノテーションを作成し、@Controller
ハンドラーメソッドにアノテーションを付けます。 AOPを使用して、これらの方法をアドバイスします。アドバイスは基本的に、いくつかのセッションまたは要求属性でフラグ(許可されているかどうか)をチェックします。許可されている場合はハンドラーメソッドの実行を続行し、許可されていない場合はUnauthorizedException
(または同様のもの)をスローします。次に、応答の生成方法をほぼ完全に制御できる例外に対して @ExceptionHandler
を宣言します:ModelAndView
(および関連)、ResponseEntity
、ハンドラーに@ResponseBody
の注釈を付けたり、応答を直接書き込んだりします。必要に応じて、より詳細に制御できるようになります。