Как реализовать «Оставайтесь в системе», когда пользователь заходит в веб-приложение

На большинстве веб-сайтов, когда пользователь собирается ввести имя пользователя и пароль для входа в систему, есть флажок «Оставайтесь в системе». Если вы установите флажок, это позволит вам войти во все сеансы из одного и того же веб-браузера. Как я могу реализовать то же самое в Java EE?

Я использую аутентификацию, управляемую контейнером на основе FORM, с помощью страницы входа в JSF.

 Student  CentralFeed  /CentralFeed.jsf    STUDENT ADMINISTRATOR    FORM jdbc-realm-scholar  /index.jsf /LoginError.jsf    Admin who has ultimate power over everything ADMINISTRATOR   Participants of the social networking Bridgeye.com STUDENT  

Java EE 8 и выше

Если вы используете Java EE 8 или новее, поставьте @RememberMe на пользовательский HttpAuthenticationMechanism вместе с RememberMeIdentityStore .

 @ApplicationScoped @AutoApplySession @RememberMe public class CustomAuthenticationMechanism implements HttpAuthenticationMechanism { @Inject private IdentityStore identityStore; @Override public AuthenticationStatus validateRequest(HttpServletRequest request, HttpServletResponse response, HttpMessageContext context) { Credential credential = context.getAuthParameters().getCredential(); if (credential != null) { return context.notifyContainerAboutLogin(identityStore.validate(credential)); } else { return context.doNothing(); } } } 

 public class CustomIdentityStore implements RememberMeIdentityStore { @Inject private UserService userService; // This is your own EJB. @Inject private LoginTokenService loginTokenService; // This is your own EJB. @Override public CredentialValidationResult validate(RememberMeCredential credential) { Optional user = userService.findByLoginToken(credential.getToken()); if (user.isPresent()) { return new CredentialValidationResult(new CallerPrincipal(user.getEmail())); } else { return CredentialValidationResult.INVALID_RESULT; } } @Override public String generateLoginToken(CallerPrincipal callerPrincipal, Set groups) { return loginTokenService.generateLoginToken(callerPrincipal.getName()); } @Override public void removeLoginToken(String token) { loginTokenService.removeLoginToken(token); } } 

Вы можете найти пример реального мира в приложении Java EE Kickoff .


Java EE 6/7

Если вы находитесь на Java EE 6 или 7, homegrow – долгоживущий файл cookie для отслеживания уникального клиента и использования API Servlet 3.0 при условии, что вы используете программный логин HttpServletRequest#login() когда пользователь не зарегистрирован, но файл cookie присутствует.

Это проще всего сделать, если вы создаете другую таблицу БД со значением java.util.UUID как ПК и идентификатором соответствующего пользователя в качестве FK.

Предположим, что следующая форма входа:

 

И следующее в методе doPost() Servlet который отображается в /login :

 String username = request.getParameter("username"); String password = hash(request.getParameter("password")); boolean remember = "true".equals(request.getParameter("remember")); User user = userService.find(username, password); if (user != null) { request.login(user.getUsername(), user.getPassword()); // Password should already be the hashed variant. request.getSession().setAttribute("user", user); if (remember) { String uuid = UUID.randomUUID().toString(); rememberMeService.save(uuid, user); addCookie(response, COOKIE_NAME, uuid, COOKIE_AGE); } else { rememberMeService.delete(user); removeCookie(response, COOKIE_NAME); } } 

( COOKIE_NAME должно быть уникальным именем cookie, например "remember" а COOKIE_AGE – это возраст в секундах, например 2592000 течение 30 дней)

Вот как метод doFilter() Filter который отображается на ограниченных страницах, может выглядеть так:

 HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; User user = request.getSession().getAttribute("user"); if (user == null) { String uuid = getCookieValue(request, COOKIE_NAME); if (uuid != null) { user = rememberMeService.find(uuid); if (user != null) { request.login(user.getUsername(), user.getPassword()); request.getSession().setAttribute("user", user); // Login. addCookie(response, COOKIE_NAME, uuid, COOKIE_AGE); // Extends age. } else { removeCookie(response, COOKIE_NAME); } } } if (user == null) { response.sendRedirect("login"); } else { chain.doFilter(req, res); } 

В сочетании с этими вспомогательными методами cookie (слишком плохо они отсутствуют в API Servlet):

 public static String getCookieValue(HttpServletRequest request, String name) { Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { if (name.equals(cookie.getName())) { return cookie.getValue(); } } } return null; } public static void addCookie(HttpServletResponse response, String name, String value, int maxAge) { Cookie cookie = new Cookie(name, value); cookie.setPath("/"); cookie.setMaxAge(maxAge); response.addCookie(cookie); } public static void removeCookie(HttpServletResponse response, String name) { addCookie(response, name, null, 0); } 

Несмотря на то, что UUID чрезвычайно сложно использовать грубую силу, вы можете предоставить пользователю возможность блокировать опцию «запомнить» на IP-адрес пользователя ( request.getRemoteAddr() ) и хранить / сравнивать его в базе данных. Это делает его еще более надежным. Кроме того, было бы полезно иметь «дату истечения срока действия», хранящуюся в базе данных.

Также рекомендуется заменить значение UUID всякий раз, когда пользователь изменил свой пароль.


Java EE 5 или ниже

Пожалуйста, обновите.

Обычно это делается следующим образом:

Когда вы регистрируете пользователя, вы также устанавливаете cookie на клиенте (и сохраняете значение cookie в базе данных), истекающего через определенное время (обычно 1-2 недели).

Когда приходит новый запрос, проверьте, существует ли определенный файл cookie, и если да, посмотрите в базу данных, чтобы узнать, соответствует ли она определенной учетной записи. Если он будет соответствовать, вы «свободно» войдете в эту учетную запись. Когда я говорю свободно, я имею в виду, что вы только позволяете этой сессии читать какую-то информацию и не писать информацию. Вам нужно будет запросить пароль, чтобы разрешить параметры записи.

Это все, что есть. Хитрость заключается в том, чтобы убедиться, что «свободный» логин не может нанести большой вред клиенту. Это несколько защитит пользователя от кого-то, кто схватит его, запомнит мне cookie и попытается войти в систему как он.

Вы не можете полностью войти в систему через HttpServletRequest.login (имя пользователя, пароль), так как вы не должны хранить как имя пользователя, так и пароль обычного текста в базе данных. Также вы не можете выполнить этот логин с хешем пароля, который сохраняется в базе данных. Однако вам нужно идентифицировать пользователя с маркером cookie / DB, но введи его в систему без ввода пароля с помощью пользовательского модуля входа (class Java) на основе API-интерфейса Glassfish.

Для получения более подробной информации см. Следующие ссылки:

http://www.lucubratory.eu/custom-jaas-realm-for-glassfish-3/

Механизм пользовательской безопасности в приложении Java EE 6/7

Interesting Posts
Давайте будем гением компьютера.