つまり、2 つの異なるマシンで同時にユーザー ID を認証することはできません。どうすればこれを制御できますか? Java EE プラットフォームを使用しています。
3 に答える
Java EEは、このシナリオの直接的なソリューションを提供していません。
Filter
制限を適用するためにサーブレットを導入する場合があります。
ユーザーがログインしているかどうかを追跡し、重複するユーザーのリクエストを拒否します。スケールアップしたい場合は、アプリケーションスコープではなく、データベースで追跡します[ただし、アプリケーションスコープのハッシュテーブルは手っ取り早いプロトタイプソリューションになります]。
HttpServletRequest.getRemoteAddr
2台の着信コンピューターを区別するために使用する場合がありますが、これは同じルーターの背後にある2台のコンピューターを区別するのに役立ちません。JPAリクエストを処理するために、EJBをフィルターに挿入します。EJBを使用すると、他の問題が解消されます。
すべてのサーブレットにフィルターをデプロイします(そうでない場合はセキュリティホールがあります)。
@WebFilter({"/*"}) public class SecurityFilter extends AbstractSecurityFilter { ... }
以下に定義するAbstractSecurityFilterは、標準のJavaEEセキュリティチェックを強化します。これにより、すべての着信サーブレット要求をチェックするオーバーヘッドが削減され、「新規ログイン」に対してのみ完全なチェックが行われます。また、拒否ロジックも処理します。議論されている認証を実装していませんが、そのための基礎を提供する可能性があります。
サブクラスを作成しauthenticate
、getFailedLoginPage()
メソッドの定義を提供します。
/***
* Augment the Java EE security check(s).
*
* Java EE Security is the primary check, so this filter doesn't take any action
* until after the user successfully logs in through the standard Java EE security
* mechanisms. Once logged in, the method authenticate is called to perform
* the custom checks. If these checks fail the user is logged out and forwarded
* to the page returned by getFailedLoginPage().
*/
public abstract class AbstractSecurityFilter implements Filter
{
protected static final String ATTR__IS_AUTHENTICATED = AbstractSecurityFilter.class.getName() + ".authenticated";
/**
* @return true if request meets our authentication requirements.
*/
protected abstract boolean authenticate(HttpServletRequest request, HttpServletResponse response);
protected abstract String getFailedLoginPage();
@Override
final public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
throws IOException, ServletException
{
/**
*
* Order of events (and order is somewhat important): <code>
*
* - ignore if user has not logged in (if Java EE Security hasn't required login, neither do we here).
*
* - check for this filter's ATTR__IS_AUTHENTICATED flag to be set on the session attributes:
* if set we have nothing else to do.
*
* - call authenticate...
* - on failure: logout, forward to failedLoginPage, and return (cancel remainder of this request).
* - on success: set ATTR__IS_AUTHENTICATED flag in the session attributes.
*
* </code>
*/
if (request instanceof HttpServletRequest) {
final HttpServletRequest httpRequest = (HttpServletRequest)request;
final HttpSession session = httpRequest.getSession(false);
if (session != null) {
/*
* Ignore if user has not (yet) logged in; let JEE Security filter(s) do their job(s) first.
*/
final Principal userPrincipal = httpRequest.getUserPrincipal();
if (userPrincipal != null) {
// Check that user has not been fully "verified".
final Object attribute = session.getAttribute(ATTR__IS_AUTHENTICATED);
if (attribute == null) {
if ( !authenticate(httpRequest, (HttpServletResponse)response) {
httpRequest.logout();
final ServletContext servletContext = httpRequest.getServletContext();
servletContext.getRequestDispatcher(getFailedLoginPage()).forward(request, response);
return;
}
// User has passed local checks; record so we don't have to do this again.
final String name = userPrincipal.getName();
session.setAttribute(ATTR__IS_AUTHENTICATED, name);
}
}
}
}
chain.doFilter(request, response);
}
}
ユーザーがログインするたびに、トークン (たとえば、セッション ID ) を与えます。後で、ユーザーがいくつかの操作を実行すると、このトークンを彼から受け取り、それを内部データ ストレージ (データベースなど) に対して検証します。検証が成功した場合は、ユーザーを許可します。
異なるコンピューターからの複数のログインを無効にするには、トークンにマシンの ID などのデータを含める必要があります。a) ログインおよび b) 検証中に、トークンからの ID と現在使用されているマシンの実際の ID を比較します。
Spring-security には、セッションでの同時実行制御があります。http://static.springsource.org/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#concurrent-sessionsを参照してください。