ruoyi-ui/src/api/monitor/online.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
ruoyi-ui/src/views/monitor/online/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
ruoyi/src/main/java/com/ruoyi/framework/redis/RedisCache.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
ruoyi/src/main/java/com/ruoyi/framework/security/LoginUser.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
ruoyi/src/main/java/com/ruoyi/framework/security/service/TokenService.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
ruoyi/src/main/java/com/ruoyi/project/monitor/controller/SysUserOnlineController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
ruoyi/src/main/java/com/ruoyi/project/monitor/domain/SysUserOnline.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
ruoyi/src/main/java/com/ruoyi/project/system/service/ISysUserOnlineService.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysUserOnlineServiceImpl.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
ruoyi-ui/src/api/monitor/online.js
对比新文件 @@ -0,0 +1,18 @@ import request from '@/utils/request' // 查询在线用户列表 export function list(query) { return request({ url: '/monitor/online/list', method: 'get', params: query }) } // 强退用户 export function forceLogout(tokenId) { return request({ url: '/monitor/online/' + tokenId, method: 'delete' }) } ruoyi-ui/src/views/monitor/online/index.vue
@@ -1,5 +1,121 @@ <template> <div class="app-container"> 在线用户 <el-form :inline="true"> <el-form-item label="登录地址"> <el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable size="small" @keyup.enter.native="handleQuery" /> </el-form-item> <el-form-item label="用户名称"> <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable size="small" @keyup.enter.native="handleQuery" /> </el-form-item> <el-form-item> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> </el-form-item> </el-form> <el-table v-loading="loading" :data="list.slice((pageNum-1)*pageSize,pageNum*pageSize)" style="width: 100%;" > <el-table-column label="序号" type="index" align="center"> <template slot-scope="scope"> <span>{{(pageNum - 1) * pageSize + scope.$index + 1}}</span> </template> </el-table-column> <el-table-column label="会话编号" align="center" prop="tokenId" :show-overflow-tooltip="true" /> <el-table-column label="登录名称" align="center" prop="userName" :show-overflow-tooltip="true" /> <el-table-column label="部门名称" align="center" prop="deptName" /> <el-table-column label="主机" align="center" prop="ipaddr" :show-overflow-tooltip="true" /> <el-table-column label="登录地点" align="center" prop="loginLocation" /> <el-table-column label="浏览器" align="center" prop="browser" /> <el-table-column label="操作系统" align="center" prop="os" /> <el-table-column label="登录时间" align="center" prop="loginTime" width="180"> <template slot-scope="scope"> <span>{{ parseTime(scope.row.loginTime) }}</span> </template> </el-table-column> <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <template slot-scope="scope"> <el-button size="mini" type="text" icon="el-icon-delete" @click="handleForceLogout(scope.row)" v-hasPermi="['monitor:online:forceLogout']" >强退</el-button> </template> </el-table-column> </el-table> <pagination v-show="total>0" :total="total" :page.sync="pageNum" :limit.sync="pageSize" /> </div> </template> </template> <script> import { list, forceLogout } from "@/api/monitor/online"; export default { data() { return { // 遮罩层 loading: true, // 总条数 total: 0, // 表格数据 list: [], pageNum: 1, pageSize: 10, // 查询参数 queryParams: { ipaddr: undefined, userName: undefined } }; }, created() { this.getList(); }, methods: { /** 查询登录日志列表 */ getList() { this.loading = true; list(this.queryParams).then(response => { this.list = response.rows; this.total = response.total; this.loading = false; }); }, /** 搜索按钮操作 */ handleQuery() { this.pageNum = 1; this.getList(); }, /** 强退按钮操作 */ handleForceLogout(row) { this.$confirm('是否确认强退名称为"' + row.userName + '"的数据项?', "警告", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning" }).then(function() { return forceLogout(row.tokenId); }).then(() => { this.getList(); this.msgSuccess("强退成功"); }).catch(function() {}); } } }; </script> ruoyi/src/main/java/com/ruoyi/framework/redis/RedisCache.java
@@ -197,4 +197,15 @@ Map<String, T> map = redisTemplate.opsForHash().entries(key); return map; } /** * 获得缓存的基本对象列表 * * @param pattern 字符串前缀 * @return 对象列表 */ public Collection<String> keys(String pattern) { return redisTemplate.keys(pattern); } } ruoyi/src/main/java/com/ruoyi/framework/security/LoginUser.java
@@ -32,6 +32,26 @@ private Long expireTime; /** * 登录IP地址 */ private String ipaddr; /** * 登录地点 */ private String loginLocation; /** * 浏览器类型 */ private String browser; /** * 操作系统 */ private String os; /** * 权限列表 */ private Set<String> permissions; @@ -130,6 +150,46 @@ this.loginTime = loginTime; } public String getIpaddr() { return ipaddr; } public void setIpaddr(String ipaddr) { this.ipaddr = ipaddr; } public String getLoginLocation() { return loginLocation; } public void setLoginLocation(String loginLocation) { this.loginLocation = loginLocation; } public String getBrowser() { return browser; } public void setBrowser(String browser) { this.browser = browser; } public String getOs() { return os; } public void setOs(String os) { this.os = os; } public Long getExpireTime() { return expireTime; ruoyi/src/main/java/com/ruoyi/framework/security/service/TokenService.java
@@ -9,9 +9,13 @@ import org.springframework.stereotype.Component; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.utils.IdUtils; import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.ip.AddressUtils; import com.ruoyi.common.utils.ip.IpUtils; import com.ruoyi.framework.redis.RedisCache; import com.ruoyi.framework.security.LoginUser; import eu.bitwalker.useragentutils.UserAgent; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; @@ -76,6 +80,7 @@ { String token = IdUtils.fastUUID(); loginUser.setToken(token); setUserAgent(loginUser); refreshToken(loginUser); Map<String, Object> claims = new HashMap<>(); @@ -104,8 +109,7 @@ /** * 刷新令牌有效期 * * @param token 令牌 * @return 令牌 * @param loginUser 登录信息 */ public void refreshToken(LoginUser loginUser) { @@ -115,7 +119,22 @@ String userKey = getTokenKey(loginUser.getToken()); redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES); } /** * 设置用户代理信息 * * @param loginUser 登录信息 */ public void setUserAgent(LoginUser loginUser) { UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent")); String ip = IpUtils.getIpAddr(ServletUtils.getRequest()); loginUser.setIpaddr(ip); loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip)); loginUser.setBrowser(userAgent.getBrowser().getName()); loginUser.setOs(userAgent.getOperatingSystem().getName()); } /** * 从数据声明生成令牌 * ruoyi/src/main/java/com/ruoyi/project/monitor/controller/SysUserOnlineController.java
对比新文件 @@ -0,0 +1,92 @@ package com.ruoyi.project.monitor.controller; 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.ruoyi.common.constant.Constants; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.aspectj.lang.annotation.Log; import com.ruoyi.framework.aspectj.lang.enums.BusinessType; import com.ruoyi.framework.redis.RedisCache; import com.ruoyi.framework.security.LoginUser; import com.ruoyi.framework.web.controller.BaseController; import com.ruoyi.framework.web.domain.AjaxResult; import com.ruoyi.framework.web.page.TableDataInfo; import com.ruoyi.project.monitor.domain.SysUserOnline; import com.ruoyi.project.system.service.ISysUserOnlineService; /** * 在线用户监控 * * @author ruoyi */ @RestController @RequestMapping("/monitor/online") 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)); return getDataTable(userOnlineList); } /** * 强退用户 */ @PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')") @Log(title = "在线用户", businessType = BusinessType.DELETE) @DeleteMapping("/{tokenId}") public AjaxResult forceLogout(@PathVariable String tokenId) { redisCache.deleteObject(Constants.LOGIN_TOKEN_KEY + tokenId); return AjaxResult.success(); } } ruoyi/src/main/java/com/ruoyi/project/monitor/domain/SysUserOnline.java
对比新文件 @@ -0,0 +1,113 @@ package com.ruoyi.project.monitor.domain; /** * 当前在线会话 * * @author ruoyi */ public class SysUserOnline { /** 会话编号 */ private String tokenId; /** 部门名称 */ private String deptName; /** 用户名称 */ private String userName; /** 登录IP地址 */ private String ipaddr; /** 登录地址 */ private String loginLocation; /** 浏览器类型 */ private String browser; /** 操作系统 */ private String os; /** 登录时间 */ private Long loginTime; public String getTokenId() { return tokenId; } public void setTokenId(String tokenId) { this.tokenId = tokenId; } public String getDeptName() { return deptName; } public void setDeptName(String deptName) { this.deptName = deptName; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getIpaddr() { return ipaddr; } public void setIpaddr(String ipaddr) { this.ipaddr = ipaddr; } public String getLoginLocation() { return loginLocation; } public void setLoginLocation(String loginLocation) { this.loginLocation = loginLocation; } public String getBrowser() { return browser; } public void setBrowser(String browser) { this.browser = browser; } public String getOs() { return os; } public void setOs(String os) { this.os = os; } public Long getLoginTime() { return loginTime; } public void setLoginTime(Long loginTime) { this.loginTime = loginTime; } } ruoyi/src/main/java/com/ruoyi/project/system/service/ISysUserOnlineService.java
对比新文件 @@ -0,0 +1,48 @@ package com.ruoyi.project.system.service; import com.ruoyi.framework.security.LoginUser; import com.ruoyi.project.monitor.domain.SysUserOnline; /** * 在线用户 服务层 * * @author ruoyi */ public interface ISysUserOnlineService { /** * 通过登录地址查询信息 * * @param ipaddr 登录地址 * @param user 用户信息 * @return 在线用户信息 */ public SysUserOnline selectOnlineByIpaddr(String ipaddr, LoginUser user); /** * 通过用户名称查询信息 * * @param userName 用户名称 * @param user 用户信息 * @return 在线用户信息 */ public SysUserOnline selectOnlineByUserName(String userName, LoginUser user); /** * 通过登录地址/用户名称查询信息 * * @param ipaddr 登录地址 * @param userName 用户名称 * @param user 用户信息 * @return 在线用户信息 */ public SysUserOnline selectOnlineByInfo(String ipaddr, String userName, LoginUser user); /** * 设置在线用户信息 * * @param user 用户信息 * @return 在线用户 */ public SysUserOnline loginUserToUserOnline(LoginUser user); } ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysUserOnlineServiceImpl.java
对比新文件 @@ -0,0 +1,95 @@ package com.ruoyi.project.system.service.impl; import org.springframework.stereotype.Service; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.security.LoginUser; import com.ruoyi.project.monitor.domain.SysUserOnline; import com.ruoyi.project.system.service.ISysUserOnlineService; /** * 在线用户 服务层处理 * * @author ruoyi */ @Service public class SysUserOnlineServiceImpl implements ISysUserOnlineService { /** * 通过登录地址查询信息 * * @param ipaddr 登录地址 * @param user 用户信息 * @return 在线用户信息 */ @Override public SysUserOnline selectOnlineByIpaddr(String ipaddr, LoginUser user) { if (StringUtils.equals(ipaddr, user.getIpaddr())) { return loginUserToUserOnline(user); } return null; } /** * 通过用户名称查询信息 * * @param userName 用户名称 * @param user 用户信息 * @return 在线用户信息 */ @Override public SysUserOnline selectOnlineByUserName(String userName, LoginUser user) { if (StringUtils.equals(userName, user.getUsername())) { return loginUserToUserOnline(user); } return null; } /** * 通过登录地址/用户名称查询信息 * * @param ipaddr 登录地址 * @param userName 用户名称 * @param user 用户信息 * @return 在线用户信息 */ @Override public SysUserOnline selectOnlineByInfo(String ipaddr, String userName, LoginUser user) { if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername())) { return loginUserToUserOnline(user); } return null; } /** * 设置在线用户信息 * * @param user 用户信息 * @return 在线用户 */ public SysUserOnline loginUserToUserOnline(LoginUser user) { if (StringUtils.isNull(user) && StringUtils.isNull(user.getUser())) { return null; } SysUserOnline sysUserOnline = new SysUserOnline(); sysUserOnline.setTokenId(user.getToken()); sysUserOnline.setUserName(user.getUsername()); sysUserOnline.setIpaddr(user.getIpaddr()); sysUserOnline.setLoginLocation(user.getLoginLocation()); sysUserOnline.setBrowser(user.getBrowser()); sysUserOnline.setOs(user.getOs()); sysUserOnline.setLoginTime(user.getLoginTime()); if (StringUtils.isNotNull(user.getUser().getDept())) { sysUserOnline.setDeptName(user.getUser().getDept().getDeptName()); } return sysUserOnline; } }