Как реализовать "оставаться в системе" при входе пользователя в веб-приложение
на большинстве веб-сайтов, когда пользователь собирается предоставить имя пользователя и пароль для входа в систему, есть флажок "оставаться в системе". Если вы установите флажок, он будет держать вас вошли во все сеансы из того же веб-браузера. Как я могу реализовать то же самое в Java EE?
Я использую форму на основе контейнера управляемой аутентификации со страницей входа JSF.
<security-constraint>
<display-name>Student</display-name>
<web-resource-collection>
<web-resource-name>CentralFeed</web-resource-name>
<description/>
<url-pattern>/CentralFeed.jsf</url-pattern>
</web-resource-collection>
<auth-constraint>
<description/>
<role-name>STUDENT</role-name>
<role-name>ADMINISTRATOR</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>jdbc-realm-scholar</realm-name>
<form-login-config>
<form-login-page>/index.jsf</form-login-page>
<form-error-page>/LoginError.jsf</form-error-page>
</form-login-config>
</login-config>
<security-role>
<description>Admin who has ultimate power over everything</description>
<role-name>ADMINISTRATOR</role-name>
</security-role>
<security-role>
<description>Participants of the social networking Bridgeye.com</description>
<role-name>STUDENT</role-name>
</security-role>
3 ответа:
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> 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<String> groups) { return loginTokenService.generateLoginToken(callerPrincipal.getName()); } @Override public void removeLoginToken(String token) { loginTokenService.removeLoginToken(token); } }
вы можете найти реальный пример на Java EE Kickoff Application.
Java EE 6/7
если вы находитесь на Java EE 6 или 7, homegrow a long-living cookie для отслеживания уникальных клиент и использовать сервлет 3.0 API при условии программного входа
HttpServletRequest#login()
когда пользователь не вошел в систему, но файл cookie присутствует.это проще всего достичь, если вы создадите другую таблицу БД с
java.util.UUID
значение как PK и идентификатор пользователя, о котором идет речь, как FK.примите следующую форму входа:
<form action="login" method="post"> <input type="text" name="username" /> <input type="password" name="password" /> <input type="checkbox" name="remember" value="true" /> <input type="submit" /> </form>
и следуя в
doPost()
метод aServlet
, который назначен на/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); } }
(the
COOKIE_NAME
должно быть уникальное имя, например,"remember"
иCOOKIE_AGE
должен быть возраст в секундах, например,2592000
на 30 дней)вот как
doFilter()
метод aFilter
который отображается на ограниченных страницах может выглядеть так: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 сервлетов):
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
is чрезвычайно трудно использовать грубую силу, вы можете предоставить пользователю возможность заблокировать опцию "запомнить" на IP-адрес пользователя (request.getRemoteAddr()
) и сохранить/сравнить его в базе данных, а также. Это делает его немного более надежным. Кроме того, было бы полезно иметь" срок годности", хранящийся в базе данных.это также хорошая практика, чтобы заменить
UUID
значение, когда пользователь изменил свой пароль.
Java EE 5 или ниже
пожалуйста, обновите.
обычно это делается так:
когда вы входите в систему пользователя, вы также устанавливаете cookie на клиенте (и сохраняете значение cookie в базе данных), истекающее через определенное время (обычно 1-2 недели).
когда приходит новый запрос, вы проверяете, существует ли определенный файл cookie, и если да, то посмотрите в базу данных, чтобы узнать, соответствует ли он определенной учетной записи. Если он совпадает, то вы будете "свободно" войти в эту учетную запись. Когда я говорю свободно, я имею в виду, что вы только позволяете этой сессии читать некоторые информация и не писать информацию. Вам нужно будет запросить пароль, чтобы разрешить параметры записи.
Это все, что есть. Хитрость заключается в том, чтобы убедиться, что "свободно" войти не в состоянии сделать много вреда для клиента. Это несколько защитит пользователя от того, кто схватит его файл cookie remember me и попытается войти в систему как он.
вы не можете войти в систему пользователя полностью через HttpServletRequest.логин (имя пользователя, пароль), так как вы не должны хранить как имя пользователя, так и простой текстовый пароль в базе данных. Также вы не можете выполнить этот вход с хэшем пароля, который сохраняется в базе данных. Однако вам необходимо идентифицировать пользователя с помощью токена cookie/DB, но войти в систему без ввода пароля с помощью пользовательского модуля входа (Java class) на основе GlassFish server API.
см. следующие ссылки для получения дополнительной информации подробности:
http://www.lucubratory.eu/custom-jaas-realm-for-glassfish-3/
пользовательский механизм безопасности в приложении Java EE 6/7