我有一个Web应用程序,我想阻止用户多次登录(来自同一台机器或不同机器上的不同浏览器)。
我读到了HttpSessionBindingListener,我尝试调整我的登录servlet和用户Bean来实现所需的解决方案。不幸的是,只有当我第二次在同一个浏览器上登录时(在不同的选项卡中),它才有效,但是如果我更换浏览器(在同一台机器上),它就不再起作用了。
代码如下。
用户Bean在成功登录后进入会话
public class BeanUtente implements HttpSessionBindingListener {
private String username;
private String gruppo;
public boolean ruoloPresente(String nomeRuolo) {
//se il gruppo dell'utente è uguale a quello richiesto dal filtro
if (this.gruppo.equals(nomeRuolo))
return true;
else
return false;
}
public void valueBound(HttpSessionBindingEvent argo) {
System.out.println("Value Bound Called, " + argo.getValue() + " isNewSession: " + argo.getSession().isNew());
}
public void valueUnbound(HttpSessionBindingEvent argo) {
System.out.println("Value UnBound Called, " + argo.getValue() + " isNewSession: " + argo.getSession().isNew());
}
public String toString() {
return "Username is: " + username;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getGruppo() {
return gruppo;
}
public void setGruppo(String gruppo) {
this.gruppo = gruppo;
}
}
登录servlet
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Db db = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
response.setHeader("Cache-Control","no-cache,no-store,must-revalidate");
response.setHeader("Pragma","no-cache");
response.setDateHeader("Expires", 0);
Locale locale = request.getLocale();
ResourceBundle labels = ResourceBundle.getBundle("risorse.label", locale);
String urlLoginOk = getInitParameter("urlLoginOk");
String urlLoginKo = getInitParameter("urlLoginKo");
String username = request.getParameter("username");
String password = request.getParameter("password");
db = new Db();
db.apriConnessione();
String sql = "SELECT gruppo FROM Utenti WHERE username=? AND password=SHA2(?, 512)";
ps = db.getConnection().prepareStatement(sql);
ps.setString(1, username);
ps.setString(2, password);
rs = ps.executeQuery();
//login OK
if(username != null && password != null && rs.next()) {
BeanUtente beanUtente = new BeanUtente();
beanUtente.setUsername(username);
beanUtente.setGruppo(rs.getString("gruppo"));
HttpSession sess = request.getSession();
sess.setAttribute("beanUtente", beanUtente);
request.getRequestDispatcher(urlLoginOk).forward(request, response);
}
//login KO
else {
request.setAttribute("errore", labels.getString("loginFallito"));
request.getRequestDispatcher(urlLoginKo).forward(request, response);
}
}
catch(Exception e) {
e.printStackTrace();
}
finally {
try {
if(!ps.isClosed())
ps.close();
if(!rs.isClosed())
rs.close();
}
catch (SQLException sqle) {
sqle.printStackTrace();
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if(db.getConnection() != null)
db.chiudiConnessione();
}
}
}
这是日志。 当我第一次登录时,我得到:
*Value Bound Called, Username is: pi isNewSession: false*
当我第二次从同一个浏览器登录时,我得到:
*Value Bound Called, Username is: pi isNewSession: false
Value UnBound Called, null isNewSession: false*
所以似乎正确调用了UnBound方法。 但是,如果我第三次从同一台机器上的另一个浏览器登录,我会得到:
*Value Bound Called, Username is: pi isNewSession: false*
即,尚未调用UnBound方法。
你能帮助我理解我的错误在哪里吗? 我想我必须明确调用session.removeAttribute(“beanUtente”)但是何时/在哪里?提前感谢您的任何帮助:)
答案 0 :(得分:0)
为避免从多个浏览器登录,我不认为HttpSessionBindingListener
会起作用,因为使用新浏览器,它会创建新会话。
您必须在特定用户的后端保存状态,对每个用户说userId
,登录后可能在cache/DB
,并从{{1}中删除一旦他退出,
所以当用户登录时如下所示。 Object user = getUser(userId);
if(user!= null){ //用户已登录,只返回自定义消息 } 其他{ //允许用户登录 }
cache/DB
上的logout
从userId
移除cache/user
。
答案 1 :(得分:0)
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.mvcMatchers("/").permitAll()
.and().sessionManagement()
.maximumSessions(1);
}