Parcourir la source

修改 在线用户逻辑

guoenzhou il y a 2 ans
Parent
commit
32af5d1f6e

+ 11 - 1
base-components/gateway/src/main/java/com/ruoyi/gateway/filter/AuthFilter.java

@@ -21,6 +21,8 @@ import com.ruoyi.gateway.config.properties.IgnoreWhiteProperties;
 import io.jsonwebtoken.Claims;
 import reactor.core.publisher.Mono;
 
+import javax.servlet.http.HttpServletRequest;
+
 /**
  * 网关鉴权
  * 
@@ -72,6 +74,7 @@ public class AuthFilter implements GlobalFilter, Ordered
         {
             return unauthorizedResponse(exchange, "令牌验证失败");
         }
+        log.info("{} access {}, userId:{},userName:{},userKey:{},",request.getRemoteAddress(),request.getMethod(),userid,username,userkey);
 
         // 设置用户信息到请求
         String tenantId = JwtUtils.getTenantId(claims);
@@ -84,7 +87,14 @@ public class AuthFilter implements GlobalFilter, Ordered
         return chain.filter(exchange.mutate().request(mutate.build()).build());
     }
 
-    private void addHeader(ServerHttpRequest.Builder mutate, String name, Object value)
+    private String buildAccessInfo(HttpServletRequest request, String token) {
+        String servletPath = request.getServletPath();
+        String method = request.getMethod();
+        String remoteHost = request.getRemoteHost();
+        return "[" + remoteHost + "]" + " access '" + method + " " + servletPath + "' with token: " + token;
+    }
+
+        private void addHeader(ServerHttpRequest.Builder mutate, String name, Object value)
     {
         if (value == null)
         {

+ 44 - 0
base-components/gateway/src/main/java/com/ruoyi/gateway/filter/CrosFilter.java

@@ -0,0 +1,44 @@
+package com.ruoyi.gateway.filter;
+import org.springframework.context.annotation.Bean;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.stereotype.Component;
+import org.springframework.web.cors.reactive.CorsUtils;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.WebFilter;
+import org.springframework.web.server.WebFilterChain;
+import reactor.core.publisher.Mono;
+
+@Component
+public class CrosFilter {
+    private static final String ALLOWED_HEADERS = "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN,token,username,client, ETag,If-None-Match";
+    private static final String ALLOWED_METHODS = "GET, PUT, POST, DELETE, OPTIONS";
+    private static final String ALLOWED_ORIGIN = "*";
+    private static final String MAX_AGE = "18000L";
+
+    @Bean
+    public WebFilter corsFilter() {
+        return (ServerWebExchange ctx, WebFilterChain chain) -> {
+            ServerHttpRequest request = ctx.getRequest();
+            //允许所有请求跨域
+//            if (CorsUtils.isCorsRequest(request)) {
+                ServerHttpResponse response = ctx.getResponse();
+                HttpHeaders headers = response.getHeaders();
+                headers.add("Access-Control-Allow-Origin", "*");
+                headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
+                headers.add("Access-Control-Max-Age", MAX_AGE);
+                headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
+                headers.add("Access-Control-Expose-Headers", "ETag");
+                headers.add("Access-Control-Allow-Credentials", "true");
+                if (request.getMethod() == HttpMethod.OPTIONS) {
+                    response.setStatusCode(HttpStatus.OK);
+                    return Mono.empty();
+                }
+//            }
+            return chain.filter(ctx);
+        };
+    }
+}

+ 7 - 3
base-components/gateway/src/main/resources/logback.xml

@@ -59,14 +59,18 @@
     </appender>
 
     <!-- 系统模块日志级别控制  -->
-	<logger name="com.ruoyi" level="info" />
+<!--	<logger name="com.ruoyi" level="info" />-->
 	<!-- Spring日志级别控制  -->
-	<logger name="org.springframework" level="warn" />
+<!--	<logger name="org.springframework" level="warn" />-->
 
 
+    <root level="debug">
+        <appender-ref ref="console"/>
+    </root>
+
 	<!--系统操作日志-->
     <root level="info">
-        <appender-ref ref="CONSOLE"/>
+        <appender-ref ref="console"/>
         <appender-ref ref="file_info" />
         <appender-ref ref="file_error" />
     </root>

+ 10 - 0
base-modules/service-system/service-system-api/src/main/java/com/usky/system/model/LoginUser.java

@@ -63,6 +63,16 @@ public class LoginUser implements Serializable
     /** 租户ID */
     private Integer tenantId;
 
+    private String userType;
+
+    public String getUserType() {
+        return userType;
+    }
+
+    public void setUserType(String userType) {
+        this.userType = userType;
+    }
+
     public Integer getTenantId()
     {
         return tenantId;

+ 104 - 0
base-modules/service-system/service-system-biz/src/main/java/com/usky/system/controller/web/SysUserOnlineController.java

@@ -0,0 +1,104 @@
+package com.usky.system.controller.web;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import com.usky.common.core.bean.ApiResult;
+import com.usky.common.core.constants.CacheConstants;
+import com.usky.common.log.annotation.Log;
+import com.usky.common.log.enums.BusinessType;
+import com.usky.common.redis.core.RedisService;
+import com.usky.common.security.annotation.RequiresPermissions;
+import com.usky.system.controller.web.page.TableDataInfo;
+import com.usky.system.domain.SysUserOnline;
+import com.usky.system.model.LoginUser;
+import com.usky.system.service.ISysUserOnlineService;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+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.ruoyi.common.core.constant.CacheConstants;
+//import com.ruoyi.common.core.utils.StringUtils;
+//import com.ruoyi.common.core.web.controller.BaseController;
+//import com.ruoyi.common.core.web.domain.AjaxResult;
+//import com.ruoyi.common.core.web.page.TableDataInfo;
+//import com.ruoyi.common.log.annotation.Log;
+//import com.ruoyi.common.log.enums.BusinessType;
+//import com.ruoyi.common.redis.service.RedisService;
+//import com.ruoyi.common.security.annotation.RequiresPermissions;
+//import com.ruoyi.system.api.model.LoginUser;
+//import com.ruoyi.system.domain.SysUserOnline;
+//import com.ruoyi.system.service.ISysUserOnlineService;
+
+/**
+ * 在线用户监控
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/online")
+public class SysUserOnlineController extends BaseController
+{
+    @Autowired
+    private ISysUserOnlineService userOnlineService;
+
+    @Autowired
+    private RedisService redisService;
+
+    @RequiresPermissions("monitor:online:list")
+    @GetMapping("/list")
+    public ApiResult<TableDataInfo> list(String ipaddr, String userName)
+    {
+        Collection<String> keys = redisService.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
+        List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
+        for (String key : keys)
+        {
+            LoginUser user = redisService.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))
+            {
+                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));
+        return ApiResult.success(getDataTable(userOnlineList));
+    }
+
+    /**
+     * 强退用户
+     */
+    @RequiresPermissions("monitor:online:forceLogout")
+    @Log(title = "在线用户", businessType = BusinessType.FORCE)
+    @DeleteMapping("/{tokenId}")
+    public ApiResult forceLogout(@PathVariable String tokenId)
+    {
+        redisService.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId);
+        return ApiResult.success();
+    }
+}

+ 0 - 1
base-modules/service-system/service-system-biz/src/main/resources/bootstrap.yml

@@ -1,7 +1,6 @@
 # Tomcat
 server:
   port: 9886
-
 # Spring
 spring:
   application:

+ 253 - 0
usky-common/usky-common-redis/src/main/java/com/usky/common/redis/core/RedisService.java

@@ -0,0 +1,253 @@
+package com.usky.common.redis.core;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.BoundSetOperations;
+import org.springframework.data.redis.core.HashOperations;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * spring redis 工具类
+ *
+ * @author ruoyi
+ **/
+@SuppressWarnings(value = { "unchecked", "rawtypes" })
+@Component
+public class RedisService
+{
+    @Autowired
+    public RedisTemplate redisTemplate;
+
+    /**
+     * 缓存基本的对象,Integer、String、实体类等
+     *
+     * @param key 缓存的键值
+     * @param value 缓存的值
+     */
+    public <T> void setCacheObject(final String key, final T value)
+    {
+        redisTemplate.opsForValue().set(key, value);
+    }
+
+    /**
+     * 缓存基本的对象,Integer、String、实体类等
+     *
+     * @param key 缓存的键值
+     * @param value 缓存的值
+     * @param timeout 时间
+     * @param timeUnit 时间颗粒度
+     */
+    public <T> void setCacheObject(final String key, final T value, final Long timeout, final TimeUnit timeUnit)
+    {
+        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
+    }
+
+    /**
+     * 设置有效时间
+     *
+     * @param key Redis键
+     * @param timeout 超时时间
+     * @return true=设置成功;false=设置失败
+     */
+    public boolean expire(final String key, final long timeout)
+    {
+        return expire(key, timeout, TimeUnit.SECONDS);
+    }
+
+    /**
+     * 设置有效时间
+     *
+     * @param key Redis键
+     * @param timeout 超时时间
+     * @param unit 时间单位
+     * @return true=设置成功;false=设置失败
+     */
+    public boolean expire(final String key, final long timeout, final TimeUnit unit)
+    {
+        return redisTemplate.expire(key, timeout, unit);
+    }
+
+    /**
+     * 获取有效时间
+     *
+     * @param key Redis键
+     * @return 有效时间
+     */
+    public long getExpire(final String key)
+    {
+        return redisTemplate.getExpire(key);
+    }
+
+    /**
+     * 判断 key是否存在
+     *
+     * @param key 键
+     * @return true 存在 false不存在
+     */
+    public Boolean hasKey(String key)
+    {
+        return redisTemplate.hasKey(key);
+    }
+
+    /**
+     * 获得缓存的基本对象。
+     *
+     * @param key 缓存键值
+     * @return 缓存键值对应的数据
+     */
+    public <T> T getCacheObject(final String key)
+    {
+        ValueOperations<String, T> operation = redisTemplate.opsForValue();
+        return operation.get(key);
+    }
+
+    /**
+     * 删除单个对象
+     *
+     * @param key
+     */
+    public boolean deleteObject(final String key)
+    {
+        return redisTemplate.delete(key);
+    }
+
+    /**
+     * 删除集合对象
+     *
+     * @param collection 多个对象
+     * @return
+     */
+    public long deleteObject(final Collection collection)
+    {
+        return redisTemplate.delete(collection);
+    }
+
+    /**
+     * 缓存List数据
+     *
+     * @param key 缓存的键值
+     * @param dataList 待缓存的List数据
+     * @return 缓存的对象
+     */
+    public <T> long setCacheList(final String key, final List<T> dataList)
+    {
+        Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
+        return count == null ? 0 : count;
+    }
+
+    /**
+     * 获得缓存的list对象
+     *
+     * @param key 缓存的键值
+     * @return 缓存键值对应的数据
+     */
+    public <T> List<T> getCacheList(final String key)
+    {
+        return redisTemplate.opsForList().range(key, 0, -1);
+    }
+
+    /**
+     * 缓存Set
+     *
+     * @param key 缓存键值
+     * @param dataSet 缓存的数据
+     * @return 缓存数据的对象
+     */
+    public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet)
+    {
+        BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
+        Iterator<T> it = dataSet.iterator();
+        while (it.hasNext())
+        {
+            setOperation.add(it.next());
+        }
+        return setOperation;
+    }
+
+    /**
+     * 获得缓存的set
+     *
+     * @param key
+     * @return
+     */
+    public <T> Set<T> getCacheSet(final String key)
+    {
+        return redisTemplate.opsForSet().members(key);
+    }
+
+    /**
+     * 缓存Map
+     *
+     * @param key
+     * @param dataMap
+     */
+    public <T> void setCacheMap(final String key, final Map<String, T> dataMap)
+    {
+        if (dataMap != null) {
+            redisTemplate.opsForHash().putAll(key, dataMap);
+        }
+    }
+
+    /**
+     * 获得缓存的Map
+     *
+     * @param key
+     * @return
+     */
+    public <T> Map<String, T> getCacheMap(final String key)
+    {
+        return redisTemplate.opsForHash().entries(key);
+    }
+
+    /**
+     * 往Hash中存入数据
+     *
+     * @param key Redis键
+     * @param hKey Hash键
+     * @param value 值
+     */
+    public <T> void setCacheMapValue(final String key, final String hKey, final T value)
+    {
+        redisTemplate.opsForHash().put(key, hKey, value);
+    }
+
+    /**
+     * 获取Hash中的数据
+     *
+     * @param key Redis键
+     * @param hKey Hash键
+     * @return Hash中的对象
+     */
+    public <T> T getCacheMapValue(final String key, final String hKey)
+    {
+        HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
+        return opsForHash.get(key, hKey);
+    }
+
+    /**
+     * 获取多个Hash中的数据
+     *
+     * @param key Redis键
+     * @param hKeys Hash键集合
+     * @return Hash对象集合
+     */
+    public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys)
+    {
+        return redisTemplate.opsForHash().multiGet(key, hKeys);
+    }
+
+    /**
+     * 获得缓存的基本对象列表
+     *
+     * @param pattern 字符串前缀
+     * @return 对象列表
+     */
+    public Collection<String> keys(final String pattern)
+    {
+        return redisTemplate.keys(pattern);
+    }
+}