Sfoglia il codice sorgente

自定义一个账号最大登录数量

车车 10 mesi fa
parent
commit
f5f394d793

+ 8 - 54
ktg-admin/src/main/java/com/ktg/web/controller/monitor/SysUserOnlineController.java

@@ -1,31 +1,21 @@
 package com.ktg.web.controller.monitor;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
 import com.ktg.common.annotation.Log;
-import com.ktg.common.constant.Constants;
 import com.ktg.common.core.controller.BaseController;
 import com.ktg.common.core.domain.AjaxResult;
-import com.ktg.common.core.domain.model.LoginUser;
 import com.ktg.common.core.page.TableDataInfo;
-import com.ktg.common.core.redis.RedisCache;
 import com.ktg.common.enums.BusinessType;
-import com.ktg.common.utils.StringUtils;
 import com.ktg.system.domain.SysUserOnline;
 import com.ktg.system.service.ISysUserOnlineService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * 在线用户监控
- * 
+ *
  * @author ruoyi
  */
 @RestController
@@ -35,46 +25,11 @@ public class SysUserOnlineController extends BaseController
     @Autowired
     private ISysUserOnlineService userOnlineService;
 
-    @Autowired
-    private RedisCache redisCache;
-
     @PreAuthorize("@ss.hasPermi('monitor:online:list')")
     @GetMapping("/list")
     public TableDataInfo list(String ipaddr, String userName)
     {
-        Collection<String> keys = redisCache.keys(Constants.LOGIN_TOKEN_KEY + "*");
-        List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
-        for (String key : keys)
-        {
-            LoginUser user = redisCache.getCacheObject(key);
-            if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))
-            {
-                if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername()))
-                {
-                    userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
-                }
-            }
-            else if (StringUtils.isNotEmpty(ipaddr))
-            {
-                if (StringUtils.equals(ipaddr, user.getIpaddr()))
-                {
-                    userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
-                }
-            }
-            else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser()))
-            {
-                if (StringUtils.equals(userName, user.getUsername()))
-                {
-                    userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
-                }
-            }
-            else
-            {
-                userOnlineList.add(userOnlineService.loginUserToUserOnline(user));
-            }
-        }
-        Collections.reverse(userOnlineList);
-        userOnlineList.removeAll(Collections.singleton(null));
+        List<SysUserOnline> userOnlineList = userOnlineService.getOnlineList(ipaddr, userName);
         return getDataTable(userOnlineList);
     }
 
@@ -86,7 +41,6 @@ public class SysUserOnlineController extends BaseController
     @DeleteMapping("/{tokenId}")
     public AjaxResult forceLogout(@PathVariable String tokenId)
     {
-        redisCache.deleteObject(Constants.LOGIN_TOKEN_KEY + tokenId);
-        return AjaxResult.success();
+        return AjaxResult.success(userOnlineService.forceLogout(tokenId));
     }
 }

+ 2 - 0
ktg-admin/src/main/resources/application.yml

@@ -17,6 +17,8 @@ ktg-mes:
   addressEnabled: true
   # 验证码类型 math 数组计算 char 字符验证
   captchaType: math
+  # 一个账号允许的同时在线数量,设置为0/null时表示无限制
+  onlineMax: 10
 
 # 开发环境配置
 server:

+ 21 - 17
ktg-framework/src/main/java/com/ktg/framework/web/service/SysLoginService.java

@@ -1,15 +1,5 @@
 package com.ktg.framework.web.service;
 
-import javax.annotation.Resource;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.authentication.BadCredentialsException;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.authority.AuthorityUtils;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.stereotype.Component;
 import com.ktg.common.constant.Constants;
 import com.ktg.common.core.domain.entity.SysUser;
 import com.ktg.common.core.domain.model.LoginUser;
@@ -20,13 +10,25 @@ import com.ktg.common.exception.user.CaptchaExpireException;
 import com.ktg.common.exception.user.UserPasswordNotMatchException;
 import com.ktg.common.utils.DateUtils;
 import com.ktg.common.utils.MessageUtils;
-import com.ktg.common.utils.StringUtils;
 import com.ktg.common.utils.ServletUtils;
+import com.ktg.common.utils.StringUtils;
 import com.ktg.common.utils.ip.IpUtils;
 import com.ktg.framework.manager.AsyncManager;
 import com.ktg.framework.manager.factory.AsyncFactory;
 import com.ktg.system.service.ISysConfigService;
+import com.ktg.system.service.ISysUserOnlineService;
 import com.ktg.system.service.ISysUserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
 
 /**
  * 登录校验方法
@@ -38,22 +40,21 @@ public class SysLoginService
 {
     @Autowired
     private TokenService tokenService;
-
     @Resource
     private AuthenticationManager authenticationManager;
-
     @Autowired
     private RedisCache redisCache;
-
     @Autowired
     private ISysUserService userService;
-
     @Autowired
     private ISysConfigService configService;
-
+    @Autowired
+    private ISysUserOnlineService userOnlineService;
     @Resource
     private SysPermissionService permissionService;
 
+
+
     /**
      * 登录验证
      *
@@ -96,7 +97,10 @@ public class SysLoginService
         LoginUser loginUser = (LoginUser) authentication.getPrincipal();
         recordLoginInfo(loginUser.getUserId());
         // 生成token
-        return tokenService.createToken(loginUser);
+        String token = tokenService.createToken(loginUser);
+        // 清理多余的登录者
+        userOnlineService.forceLogoutByName(username);
+        return token;
     }
 
     public String loginWithoutPassword(SysUser sysUser) {

+ 14 - 0
ktg-system/src/main/java/com/ktg/system/service/ISysUserOnlineService.java

@@ -3,6 +3,8 @@ package com.ktg.system.service;
 import com.ktg.common.core.domain.model.LoginUser;
 import com.ktg.system.domain.SysUserOnline;
 
+import java.util.List;
+
 /**
  * 在线用户 服务层
  *
@@ -45,4 +47,16 @@ public interface ISysUserOnlineService
      * @return 在线用户
      */
     public SysUserOnline loginUserToUserOnline(LoginUser user);
+
+    List<SysUserOnline> getOnlineList(String ipaddr, String userName);
+
+    Boolean forceLogout(String tokenId);
+
+    /**
+     * 根据登录名清除多余的登录地
+     * @param userName
+     * @return
+     */
+    Boolean forceLogoutByName(String userName);
+
 }

+ 77 - 1
ktg-system/src/main/java/com/ktg/system/service/impl/SysUserOnlineServiceImpl.java

@@ -1,10 +1,17 @@
 package com.ktg.system.service.impl;
 
-import org.springframework.stereotype.Service;
+import com.ktg.common.constant.Constants;
 import com.ktg.common.core.domain.model.LoginUser;
+import com.ktg.common.core.redis.RedisCache;
 import com.ktg.common.utils.StringUtils;
 import com.ktg.system.domain.SysUserOnline;
 import com.ktg.system.service.ISysUserOnlineService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * 在线用户 服务层处理
@@ -14,6 +21,13 @@ import com.ktg.system.service.ISysUserOnlineService;
 @Service
 public class SysUserOnlineServiceImpl implements ISysUserOnlineService
 {
+
+    @Autowired
+    private RedisCache redisCache;
+    // 获取单个账号在线最大数量
+    @Value("${ktg-mes.onlineMax}")
+    private Integer onlineMax;
+
     /**
      * 通过登录地址查询信息
      *
@@ -93,4 +107,66 @@ public class SysUserOnlineServiceImpl implements ISysUserOnlineService
         }
         return sysUserOnline;
     }
+
+    @Override
+    public List<SysUserOnline> getOnlineList(String ipaddr, String userName) {
+        Collection<String> keys = redisCache.keys(Constants.LOGIN_TOKEN_KEY + "*");
+        List<SysUserOnline> userOnlineList = new ArrayList<>();
+        for (String key : keys)
+        {
+            LoginUser user = redisCache.getCacheObject(key);
+            if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))
+            {
+                if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername()))
+                {
+                    userOnlineList.add(selectOnlineByInfo(ipaddr, userName, user));
+                }
+            }
+            else if (StringUtils.isNotEmpty(ipaddr))
+            {
+                if (StringUtils.equals(ipaddr, user.getIpaddr()))
+                {
+                    userOnlineList.add(selectOnlineByIpaddr(ipaddr, user));
+                }
+            }
+            else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser()))
+            {
+                if (StringUtils.equals(userName, user.getUsername()))
+                {
+                    userOnlineList.add(selectOnlineByUserName(userName, user));
+                }
+            }
+            else
+            {
+                userOnlineList.add(loginUserToUserOnline(user));
+            }
+        }
+        Collections.reverse(userOnlineList);
+        userOnlineList.removeAll(Collections.singleton(null));
+        // 进行登陆时间排序,越早登录越在前,不用判断空指针,因为至少当前用户在线
+        userOnlineList = userOnlineList.stream().sorted(Comparator.comparingLong(SysUserOnline::getLoginTime)).collect(Collectors.toList());
+        return userOnlineList;
+    }
+
+    @Override
+    public Boolean forceLogout(String tokenId) {
+        return redisCache.deleteObject(Constants.LOGIN_TOKEN_KEY + tokenId);
+    }
+
+    @Override
+    public Boolean forceLogoutByName(String userName) {
+        // 获取当前登陆的数据,返回的数据已经根据时间排序好了
+        List<SysUserOnline> onlineList = getOnlineList(null, userName);
+        // 判断当前的账号是否超过限制,超过了,就把最近没活跃的账号清理掉
+        if (onlineMax != null && onlineMax != 0 && onlineList.size() > onlineMax) {
+            // 找到对应的开始强制下线删除
+            int forceNum = onlineList.size() - onlineMax;
+            for (int i = 0; i < forceNum; i++) {
+                forceLogout(onlineList.get(i).getTokenId());
+            }
+        }
+        return true;
+    }
+
+
 }