在后台管理中,我们常常需要查看在线的用户,然后管理用户,比如踢出用户等操作。
在 spring security 同样也可以做到,我们只需要在 HttpSecurity 中配置sessionRegistry,然后就可以在容器中注入SessionRegistry,调用其方法来实现。
一、注入SessionRegistry
SecurityConfig.java
@Override
protected void configure(HttpSecurity http) throws Exception {
http
...(省略其他配置)...
// 配置Session注册器
.sessionRegistry(sessionRegistry());
}
/***
* 注入Session注册器
* 可使用该类获取在线的全部用户
*/
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
二、使用SessionRegistry获取在线用户+踢出用户
package com.miaopasi.securitydemo.controller;
import cn.hutool.core.lang.Console;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.miaopasi.securitydemo.config.security.SysUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 测试工具类
*
* @author lixin
*/
@RestController
public class TestController {
private final SessionRegistry sessionRegistry;
@Autowired
public TestController(SessionRegistry sessionRegistry) {
this.sessionRegistry = sessionRegistry;
}
/*** 获取全部在线用户 **/
@GetMapping("/loginUsers")
public List<Object> loginUsers() {
return sessionRegistry.getAllPrincipals();
}
/*** 踢出指定用户 **/
@PostMapping("kickOut")
public Integer kickOutUser(@RequestParam(name = "username") String username) {
// 1.在全部的登录用户中或者到指定对象
final List<Object> allPrincipals = sessionRegistry.getAllPrincipals();
final List<Object> collect = allPrincipals.stream().filter((item) -> Objects.equals(username, ((SysUser) item).getUsername())).collect(Collectors.toList());
// 2.获取指定对象全部的Session(多登录)
List<SessionInformation> sessions = new ArrayList<>();
collect.forEach((item) -> sessions.addAll(sessionRegistry.getAllSessions(item, false)));
// 3.设置Session过期
sessions.forEach((item)->{
// 立即过期
item.expireNow();
// 移除Session
sessionRegistry.removeSessionInformation(item.getSessionId());
});
// 4.返回清除的记录数
return sessions.size();
}
}
三、测试接口
- 登录用户 user1、user2、user3,然后调用接口
/loginUsers
[
{
"id": 1,
"gmtCreate": "2021-08-07T11:18:21.524+0000",
"gmtModified": null,
"isDelete": false,
"operator": "管理员",
"sort": 0,
"version": null,
"username": "user1",
"password": null,
"status": 0,
"remarks": "测试用户1",
"authorities": [
{
"authority": "guest"
}
],
"enabled": true,
"accountNonExpired": true,
"accountNonLocked": true,
"credentialsNonExpired": true
},
{
"id": 2,
"gmtCreate": "2021-08-07T14:13:18.784+0000",
"gmtModified": null,
"isDelete": false,
"operator": "管理员",
"sort": 0,
"version": null,
"username": "user2",
"password": null,
"status": 0,
"remarks": "测试用户2",
"authorities": [
{
"authority": "guest"
}
],
"enabled": true,
"accountNonExpired": true,
"accountNonLocked": true,
"credentialsNonExpired": true
},
{
"id": 3,
"gmtCreate": "2021-08-07T14:13:38.176+0000",
"gmtModified": null,
"isDelete": false,
"operator": "管理员",
"sort": 0,
"version": null,
"username": "user3",
"password": null,
"status": 0,
"remarks": "测试用户3",
"authorities": [
{
"authority": "guest"
}
],
"enabled": true,
"accountNonExpired": true,
"accountNonLocked": true,
"credentialsNonExpired": true
}
]
- 我们现在调用接口
/kickOut
踢出登录用user2
POST http://127.0.0.1:8080/kickOut
HTTP/1.1 200
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: application/json
Transfer-Encoding: chunked
Date: Sat, 07 Aug 2021 14:17:28 GMT
Keep-Alive: timeout=60
Connection: keep-alive
1
Response code: 200; Time: 24ms; Content length: 1 bytes
- 然后我们在登录了user2的浏览器上刷新
{
"msg": "你的账号已在其他地方登录",
"code": 1000
}