@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.successHandler((req,resp,authentication) -> {
Object principal = authentication.getPrincipal();
PrintWriter out = resp.getWriter();
out.println(JSON.toJSON(principal));
out.flush();
out.close();
})
.and()
.authorizeRequests()
.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/user/**").hasRole("user")
.anyRequest().authenticated()
.and()
.csrf().disable()
.sessionManagement()
.maximumSessions(1)
.maxSessionsPreventsLogin(true); // 配置为true就是一旦用户登录,则不允许其他人登录,使用这个需要配置一个Bean(HttpSessionEventPublisher)
}
@Bean
HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
public class SessionRegistryImpl implements SessionRegistry,
ApplicationListener<SessionDestroyedEvent> {
/** <principal:Object,SessionIdSet> */
private final ConcurrentMap<Object, Set<String>> principals;
/** <sessionId:Object,SessionInformation> */
private final Map<String, SessionInformation> sessionIds;
public void registerNewSession(String sessionId, Object principal) {
if (getSessionInformation(sessionId) != null) {
removeSessionInformation(sessionId);
}
sessionIds.put(sessionId,
new SessionInformation(principal, sessionId, new Date()));
principals.compute(principal, (key, sessionsUsedByPrincipal) -> {
if (sessionsUsedByPrincipal == null) {
sessionsUsedByPrincipal = new CopyOnWriteArraySet<>();
}
sessionsUsedByPrincipal.add(sessionId);
return sessionsUsedByPrincipal;
});
}
public void removeSessionInformation(String sessionId) {
SessionInformation info = getSessionInformation(sessionId);
if (info == null) {
return;
}
sessionIds.remove(sessionId);
principals.computeIfPresent(info.getPrincipal(), (key, sessionsUsedByPrincipal) -> {
sessionsUsedByPrincipal.remove(sessionId);
if (sessionsUsedByPrincipal.isEmpty()) {
sessionsUsedByPrincipal = null;
}
return sessionsUsedByPrincipal;
});
}
}
1.首先一上来声明了一个 principals 对象,这是一个支持并发访问的 map 集合,集合的 key 就是用户的主体(principal),正常来说,用户的 principal 其实就是用户对象
2.如有新的 session 需要添加,就在 registerNewSession 方法中进行添加,具体是调用 principals.compute 方法进行添加,key 就是 principal。
3.如果用户注销登录,sessionid 需要移除,相关操作在 removeSessionInformation 方法中完成,具体也是调用 principals.computeIfPresent 方法,这些关于集合的基本操作我就不再赘述了。
其中的ConcurrentMap 集合的 key 是 principal 对象,用对象做 key,一定要重写 equals 方法和 hashCode 方法,否则第一次存完数据,下次就找不到了。
SpringSecurity之sessionManagement设置maximumSessions无效
原文:https://www.cnblogs.com/cyoking/p/15120209.html