first commit
This commit is contained in:
10
pom.xml
10
pom.xml
@ -127,6 +127,11 @@
|
|||||||
<artifactId>qiaoba-module-file</artifactId>
|
<artifactId>qiaoba-module-file</artifactId>
|
||||||
<version>${qiaoba.version}</version>
|
<version>${qiaoba.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.qiaoba</groupId>
|
||||||
|
<artifactId>qiaoba-module-monitor</artifactId>
|
||||||
|
<version>${qiaoba.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.qiaoba</groupId>
|
<groupId>com.qiaoba</groupId>
|
||||||
<artifactId>qiaoba-common-base</artifactId>
|
<artifactId>qiaoba-common-base</artifactId>
|
||||||
@ -157,6 +162,11 @@
|
|||||||
<artifactId>qiaoba-common-poi</artifactId>
|
<artifactId>qiaoba-common-poi</artifactId>
|
||||||
<version>${qiaoba.version}</version>
|
<version>${qiaoba.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.qiaoba</groupId>
|
||||||
|
<artifactId>qiaoba-api-auth</artifactId>
|
||||||
|
<version>${qiaoba.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.qiaoba</groupId>
|
<groupId>com.qiaoba</groupId>
|
||||||
<artifactId>qiaoba-common-redis</artifactId>
|
<artifactId>qiaoba-common-redis</artifactId>
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
<module>qiaoba-api-system</module>
|
<module>qiaoba-api-system</module>
|
||||||
<module>qiaoba-api-job</module>
|
<module>qiaoba-api-job</module>
|
||||||
<module>qiaoba-api-file</module>
|
<module>qiaoba-api-file</module>
|
||||||
|
<module>qiaoba-api-auth</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
|
|
||||||
|
21
qiaoba-apis/qiaoba-api-auth/pom.xml
Normal file
21
qiaoba-apis/qiaoba-api-auth/pom.xml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>qiaoba-apis</artifactId>
|
||||||
|
<groupId>com.qiaoba</groupId>
|
||||||
|
<version>1.0</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>qiaoba-api-auth</artifactId>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- Spring Security -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@ -1,9 +1,10 @@
|
|||||||
package com.qiaoba.api.system.service;
|
package com.qiaoba.api.auth.service;
|
||||||
|
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SysUserDetails 暴露接口
|
* SysUserDetails 暴露接口
|
||||||
|
*
|
||||||
* @author ailanyin
|
* @author ailanyin
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 2023/5/19 17:17
|
* @since 2023/5/19 17:17
|
||||||
@ -16,5 +17,13 @@ public interface SysUserDetailsApiService {
|
|||||||
* @param username username
|
* @param username username
|
||||||
* @return UserDetails
|
* @return UserDetails
|
||||||
*/
|
*/
|
||||||
UserDetails toCache(String username);
|
UserDetails toCache(String username, String deviceSn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从缓存中删除
|
||||||
|
*
|
||||||
|
* @param username username
|
||||||
|
* @param deviceSn deviceSn
|
||||||
|
*/
|
||||||
|
void deleteCache(String username, String deviceSn);
|
||||||
}
|
}
|
@ -24,10 +24,6 @@
|
|||||||
<groupId>jakarta.validation</groupId>
|
<groupId>jakarta.validation</groupId>
|
||||||
<artifactId>jakarta.validation-api</artifactId>
|
<artifactId>jakarta.validation-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.qiaoba</groupId>
|
|
||||||
<artifactId>qiaoba-auth</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.qiaoba</groupId>
|
<groupId>com.qiaoba</groupId>
|
||||||
<artifactId>qiaoba-common-poi</artifactId>
|
<artifactId>qiaoba-common-poi</artifactId>
|
||||||
|
@ -12,6 +12,10 @@
|
|||||||
<artifactId>qiaoba-application</artifactId>
|
<artifactId>qiaoba-application</artifactId>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.qiaoba</groupId>
|
||||||
|
<artifactId>qiaoba-module-monitor</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.qiaoba</groupId>
|
<groupId>com.qiaoba</groupId>
|
||||||
<artifactId>qiaoba-module-system</artifactId>
|
<artifactId>qiaoba-module-system</artifactId>
|
||||||
|
@ -3,9 +3,9 @@ qiaoba:
|
|||||||
datasource:
|
datasource:
|
||||||
master:
|
master:
|
||||||
driver: com.mysql.cj.jdbc.Driver
|
driver: com.mysql.cj.jdbc.Driver
|
||||||
url: jdbc:mysql://localhost:3306/qiaoba-boot?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowMultiQueries=true
|
url: jdbc:mysql://120.79.217.22:3306/qiaoba-boot?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowMultiQueries=true
|
||||||
username: root
|
username: root
|
||||||
password: root
|
password: FeyZ7xZr6JtuKibm
|
||||||
pool:
|
pool:
|
||||||
init: 5 #连接池初始化大小
|
init: 5 #连接池初始化大小
|
||||||
min: 10 #最小空闲连接数
|
min: 10 #最小空闲连接数
|
||||||
|
@ -12,10 +12,9 @@
|
|||||||
<artifactId>qiaoba-auth</artifactId>
|
<artifactId>qiaoba-auth</artifactId>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<!-- Spring Security -->
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>com.qiaoba</groupId>
|
||||||
<artifactId>spring-boot-starter-security</artifactId>
|
<artifactId>qiaoba-api-auth</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- common-base -->
|
<!-- common-base -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -64,7 +64,8 @@ public class LoginUser implements UserDetails {
|
|||||||
public LoginUser() {
|
public LoginUser() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoginUser(String userId, String deptId, String username, String nickname, List<RoleDto> roles, List<String> roleKeys, Set<String> permissions) {
|
public LoginUser(String deviceSn, String userId, String deptId, String username, String nickname, List<RoleDto> roles, List<String> roleKeys, Set<String> permissions) {
|
||||||
|
this.deviceSn = deviceSn;
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
this.deptId = deptId;
|
this.deptId = deptId;
|
||||||
this.username = username;
|
this.username = username;
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package com.qiaoba.auth.entity;
|
package com.qiaoba.auth.entity;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -13,6 +15,8 @@ import java.util.Date;
|
|||||||
* @since 2023/5/25 17:05
|
* @since 2023/5/25 17:05
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
public class OnlineUser implements Serializable {
|
public class OnlineUser implements Serializable {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
@ -26,6 +26,11 @@ public class SecurityUser implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private String userId;
|
private String userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备SN
|
||||||
|
*/
|
||||||
|
private String deviceSn;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 部门ID
|
* 部门ID
|
||||||
*/
|
*/
|
||||||
|
@ -6,6 +6,7 @@ import com.qiaoba.auth.entity.OnlineUser;
|
|||||||
import com.qiaoba.auth.properties.AuthConfigProperties;
|
import com.qiaoba.auth.properties.AuthConfigProperties;
|
||||||
import com.qiaoba.auth.service.OnlineUserService;
|
import com.qiaoba.auth.service.OnlineUserService;
|
||||||
import com.qiaoba.auth.utils.TokenUtil;
|
import com.qiaoba.auth.utils.TokenUtil;
|
||||||
|
import com.qiaoba.common.redis.service.RedisService;
|
||||||
import com.qiaoba.common.web.utils.ResponseUtil;
|
import com.qiaoba.common.web.utils.ResponseUtil;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
@ -33,6 +34,7 @@ import java.util.Objects;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
|
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
|
private final RedisService redisService;
|
||||||
private final UserDetailsService userDetailsService;
|
private final UserDetailsService userDetailsService;
|
||||||
private final OnlineUserService onlineUserService;
|
private final OnlineUserService onlineUserService;
|
||||||
private final AuthConfigProperties authConfigProperties;
|
private final AuthConfigProperties authConfigProperties;
|
||||||
@ -51,17 +53,22 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
|
|||||||
String authHeader = request.getHeader(SecurityConstant.TOKEN_HEADER);
|
String authHeader = request.getHeader(SecurityConstant.TOKEN_HEADER);
|
||||||
if (StrUtil.isNotBlank(authHeader) && authHeader.startsWith(SecurityConstant.TOKEN_HEAD)) {
|
if (StrUtil.isNotBlank(authHeader) && authHeader.startsWith(SecurityConstant.TOKEN_HEAD)) {
|
||||||
String authToken = authHeader.substring(SecurityConstant.TOKEN_HEAD.length());
|
String authToken = authHeader.substring(SecurityConstant.TOKEN_HEAD.length());
|
||||||
// todo
|
String username = authToken.split(":")[0];
|
||||||
/* String username1 = "admin";
|
String deviceSn = authToken.split(":")[1];
|
||||||
OnlineUser onlineUser = onlineUserService.selectByUsername(username1);
|
|
||||||
if (Objects.isNull(onlineUser)) {
|
if (!"/logout".equals(request.getRequestURI())) {
|
||||||
ResponseUtil.errorAuth(response, 4011, "暂无登录");
|
if (redisService.hasKey(SecurityConstant.LOGGED_USER_REDIS_KEY + username)) {
|
||||||
|
if (!onlineUserService.checkIsLastLogged(username, deviceSn)) {
|
||||||
|
ResponseUtil.errorAuth(response, 4012, "被挤下线");
|
||||||
|
onlineUserService.deleteOne(username, deviceSn);
|
||||||
return;
|
return;
|
||||||
}*/
|
}
|
||||||
// 续期有效期
|
} else {
|
||||||
//onlineUserService.insert(onlineUser);
|
ResponseUtil.errorAuth(response, 4011, "登陆过期");
|
||||||
if (TokenUtil.validateToken(authToken)) {
|
return;
|
||||||
String username = TokenUtil.getUserNameFromToken(authToken);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||||
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
|
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
|
||||||
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
|
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
|
||||||
@ -69,7 +76,6 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
|
|||||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
chain.doFilter(request, response);
|
chain.doFilter(request, response);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.qiaoba.auth.handler;
|
package com.qiaoba.auth.handler;
|
||||||
|
|
||||||
import com.qiaoba.auth.constants.SecurityConstant;
|
|
||||||
import com.qiaoba.auth.entity.LoginUser;
|
import com.qiaoba.auth.entity.LoginUser;
|
||||||
import com.qiaoba.auth.service.OnlineUserService;
|
import com.qiaoba.auth.service.OnlineUserService;
|
||||||
import com.qiaoba.common.redis.service.RedisService;
|
import com.qiaoba.common.redis.service.RedisService;
|
||||||
@ -32,7 +31,6 @@ public class LogoutHandler implements LogoutSuccessHandler {
|
|||||||
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
|
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
|
||||||
// 删除缓存中的用户信息
|
// 删除缓存中的用户信息
|
||||||
LoginUser user = (LoginUser) authentication.getPrincipal();
|
LoginUser user = (LoginUser) authentication.getPrincipal();
|
||||||
redisService.del(SecurityConstant.USER_DETAILS_REDIS_KEY + user.getUsername());
|
|
||||||
onlineUserService.deleteOne(user.getUsername(), user.getDeviceSn());
|
onlineUserService.deleteOne(user.getUsername(), user.getDeviceSn());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,5 +52,12 @@ public interface OnlineUserService {
|
|||||||
*/
|
*/
|
||||||
List<OnlineUser> selectList(String username);
|
List<OnlineUser> selectList(String username);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查设备是否是最新登陆的设备
|
||||||
|
*
|
||||||
|
* @param username username
|
||||||
|
* @param deviceSn deviceSn
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
Boolean checkIsLastLogged(String username, String deviceSn);
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
package com.qiaoba.auth.service.impl;
|
package com.qiaoba.auth.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.qiaoba.api.auth.service.SysUserDetailsApiService;
|
||||||
import com.qiaoba.auth.constants.SecurityConstant;
|
import com.qiaoba.auth.constants.SecurityConstant;
|
||||||
import com.qiaoba.auth.entity.OnlineUser;
|
import com.qiaoba.auth.entity.OnlineUser;
|
||||||
import com.qiaoba.auth.service.OnlineUserService;
|
import com.qiaoba.auth.service.OnlineUserService;
|
||||||
import com.qiaoba.auth.utils.TokenUtil;
|
import com.qiaoba.auth.utils.TokenUtil;
|
||||||
|
import com.qiaoba.common.base.constants.BaseConstant;
|
||||||
import com.qiaoba.common.redis.service.RedisService;
|
import com.qiaoba.common.redis.service.RedisService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -24,29 +27,34 @@ import java.util.List;
|
|||||||
public class OnlineUserServiceImpl implements OnlineUserService {
|
public class OnlineUserServiceImpl implements OnlineUserService {
|
||||||
|
|
||||||
private final RedisService redisService;
|
private final RedisService redisService;
|
||||||
|
private final SysUserDetailsApiService sysUserDetailsApiService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void insert(OnlineUser onlineUser) {
|
public void insert(OnlineUser onlineUser) {
|
||||||
// key: username
|
// key: username:deviceSn
|
||||||
// hashKey: deviceSn
|
|
||||||
// value: onlineUser
|
// value: onlineUser
|
||||||
redisService.hSet(handleKey(onlineUser.getUsername()), onlineUser.getDeviceSn(), onlineUser, TokenUtil.expireTime * 3600);
|
redisService.set(handleKey(onlineUser.getUsername(), onlineUser.getDeviceSn()), onlineUser, TokenUtil.expireTime * 3600);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteOne(String username, String deviceSn) {
|
public void deleteOne(String username, String deviceSn) {
|
||||||
redisService.hDel(handleKey(username), deviceSn);
|
if (deviceSn.equals(redisService.get(SecurityConstant.LOGGED_USER_REDIS_KEY + username))) {
|
||||||
|
redisService.del(SecurityConstant.LOGGED_USER_REDIS_KEY + username);
|
||||||
|
}
|
||||||
|
sysUserDetailsApiService.deleteCache(username, deviceSn);
|
||||||
|
redisService.del(handleKey(username, deviceSn));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteAll(String username) {
|
public void deleteAll(String username) {
|
||||||
redisService.del(handleKey(username));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OnlineUser selectOne(String username, String deviceSn) {
|
public OnlineUser selectOne(String username, String deviceSn) {
|
||||||
if (redisService.hHasKey(username, deviceSn)) {
|
String key = handleKey(username, deviceSn);
|
||||||
return redisService.hGetObject(username, deviceSn, OnlineUser.class);
|
if (redisService.hasKey(key)) {
|
||||||
|
return redisService.getObject(key, OnlineUser.class);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -58,13 +66,22 @@ public class OnlineUserServiceImpl implements OnlineUserService {
|
|||||||
key = key + username + "*";
|
key = key + username + "*";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (redisService.hasKey(key)) {
|
List<OnlineUser> users = new ArrayList<>();
|
||||||
return redisService.getObjectList(key, OnlineUser.class);
|
Collection<String> keys = redisService.getKeys(key);
|
||||||
|
for (String temp : keys) {
|
||||||
|
temp = temp.replace("tenant_1:", "");
|
||||||
|
users.add(redisService.getObject(temp, OnlineUser.class));
|
||||||
}
|
}
|
||||||
return Collections.emptyList();
|
return users;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String handleKey(String key) {
|
@Override
|
||||||
return SecurityConstant.ONLINE_USER_REDIS_KEY + key;
|
public Boolean checkIsLastLogged(String username, String deviceSn) {
|
||||||
|
String loggedDevice = redisService.get(SecurityConstant.LOGGED_USER_REDIS_KEY + username).toString();
|
||||||
|
return deviceSn.equals(loggedDevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String handleKey(String key, String deviceSn) {
|
||||||
|
return SecurityConstant.ONLINE_USER_REDIS_KEY + key + BaseConstant.COLON_JOIN_STR + deviceSn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ public class TokenUtil {
|
|||||||
* jwt 加解密密钥,第一次项目启动时创建随机数
|
* jwt 加解密密钥,第一次项目启动时创建随机数
|
||||||
*/
|
*/
|
||||||
public static String secret;
|
public static String secret;
|
||||||
public static Integer expireTime = 1;
|
public static Integer expireTime = 72;
|
||||||
|
|
||||||
public static String generateToken(String username) {
|
public static String generateToken(String username) {
|
||||||
DateTime now = DateTime.now();
|
DateTime now = DateTime.now();
|
||||||
|
@ -24,6 +24,11 @@ public class BaseConstant {
|
|||||||
*/
|
*/
|
||||||
public static final String LINE_JOIN_STR = "|";
|
public static final String LINE_JOIN_STR = "|";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 冒号拼接符号: ':'(英文冒号)
|
||||||
|
*/
|
||||||
|
public static final String COLON_JOIN_STR = ":";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 树的key的命名
|
* 树的key的命名
|
||||||
*/
|
*/
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
<module>qiaoba-module-system</module>
|
<module>qiaoba-module-system</module>
|
||||||
<module>qiaoba-module-job</module>
|
<module>qiaoba-module-job</module>
|
||||||
<module>qiaoba-module-file</module>
|
<module>qiaoba-module-file</module>
|
||||||
|
<module>qiaoba-module-monitor</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
28
qiaoba-modules/qiaoba-module-monitor/pom.xml
Normal file
28
qiaoba-modules/qiaoba-module-monitor/pom.xml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>qiaoba-modules</artifactId>
|
||||||
|
<groupId>com.qiaoba</groupId>
|
||||||
|
<version>1.0</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>qiaoba-module-monitor</artifactId>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.qiaoba</groupId>
|
||||||
|
<artifactId>qiaoba-auth</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.qiaoba</groupId>
|
||||||
|
<artifactId>qiaoba-common-doc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.qiaoba</groupId>
|
||||||
|
<artifactId>qiaoba-common-datasource</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@ -0,0 +1,41 @@
|
|||||||
|
package com.qiaoba.module.monitor.controller;
|
||||||
|
|
||||||
|
import com.qiaoba.auth.service.OnlineUserService;
|
||||||
|
import com.qiaoba.common.base.result.AjaxResult;
|
||||||
|
import com.qiaoba.common.database.entity.TableDataInfo;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在线用户管理 Web层
|
||||||
|
*
|
||||||
|
* @author ailanyin
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2023-05-27 21:59:12
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/monitor/online")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "在线用户管理")
|
||||||
|
public class OnlineUserController {
|
||||||
|
|
||||||
|
private final OnlineUserService onlineUserService;
|
||||||
|
|
||||||
|
@PreAuthorize("hasAuthority('monitor:online:list')")
|
||||||
|
@Operation(summary = "获取列表")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo getList(String username) {
|
||||||
|
return TableDataInfo.build(onlineUserService.selectList(username));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAuthority('monitor:online:forceLogout')")
|
||||||
|
@DeleteMapping("/{username}/{deviceSn}")
|
||||||
|
@Operation(summary = "强退用户")
|
||||||
|
public AjaxResult forceLogout(@PathVariable String username, @PathVariable String deviceSn) {
|
||||||
|
onlineUserService.deleteOne(username, deviceSn);
|
||||||
|
return AjaxResult.success();
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,10 @@
|
|||||||
<groupId>com.qiaoba</groupId>
|
<groupId>com.qiaoba</groupId>
|
||||||
<artifactId>qiaoba-api-system</artifactId>
|
<artifactId>qiaoba-api-system</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.qiaoba</groupId>
|
||||||
|
<artifactId>qiaoba-api-auth</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.qiaoba</groupId>
|
<groupId>com.qiaoba</groupId>
|
||||||
<artifactId>qiaoba-api-file</artifactId>
|
<artifactId>qiaoba-api-file</artifactId>
|
||||||
|
@ -6,10 +6,14 @@ import cn.hutool.core.lang.UUID;
|
|||||||
import cn.hutool.core.thread.ThreadUtil;
|
import cn.hutool.core.thread.ThreadUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.http.useragent.UserAgent;
|
||||||
|
import cn.hutool.http.useragent.UserAgentUtil;
|
||||||
import com.qiaoba.api.system.entity.SysUser;
|
import com.qiaoba.api.system.entity.SysUser;
|
||||||
import com.qiaoba.api.system.entity.dto.LoginDto;
|
import com.qiaoba.api.system.entity.dto.LoginDto;
|
||||||
import com.qiaoba.api.system.service.SysUserDetailsApiService;
|
import com.qiaoba.api.auth.service.SysUserDetailsApiService;
|
||||||
import com.qiaoba.auth.constants.SecurityConstant;
|
import com.qiaoba.auth.constants.SecurityConstant;
|
||||||
|
import com.qiaoba.auth.entity.OnlineUser;
|
||||||
|
import com.qiaoba.auth.service.OnlineUserService;
|
||||||
import com.qiaoba.auth.utils.SecurityUtil;
|
import com.qiaoba.auth.utils.SecurityUtil;
|
||||||
import com.qiaoba.auth.utils.TokenUtil;
|
import com.qiaoba.auth.utils.TokenUtil;
|
||||||
import com.qiaoba.common.base.enums.BaseEnum;
|
import com.qiaoba.common.base.enums.BaseEnum;
|
||||||
@ -22,6 +26,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -40,6 +45,7 @@ public class SysLoginServiceImpl implements SysLoginService {
|
|||||||
private final HttpServletRequest request;
|
private final HttpServletRequest request;
|
||||||
private final SysUserDetailsApiService userDetailsService;
|
private final SysUserDetailsApiService userDetailsService;
|
||||||
private final SysUserService sysUserService;
|
private final SysUserService sysUserService;
|
||||||
|
private final OnlineUserService onlineUserService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Object> getCaptchaImage() {
|
public Map<String, Object> getCaptchaImage() {
|
||||||
@ -70,10 +76,12 @@ public class SysLoginServiceImpl implements SysLoginService {
|
|||||||
validateUser(dto.getUsername(), sysUser);
|
validateUser(dto.getUsername(), sysUser);
|
||||||
// 检验密码
|
// 检验密码
|
||||||
validatePassword(dto.getUsername(), sysUser.getPassword(), dto.getPassword());
|
validatePassword(dto.getUsername(), sysUser.getPassword(), dto.getPassword());
|
||||||
// 缓存user
|
// 缓存在线用户
|
||||||
userDetailsService.toCache(sysUser.getUsername());
|
String deviceSn = cacheOnlineUser(dto.getUsername(), sysUser.getNickname());
|
||||||
|
// 缓存userDetails
|
||||||
|
userDetailsService.toCache(sysUser.getUsername(), deviceSn);
|
||||||
// 生成Token
|
// 生成Token
|
||||||
return TokenUtil.generateToken(sysUser.getUsername());
|
return dto.getUsername() + ":" + deviceSn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validatePassword(String username, String password, String inputPassword) {
|
private void validatePassword(String username, String password, String inputPassword) {
|
||||||
@ -131,4 +139,17 @@ public class SysLoginServiceImpl implements SysLoginService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String cacheOnlineUser(String username, String nickname) {
|
||||||
|
String deviceSn = UUID.fastUUID().toString(true);
|
||||||
|
String ip = IpUtil.getIp(request);
|
||||||
|
String address = IpUtil.getIpAddr(ip);
|
||||||
|
UserAgent userAgent = UserAgentUtil.parse(request.getHeader("User-Agent"));
|
||||||
|
String browser = userAgent.getBrowser().getName() + userAgent.getVersion();
|
||||||
|
String os = userAgent.getOs().getName();
|
||||||
|
|
||||||
|
redisService.set(SecurityConstant.LOGGED_USER_REDIS_KEY + username, deviceSn, TokenUtil.expireTime * 3600);
|
||||||
|
onlineUserService.insert(new OnlineUser(deviceSn, username, nickname, ip, address, browser, os, new Date()));
|
||||||
|
return deviceSn;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
package com.qiaoba.module.system.service.impl;
|
package com.qiaoba.module.system.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.json.JSONUtil;
|
|
||||||
import com.qiaoba.api.system.entity.SysUser;
|
import com.qiaoba.api.system.entity.SysUser;
|
||||||
import com.qiaoba.api.system.service.SysUserDetailsApiService;
|
import com.qiaoba.api.auth.service.SysUserDetailsApiService;
|
||||||
import com.qiaoba.auth.constants.SecurityConstant;
|
import com.qiaoba.auth.constants.SecurityConstant;
|
||||||
import com.qiaoba.auth.entity.LoginUser;
|
import com.qiaoba.auth.entity.LoginUser;
|
||||||
import com.qiaoba.auth.entity.SecurityUser;
|
import com.qiaoba.auth.entity.SecurityUser;
|
||||||
@ -21,6 +20,7 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -44,26 +44,34 @@ public class SysUserDetailsServiceImpl implements UserDetailsService, SysUserDet
|
|||||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||||
if (redisService.hasKey(SecurityConstant.USER_DETAILS_REDIS_KEY + username)) {
|
if (redisService.hasKey(SecurityConstant.USER_DETAILS_REDIS_KEY + username)) {
|
||||||
SecurityUser user = redisService.getObject(SecurityConstant.USER_DETAILS_REDIS_KEY + username, SecurityUser.class);
|
SecurityUser user = redisService.getObject(SecurityConstant.USER_DETAILS_REDIS_KEY + username, SecurityUser.class);
|
||||||
return new LoginUser(user.getUserId(), user.getDeptId(), user.getUsername(), user.getNickname(), user.getRoles(), user.getRoleKeys(), user.getPermissions());
|
return new LoginUser(user.getDeviceSn(), user.getUserId(), user.getDeptId(), user.getUsername(), user.getNickname(), user.getRoles(), user.getRoleKeys(), user.getPermissions());
|
||||||
}
|
}
|
||||||
|
|
||||||
return toCache(username);
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private UserDetails createUserDetails(SysUser user) {
|
private UserDetails createUserDetails(SysUser user, String deviceSn) {
|
||||||
Set<String> perms = sysMenuService.selectPermsByUserId(user.getUserId());
|
Set<String> perms = sysMenuService.selectPermsByUserId(user.getUserId());
|
||||||
List<RoleDto> roles = sysUserRoleService.selectRoleDtoByUserId(user.getUserId(), BaseEnum.NORMAL.getCode());
|
List<RoleDto> roles = sysUserRoleService.selectRoleDtoByUserId(user.getUserId(), BaseEnum.NORMAL.getCode());
|
||||||
List<String> roleKeys = roles.stream().map(RoleDto::getRoleKey).collect(Collectors.toList());
|
List<String> roleKeys = roles.stream().map(RoleDto::getRoleKey).collect(Collectors.toList());
|
||||||
return new LoginUser(user.getUserId(), user.getDeptId(), user.getUsername(), user.getNickname(), roles, roleKeys, perms);
|
return new LoginUser(deviceSn, user.getUserId(), user.getDeptId(), user.getUsername(), user.getNickname(), roles, roleKeys, perms);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserDetails toCache(String username) {
|
public UserDetails toCache(String username, String deviceSn) {
|
||||||
SysUser user = sysUserService.selectByUsername(username);
|
SysUser user = sysUserService.selectByUsername(username);
|
||||||
UserDetails details = createUserDetails(user);
|
UserDetails details = createUserDetails(user, deviceSn);
|
||||||
SecurityUser securityUser = BeanUtil.copyProperties(details, SecurityUser.class);
|
SecurityUser securityUser = BeanUtil.copyProperties(details, SecurityUser.class);
|
||||||
redisService.set(SecurityConstant.USER_DETAILS_REDIS_KEY + username, securityUser, TokenUtil.expireTime * 3600);
|
redisService.set(SecurityConstant.USER_DETAILS_REDIS_KEY + username, securityUser, TokenUtil.expireTime * 3600);
|
||||||
return details;
|
return details;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteCache(String username, String deviceSn) {
|
||||||
|
SecurityUser user = redisService.getObject(SecurityConstant.USER_DETAILS_REDIS_KEY + username, SecurityUser.class);
|
||||||
|
if (Objects.nonNull(user) && deviceSn.equals(user.getDeviceSn())) {
|
||||||
|
redisService.del(SecurityConstant.USER_DETAILS_REDIS_KEY + username);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user