【发布时间】:2014-04-17 17:26:25
【问题描述】:
我正在使用 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登录APP。
- USER_A 使用 Firefox 登录 APP。他被拒绝,因为用户一次只能有 1 个登录会话。
- ADMIN_A 进入,并调用类似 rest 的服务(上面的代码)以“踢”出 USER_A 的所有会话。
- USER_A 现在可以使用 firefox 登录 APP。
但是,USER_A 现在登录了两次,一次在 chrome 中,一次在 Firefox 中。
- 在 chrome 中刷新 USER_A 的(弹簧安全保护)页面(首次登录)不会强制他被重定向(到登录页面)。
- 在 Firefox 中刷新 USER_A 的受保护页面(第二次登录)也不会强制他被重定向。
关于如何完全无效/销毁 USER_A 的第一个/以前的登录会话的方法的任何想法,这样如果他尝试访问受保护的页面,spring security 就会知道,“嘿,这个人的会话无效或过期,将他发送到登录页面“?
感谢任何帮助。谢谢。
【问题讨论】:
标签: java spring spring-mvc spring-security