protocolo autenticacion aplicaciones java session jsf richfaces facelets

java - autenticacion - Cómo invalidar una sesión de usuario cuando inicia sesión dos veces con las mismas credenciales



saml autenticacion (3)

  1. crear un campo entero en la base de datos userLoggedInCount
  2. En cada inicio de sesión, incremente ese indicador y almacene el resultado en la sesión.
  3. En cada solicitud, verifique el valor en la base de datos y el de la sesión, y si el de la sesión es menor que el de la base de datos, invalidate() la sesión y disminuya el valor de la base de datos.
  4. cada vez que se destruye una sesión, decrementa el valor también.

Estoy usando JSF 1.2 con Richfaces y Facelets.

Tengo una aplicación con muchos beans de sesión y algunos beans de aplicación.

El usuario inicia sesión con, digamos, Firefox. Se crea una sesión con ID = "A"; Luego abre Chrome y vuelve a iniciar sesión con las mismas credenciales. Se crea una sesión con ID = "B".

Cuando se crea la sesión "B", quiero poder destruir la sesión "A". ¿Como hacer eso?

También. cuando el usuario en Firefox hace algo, quiero poder mostrar una ventana emergente o algún tipo de notificación que diga "Se ha desconectado porque ha iniciado sesión desde otro lugar".

Tengo un SessionListener que realiza un seguimiento de las sesiones creadas y destruidas. La cuestión es que podría guardar el objeto HTTPSession en un bean de ámbito de aplicación y destruirlo cuando detecto que el usuario ha iniciado sesión dos veces. Pero algo me dice que está mal y no funcionará.

¿JSF realiza un seguimiento de las sesiones en algún lugar del lado del servidor? ¿Cómo acceder a ellos por identificador? Si no es así, ¿cómo eliminar el primer inicio de sesión de un usuario cuando inicia sesión dos veces?


Me gusta la respuesta de BalusC con un HttpSessionBindingListener.

Pero en Enterprise JavaBeansTM Specification, la versión 2.0 está escrita:

Un Bean empresarial no debe usar campos estáticos de lectura / escritura. Se permite el uso de campos estáticos de solo lectura. Por lo tanto, se recomienda que todos los campos estáticos en la clase de enterprise bean se declaren como finales

Entonces, ¿no es mejor hacer un ApplicationScoped Bean que almacene toda la aplicación de la tabla sin usar campos estáticos?

Lo probó y parece funcionar ...

Aquí está mi ejemplo:

@Named @ApplicationScoped public class UserSessionStorage implements java.io.Serializable,HttpSessionBindingListener { @Inject UserManagement userManagement; private static final long serialVersionUID = 1L; /** * Application wide storage of the logins */ private final Map<User, List<HttpSession>> logins = new HashMap<User, List<HttpSession>>(); @Override public void valueBound(final HttpSessionBindingEvent event) { System.out.println("valueBound"); /** * Get current user from userManagement... */ User currentUser = userManagement.getCurrentUser(); List<HttpSession> sessions = logins.get(currentUser); if (sessions != null) { for (HttpSession httpSession : sessions) { httpSession.setAttribute("invalid", "viewExpired"); } } else { sessions = new ArrayList<HttpSession>(); } HttpSession currentSession = event.getSession(); sessions.add(currentSession); logins.put(currentUser, sessions); } @Override public void valueUnbound(final HttpSessionBindingEvent event) { System.out.println("valueUnbound"); User currentUser = userManagement.getCurrentUser(); List<HttpSession> sessions = logins.get(currentUser); if (sessions != null) { sessions.remove(event.getSession()); } else { sessions = new ArrayList<HttpSession>(); } logins.put(currentUser, sessions); }

}

-> Lo siento por mi änglish ...


El enfoque independiente de la base de datos sería permitir que el User tenga una variable de static Map<User, HttpSession> e implementar HttpSessionBindingListener (y Object#equals() y Object#hashCode() ). De esta manera, su aplicación web seguirá funcionando después de un bloqueo imprevisto que puede hacer que los valores de la base de datos no se actualicen (por supuesto, puede crear un ServletContextListener que restablece la base de datos en el inicio de la aplicación web, pero eso es solo un trabajo cada vez más).

Así es como debe verse el User :

public class User implements HttpSessionBindingListener { // All logins. private static Map<User, HttpSession> logins = new ConcurrentHashMap<>(); // Normal properties. private Long id; private String username; // Etc.. Of course with public getters+setters. @Override public boolean equals(Object other) { return (other instanceof User) && (id != null) ? id.equals(((User) other).id) : (other == this); } @Override public int hashCode() { return (id != null) ? (this.getClass().hashCode() + id.hashCode()) : super.hashCode(); } @Override public void valueBound(HttpSessionBindingEvent event) { HttpSession session = logins.remove(this); if (session != null) { session.invalidate(); } logins.put(this, event.getSession()); } @Override public void valueUnbound(HttpSessionBindingEvent event) { logins.remove(this); } }

Cuando inicia sesión el User siguiente manera:

User user = userDAO.find(username, password); if (user != null) { sessionMap.put("user", user); } else { // Show error. }

luego invocará el valueBound() que eliminará cualquier usuario que haya iniciado sesión previamente del mapa de valueBound() de logins e invalidará la sesión.

Cuando cierre la sesión del User siguiente manera:

sessionMap.remove("user");

o cuando se agote el tiempo de espera de la sesión, se valueUnbound() que elimina al usuario de la valueUnbound() de logins .