Come implementare “Resta connesso” quando l’utente accede all’applicazione web

Sulla maggior parte dei siti web, quando l’utente sta per fornire il nome utente e la password per accedere al sistema, c’è una casella di controllo come “Rimani connesso”. Se selezioni la casella, ti manterrà connesso in tutte le sessioni dallo stesso browser web. Come posso implementare lo stesso in Java EE?

Utilizzo l’autenticazione gestita dal contenitore basata su FORM con una pagina di accesso 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 e versioni successive

Se sei su Java EE 8 o successivo, metti @RememberMe su un HttpAuthenticationMechanism personalizzato insieme a 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); } } 

È ansible trovare un esempio reale nell’applicazione Java EE Kickoff .


Java EE 6/7

Se sei su Java EE 6 o 7, homegrow un cookie longevo per tracciare il client univoco e utilizzare l’API Servlet 3.0 fornita accesso programmatico HttpServletRequest#login() quando l’utente non è connesso ma il cookie è presente.

Questo è il più facile da ottenere se si crea un’altra tabella DB con un valore java.util.UUID come PK e l’ID dell’utente in questione come FK.

Assumi il seguente modulo di accesso:

 

E il seguente nel metodo doPost() di un Servlet che è mappato su /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); } } 

(il COOKIE_NAME dovrebbe essere il nome univoco del cookie, ad esempio "remember" e COOKIE_AGE dovrebbe essere l’età in secondi, ad esempio 2592000 per 30 giorni)

Ecco come può doFilter() metodo doFilter() di un Filter mappato su pagine riservate:

 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); } 

In combinazione con quei metodi di cookie helper (troppo male mancano nell’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); } 

Sebbene l’ UUID sia estremamente difficile da usare come forza bruta, è ansible fornire all’utente un’opzione per bloccare l’opzione “remember” sull’indirizzo IP dell’utente ( request.getRemoteAddr() ) e memorizzarla / confrontarla anche nel database. Questo lo rende un po ‘più robusto. Inoltre, avere una “data di scadenza” memorizzata nel database sarebbe utile.

È anche buona norma sostituire il valore UUID ogni volta che l’utente ha cambiato la sua password.


Java EE 5 o inferiore

Per favore, aggiorna.

Normalmente questo è fatto in questo modo:

Quando si accede a un utente, si imposta anche un cookie sul client (e si memorizza il valore del cookie nel database) che scade dopo un certo tempo (in genere 1-2 settimane).

Quando arriva una nuova richiesta, controlla che esista un determinato cookie e, in tal caso, controlla nel database per vedere se corrisponde a un determinato account. Se corrisponde ti verrà quindi “liberamente” accedere a quell’account. Quando dico liberamente, voglio dire che lasci solo che quella sessione legga alcune informazioni e non scriva informazioni. Dovrai richiedere la password per consentire le opzioni di scrittura.

Questo è tutto ciò che è. Il trucco è assicurarsi che un accesso “lento” non sia in grado di fare molto danno al cliente. Questo in qualche modo proteggerà l’utente da qualcuno che afferra il suo remember me cookie e cerca di accedere come lui.

Non è ansible accedere a un utente completamente tramite HttpServletRequest.login (nome utente, password) poiché non è necessario mantenere sia il nome utente che la password in testo semplice nel database. Inoltre non è ansible eseguire questo login con un hash password che viene salvato nel database. Tuttavia, è necessario identificare un utente con un token cookie / DB, ma accedervi senza inserire la password utilizzando il modulo di login personalizzato (class Java) basato sull’API del server Glassfish.

Vedere i seguenti collegamenti per maggiori dettagli:

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

Meccanismo di sicurezza personalizzato nell’applicazione Java EE 6/7