我在实现 spring security 时遇到了一个问题,记住我的持久性令牌。已经成功实现了记住我的持久令牌,但是当用户注销系统时出现问题。
这里是实现:spring-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);
}
通证道:
@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)