在实现spring security remember-me持久性令牌时遇到问题。 已成功实现remember-me持久性令牌,但在用户注销系统时会出现问题。
以下是实施: 弹簧security.xml文件
<global-method-security pre-post-annotations="enabled"/>
<http auto-config="true" use-expressions="true" >
...some url parten
<form-login login-page="/login.html"
authentication-failure-url="/loginfailed.html"
authentication-success-handler-ref="customAuthenticationHandler"/>
<logout logout-success-url="/logout.html" delete-cookies='JSESSIONID' />
<remember-me services-ref="pfRememberMeServices"
key="pf_token_key"/>
</http>
<beans:bean id="pfRememberMeServices"
class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
<beans:property name="tokenRepository" ref="pfTokenRepository" />
<beans:property name="userDetailsService" ref="userDetailsService" />
<beans:property name="tokenValiditySeconds" value="86400"/> <!-- alive in 1 day -->
<beans:property name="key" value="pf_token_key" />
<beans:property name="cookieName" value="mycookie" />
<beans:property name="alwaysRemember" value="true" />
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="userDetailsService" />
</authentication-manager>
<beans:bean id="userDetailsService"
class="com.platform.authenticate.model.UserDetailsServiceImpl" >
</beans:bean>.
令牌存储库:
@Override
public void removeUserTokens(String userid) {
// TODO Auto-generated method stub
tokenDao.removeUserTokens(userid);
}
TokenDao:
@Transactional
public void removeUserTokens(final String username) {
//Session session = getSessionFactory().getCurrentSession();
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Token token =
(Token) session.createCriteria(Token.class)
.add(Restrictions.eq("username", username)).uniqueResult();
if (token != null) {
session.delete(token);
}
tx.commit();
} catch (RuntimeException e) {
tx.rollback();
throw e; // or display error message
} finally {
session.close();
}
}
当我在两个浏览器或两个客户端上使用同一用户登录时,persistent_logins表中有两条记录如下:
"2JLIh8E8vifKOdlaidCIog==";"user12";"OKjbqqIAhx74JpmPsNQHaw==";"2013-07-03 16:19:05.12"
"gQ2EDtl87ZC6XSjV6cTYrA==";"user12";"iYrG7dlnjPyKxUz/hwQMdQ==";"2013-07-03 15:47:24.011"
当同一个用户有两条记录时,我的实施是否正确?
然后,当我从一个浏览器或一个客户端注销时,会触发removeUserTokens()函数,但是:
Token token =
(Token) session.createCriteria(Token.class)
.add(Restrictions.eq("username", username)).uniqueResult();
使用上面的代码,我无法通过用户名删除注销用户的令牌,当有user12的2条记录时,它不是唯一的结果。
如果我强制删除所有user12,则将删除所有客户端的所有会话/令牌。这不对吗?
那么我怎样才能删除注销用户的会话/令牌信息,但是为其他客户端的同一用户保留会话/令牌?
我已经问过谷歌先生,但我的问题似乎很独特,找不到任何相同的。
如果我的实施有误,请告诉我。
更新 当我从一个客户端发送j_spring_security_logout时,这是堆栈跟踪:
例外
org.hibernate.NonUniqueResultException:查询没有返回唯一的 结果:2 org.hibernate.impl.AbstractQueryImpl.uniqueElement(AbstractQueryImpl.java:899) org.hibernate.impl.CriteriaImpl.uniqueResult(CriteriaImpl.java:369)
答案 0 :(得分:0)
我有同样的实现 - 我遇到了同样的问题。
但是我没有决定删除所有令牌,因为要查找令牌肯定是
List<Token> tokens = sessionFactory.getCurrentSession().createCriteria(Token.class)
.add(Restrictions.eq("username", username)).list();
if (tokens.size() > 0) {
for (Token token : tokens) {
sessionFactory.getCurrentSession().delete(token);
}
}