我正在使用spring security v3.1.4。我想要实现的是让管理员能够注销常规用户(使他的会话无效)。用户只能在任何给定时间登录一次,但如果他忘记退出,那么当他尝试从其他位置登录时,他将无法登录。所以他会把一张票给管理员和管理员将使他之前登录的所有会话无效(希望只有一个)。
在我的web.xml中,我有以下定义。
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
在我的spring security xml中我定义了以下内容。
<session-management invalid-session-url="/home">
<concurrency-control max-sessions="1" error-if-maximum-exceeded="true" session-registry-ref="sessionRegistry"/>
</session-management>
<beans:bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl"/>
然后我有一个类似休息的控制器来执行注销。
@Controller
@RequestMapping("/api/admin")
public class RestAdminController {
static final Set<SimpleGrantedAuthority> AUTHS = new HashSet<>();
static {
AUTHS.add(new SimpleGrantedAuthority("ROLE_USER"));
}
@Autowired
private SessionRegistry sessionRegistry;
@RequestMapping("/user/logout");
public @ResponseBody String logout(@RequestBody Account account) {
User user = new User(account.getUsername(), "", AUTHS);
List<SessionInformation> infos = sessionRegistry.getAllSessions(u, false);
for(SessionInformation info : infos) {
info.expireNow(); //expire the session
sessionRegistry.removeSessionInformation(info.getSessionId()); //remove session
}
return "ok";
}
}
当我从同一台计算机上测试时,这段代码“有点”有效。假设我们有一个用户USER_A和一个管理员ADMIN_A。
然而,USER_A现在已经登录两次,一次是在chrome中,一次是在firefox中。
关于如何完全无效/销毁USER_A的第一个/上一个登录会话的方法的任何想法,如果他试图访问受保护的页面,Spring安全性会知道,“嘿,这个人的会话无效或已过期,请将他发送到登录页面“?
任何帮助表示赞赏。感谢。
答案 0 :(得分:10)
看起来你几乎已经得到了它,但我认为问题在于你是否过早地从SessionRegistry
删除了这些信息。当用户发出请求时,ConcurrentSessionFilter会对当前会话执行检查,此时,它会注销已过期的会话并使其无效。由于您已经删除了该会话的信息,因此无法找到它并且什么都不做。
尝试删除该行:
sessionRegistry.removeSessionInformation(info.getSessionId());
答案 1 :(得分:0)
您只需修改equals()
和hashCode()
即可。您的代码稍后会运行。这可能会有所帮助:http://blog.trifork.com/2014/02/28/session-timeout-and-concurrent-session-control-with-spring-security-and-spring-mvc/