如何使用spring security以编程方式记录用户

Jan*_*yne 6 java spring spring-mvc spring-security

我正在使用spring security v3.1.4.我想要实现的是让管理员能够注销常规用户(使他的会话无效).用户只能在任何给定时间登录一次,但如果他忘记退出,那么当他尝试从其他位置登录时,他将无法登录.所以他会把一张票给管理员和管理员将使他之前登录的所有会话无效(希望只有一个).

在我的web.xml中,我有以下定义.

<listener>
 <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
Run Code Online (Sandbox Code Playgroud)

在我的春天安全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"/>
Run Code Online (Sandbox Code Playgroud)

然后我有一个类似休息的控制器来执行注销.

@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";
 }
}
Run Code Online (Sandbox Code Playgroud)

当我从同一台计算机上测试时,这段代码"kinda"有效.假设我们有一个用户USER_A和一个管理员ADMIN_A.

  • USER_A使用chrome登录APP.
  • USER_A使用firefox登录APP.他被拒绝是因为用户一次只能有1个登录会话.
  • ADMIN_A进入,并调用类似其余的服务(上面的代码)来"踢出"所有USER_A的会话.
  • USER_A现在可以使用firefox登录APP.

但是,USER_A现在登录两次,一次是在chrome中,一次是在firefox中.

  • 在chrome(第一次登录)中刷新USER_A的(弹簧安全保护的)页面不会强制他被重定向(到登录页面).
  • 在firefox中刷新USER_A的受保护页面(第二次登录)也不会强制他被重定向.

关于如何完全无效/销毁USER_A的第一个/上一个登录会话的方法的任何想法,如果他试图访问受保护的页面,春天的安全性会知道,"嘿这个人的会话无效或过期,将他发送到登录页面"?

任何帮助表示赞赏.谢谢.

Sha*_*eep 10

看起来你几乎已经得到了它,但我认为问题在于你是否过早地从信息中删除了信息SessionRegistry.在ConcurrentSessionFilter执行对当用户发出请求的当前会话的检查,并且在这一点上,注销过期会话并使其无效.由于您已经删除了该会话的信息,因此无法找到它并且什么都不做.

尝试删除该行:

sessionRegistry.removeSessionInformation(info.getSessionId());
Run Code Online (Sandbox Code Playgroud)