正解には多くの欠陥があります。そこにある私のコメントを参照してください。問題は実際には簡単です。永続的なデータストア (SQL データベースなど) が必要になります。同様に使用できますServletContext
が、ユーザーはサーバーの再起動またはアプリケーションの再デプロイ後にログアウトされます。HashMap
inを使用する場合はServletContext
、より多くのスレッドから同時にアクセスされる可能性があるため、適切に同期することを忘れないでください。
サーバーのセッションとそのIDでハッキングしないでください。それはあなたの管理下になく、サーバーが元のセッションを期限切れにした後にJSESSIONIDを含むリクエストが表示された場合、一部のサーバーはセッションIDを変更します。独自のクッキーをロールします。
基本的に必要なもの:
- 安全にランダムな値を持つ、永続的ではない独自の Cookie
- データストア
javax.servlet.Filter
ログインを確認する
フィルタの実装は次のようになります。
public class LoginFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
// Java 1.8 stream API used here
Cookie loginCookie = Arrays.stream(req.getCookies()).filter(c -> c.getName()
.equals("MY_SESSION_COOKIE")).findAny().orElse(null);
// if we don't have the user already in session, check our cookie MY_SESSION_COOKIE
if (req.getSession().getAttribute("currentUser") == null) {
// if the cookie is not present, add it
if (loginCookie == null) {
loginCookie = new Cookie("MY_SESSION_COOKIE", UUID.randomUUID().toString());
// Store that cookie only for our app. You can store it under "/",
// if you wish to cover all webapps on the server, but the same datastore
// needs to be available for all webapps.
loginCookie.setPath(req.getContextPath());
loginCookie.setMaxAge(DAYS.toSeconds(1)); // valid for one day, choose your value
resp.addCookie(loginCookie);
}
// if we have our cookie, check it
else {
String userId = datastore.getLoggedUserForToken(loginCookie.getValue());
// the datastore returned null, if it does not know the token, or
// if the token is expired
req.getSession().setAttribute("currentUser", userId);
}
}
else {
if (loginCookie != null)
datastore.updateTokenLastActivity(loginCookie.getValue());
}
// if we still don't have the userId, forward to login
if (req.getSession().getAttribute("currentUser") == null)
resp.sendRedirect("login.jsp");
// else return the requested resource
else
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
}
ユーザーがログインしたら、MY_SEESSION_COOKIE の値を とともにデータストアに追加し、userId
ログアウト時に削除する必要があります。また、有効期限をデータストアに保存し、トークンを受け入れる前に確認する必要があります。maxAge プロパティに関するブラウザーに依存しないでください。
また、データストアのクリーンアップを追加して、未処理の Cookie が永久に残るのを防ぐことを忘れないでください。
上記のコードは実際にはテストされていません。いくつかの癖があるかもしれませんが、基本的な考え方は機能するはずです。少なくとも、受け入れられているソリューションよりもはるかに優れています。