获取在线用户

5/10/2022 安全框架

# Shiro获取在线用户功能

# 1、定义ShiroSessionListener类🐭

/**
 * @version 1.0.0
 * @className: ShiroSessionListener
 * @description:
 * @author: LiJunYi
 * @create: 2022/5/10 14:50
 */
public class ShiroSessionListener implements SessionListener
{

    private final AtomicInteger sessionCount = new AtomicInteger(0);

    @Override
    public void onStart(Session session) {
        sessionCount.incrementAndGet();
    }

    @Override
    public void onStop(Session session) {
        sessionCount.decrementAndGet();
    }

    @Override
    public void onExpiration(Session session) {
        sessionCount.decrementAndGet();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 2、ShiroConfig的配置

# 2.1、Ehcache版本

@Configuration
public class ShiroConfig {
	
	@Bean  
    public SecurityManager securityManager(){  
       DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
       securityManager.setRealm(myShiroRealm());
       securityManager.setRememberMeManager(rememberMeManager());
       securityManager.setCacheManager(ehCacheManager());
       securityManager.setSessionManager(sessionManager());
       return securityManager;  
    }  
    
	@Bean
	public SessionDAO sessionDAO()
    {
        // 注意这块
		MemorySessionDAO sessionDAO = new MemorySessionDAO();
		return sessionDAO;
	}

	@Bean
	public SessionManager sessionManager() {
		DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
		Collection<SessionListener> listeners = new ArrayList<SessionListener>();
		listeners.add(new ShiroSessionListener());
		sessionManager.setSessionListeners(listeners);
		sessionManager.setSessionDAO(sessionDAO());
		return sessionManager;
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 2.2、Redis版本

@Configuration
public class ShiroConfig
{
    @Bean
    public RedisManager redisManager()
    {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(redisHost + ":" + redisPort);
        redisManager.setDatabase(database);
        if (StrUtil.isNotEmpty(password))
        {
            redisManager.setPassword(password);
        }
        redisManager.setTimeout(30 * 60);
        return redisManager;
    }

    @Bean
    public RedisCacheManager redisCacheManager()
    {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        redisCacheManager.setPrincipalIdFieldName("userId");
        return redisCacheManager;
    }

    @Bean
    public RedisSessionDAO sessionDAO()
    {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }

    @Bean
    public SessionManager sessionManager()
    {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        Collection<SessionListener> listeners = new ArrayList<SessionListener>();
        listeners.add(new ShiroSessionListener());
        sessionManager.setSessionListeners(listeners);
        sessionManager.setSessionDAO(sessionDAO());
        return sessionManager;
    }

    @Bean
    public SecurityManager securityManager()
    {
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        securityManager.setRememberMeManager(rememberMeManager());
        securityManager.setCacheManager(redisCacheManager());
        // 注入session manager
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

# 3、定义一个在线用户类😶

@Data
public class UserOnline implements Serializable
{
    private static final long serialVersionUID = -8665498712823783978L;

    private String sessionId;

    private String userId;

    private String username;

    private String host;

    private String ip;

    private String status;

    private Date startTime;

    private Date lastTime;

    private Long timeout;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 4、获取在线用户接口 😧

@RestController
@RequestMapping("user")
public class IndexController {

    @Autowired
    private SessionDAO sessionDAO;

    @RequestMapping("/userOnline/list")
    @ResponseBody
    public List<UserOnline> list() {
        List<UserOnline> list = new ArrayList<>();
        Collection<Session> sessions = sessionDAO.getActiveSessions();
        for (Session session : sessions) {
            UserOnline userOnline = new UserOnline();
            UserInfoModel user = new UserInfoModel();
            SimplePrincipalCollection principalCollection;
            if (session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY) == null) {
                continue;
            } else {
                principalCollection = (SimplePrincipalCollection) session
                        .getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
                user = (UserInfoModel) principalCollection.getPrimaryPrincipal();
                userOnline.setUsername(user.getUserName());
                userOnline.setUserId(user.getUserId().toString());
            }
            userOnline.setSessionId((String) session.getId());
            userOnline.setHost(session.getHost());
            userOnline.setStartTime(session.getStartTimestamp());
            userOnline.setLastTime(session.getLastAccessTime());
            Long timeout = session.getTimeout();
            if (timeout == 0L) {
                userOnline.setStatus("离线");
            } else {
                userOnline.setStatus("在线");
            }
            userOnline.setTimeout(timeout);
            list.add(userOnline);
        }
        return list;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

访问接口获得Json数据

[
  {
    sessionId: "8e4813cb-24e0-4c5c-a2ea-fa62459386db",
    userId: "30",
    username: "吴军",
    host: "0:0:0:0:0:0:0:1",
    ip: null,
    status: "在线",
    startTime: 1652167812026,
    lastTime: 1652167817938,
    timeout: -1000
  },
  {
    sessionId: "398c7caf-92f2-4af3-b506-ba631488af3d",
    userId: "24",
    username: "张三",
    host: "127.0.0.1",
    ip: null,
    status: "在线",
    startTime: 1652167804112,
    lastTime: 1652167808655,
    timeout: -1000
  }
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 3、强制用户下线😬

@RequestMapping("/forceLogout")
@ResponseBody
public boolean forceLogout(String sessionId) {
    Session session = sessionDAO.readSession(sessionId);
    session.setTimeout(0);
    return true;
}
1
2
3
4
5
6
7

最后:代码目前只是为了记录写在Controller里,实际可以根据自己的项目风格写在业务处理层中.

十年
陈奕迅