From e235d5aa57314fbad9d30a77bab14bf917edb133 Mon Sep 17 00:00:00 2001 From: RuoYi <yzz_ivy@163.com> Date: 星期五, 11 十月 2019 10:50:47 +0800 Subject: [PATCH] 新增在线用户 --- ruoyi-ui/src/views/monitor/online/index.vue | 120 +++++++++++ ruoyi/src/main/java/com/ruoyi/project/system/service/ISysUserOnlineService.java | 48 ++++ ruoyi/src/main/java/com/ruoyi/framework/security/LoginUser.java | 60 ++++++ ruoyi/src/main/java/com/ruoyi/project/monitor/domain/SysUserOnline.java | 113 +++++++++++ ruoyi-ui/src/api/monitor/online.js | 18 + ruoyi/src/main/java/com/ruoyi/project/monitor/controller/SysUserOnlineController.java | 92 +++++++++ ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysUserOnlineServiceImpl.java | 95 +++++++++ ruoyi/src/main/java/com/ruoyi/framework/redis/RedisCache.java | 11 + ruoyi/src/main/java/com/ruoyi/framework/security/service/TokenService.java | 25 ++ 9 files changed, 577 insertions(+), 5 deletions(-) diff --git a/ruoyi-ui/src/api/monitor/online.js b/ruoyi-ui/src/api/monitor/online.js new file mode 100644 index 0000000..288ebe0 --- /dev/null +++ b/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' + }) +} diff --git a/ruoyi-ui/src/views/monitor/online/index.vue b/ruoyi-ui/src/views/monitor/online/index.vue index 764613a..17104de 100644 --- a/ruoyi-ui/src/views/monitor/online/index.vue +++ b/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> \ No newline at end of file +</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> + diff --git a/ruoyi/src/main/java/com/ruoyi/framework/redis/RedisCache.java b/ruoyi/src/main/java/com/ruoyi/framework/redis/RedisCache.java index a290494..9ec7543 100644 --- a/ruoyi/src/main/java/com/ruoyi/framework/redis/RedisCache.java +++ b/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); + } } diff --git a/ruoyi/src/main/java/com/ruoyi/framework/security/LoginUser.java b/ruoyi/src/main/java/com/ruoyi/framework/security/LoginUser.java index 46afd22..6b2ff09 100644 --- a/ruoyi/src/main/java/com/ruoyi/framework/security/LoginUser.java +++ b/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; diff --git a/ruoyi/src/main/java/com/ruoyi/framework/security/service/TokenService.java b/ruoyi/src/main/java/com/ruoyi/framework/security/service/TokenService.java index 5eafd02..fde9bb2 100644 --- a/ruoyi/src/main/java/com/ruoyi/framework/security/service/TokenService.java +++ b/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); } - + + /** + * 璁剧疆鐢ㄦ埛浠g悊淇℃伅 + * + * @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()); + } + /** * 浠庢暟鎹0鏄庣敓鎴愪护鐗� * diff --git a/ruoyi/src/main/java/com/ruoyi/project/monitor/controller/SysUserOnlineController.java b/ruoyi/src/main/java/com/ruoyi/project/monitor/controller/SysUserOnlineController.java new file mode 100644 index 0000000..5a73019 --- /dev/null +++ b/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(); + } +} diff --git a/ruoyi/src/main/java/com/ruoyi/project/monitor/domain/SysUserOnline.java b/ruoyi/src/main/java/com/ruoyi/project/monitor/domain/SysUserOnline.java new file mode 100644 index 0000000..843148b --- /dev/null +++ b/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; + } +} diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysUserOnlineService.java b/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysUserOnlineService.java new file mode 100644 index 0000000..63a4a3a --- /dev/null +++ b/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); +} diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysUserOnlineServiceImpl.java b/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysUserOnlineServiceImpl.java new file mode 100644 index 0000000..756b20e --- /dev/null +++ b/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; + } +} -- Gitblit v1.9.3