feat: 用户会话后端代码.
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"local": {
|
||||
"baseUrl": "http://127.0.0.1:9200/orion-api",
|
||||
"token": "Bearer YQJ3IpwJJv5HujIWY6ZTNDgUxXRY6aDt"
|
||||
"token": "Bearer YQJ3IpwJJv5HujIWY6ZTNDgUxXRY6aDt",
|
||||
"timestamp": 1689577685914
|
||||
},
|
||||
"gateway": {
|
||||
"baseUrl": "http://127.0.0.1:9200/orion-api",
|
||||
|
||||
@@ -46,11 +46,11 @@ public enum ErrorCode implements CodeInfo {
|
||||
|
||||
// -------------------- 自定义 - 业务 --------------------
|
||||
|
||||
OTHER_DEVICE_LOGIN(700, "该账号于 {} 已在其他设备登录 {}({})"),
|
||||
USER_DISABLED(700, "当前用户已禁用"),
|
||||
|
||||
USER_DISABLED(701, "当前用户已禁用"),
|
||||
USER_LOCKED(701, "当前用户已被锁定"),
|
||||
|
||||
USER_LOCKED(702, "当前用户已被锁定"),
|
||||
OTHER_DEVICE_LOGIN(702, "该账号于 {} 已在其他设备登录 {}({})"),
|
||||
|
||||
// -------------------- 自定义 - 通用 --------------------
|
||||
|
||||
|
||||
@@ -31,6 +31,9 @@ public class LoginUser {
|
||||
@Schema(description = "头像地址")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "登录时间戳")
|
||||
private Long timestamp;
|
||||
|
||||
@Schema(description = "角色")
|
||||
private List<String> roles;
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.orion.lang.define.cache.CacheKeyDefine;
|
||||
import com.orion.lang.utils.Strings;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -83,7 +84,7 @@ public class RedisStrings extends RedisUtils {
|
||||
* @param keys keys
|
||||
* @return cache
|
||||
*/
|
||||
public static List<JSONObject> getJsonList(List<String> keys) {
|
||||
public static List<JSONObject> getJsonList(Collection<String> keys) {
|
||||
List<String> values = redisTemplate.opsForValue().multiGet(keys);
|
||||
if (values == null) {
|
||||
return new ArrayList<>();
|
||||
@@ -101,7 +102,7 @@ public class RedisStrings extends RedisUtils {
|
||||
* @param <T> T
|
||||
* @return cache
|
||||
*/
|
||||
public static <T> List<T> getJsonList(List<String> keys, CacheKeyDefine define) {
|
||||
public static <T> List<T> getJsonList(Collection<String> keys, CacheKeyDefine define) {
|
||||
return getJsonList(keys, (Class<T>) define.getType());
|
||||
}
|
||||
|
||||
@@ -113,7 +114,7 @@ public class RedisStrings extends RedisUtils {
|
||||
* @param <T> T
|
||||
* @return cache
|
||||
*/
|
||||
public static <T> List<T> getJsonList(List<String> keys, Class<T> type) {
|
||||
public static <T> List<T> getJsonList(Collection<String> keys, Class<T> type) {
|
||||
List<String> values = redisTemplate.opsForValue().multiGet(keys);
|
||||
if (values == null) {
|
||||
return new ArrayList<>();
|
||||
@@ -182,7 +183,7 @@ public class RedisStrings extends RedisUtils {
|
||||
* @param keys keys
|
||||
* @return cache
|
||||
*/
|
||||
public static List<JSONArray> getJsonArrayList(List<String> keys) {
|
||||
public static List<JSONArray> getJsonArrayList(Collection<String> keys) {
|
||||
List<String> values = redisTemplate.opsForValue().multiGet(keys);
|
||||
if (values == null) {
|
||||
return new ArrayList<>();
|
||||
@@ -200,7 +201,7 @@ public class RedisStrings extends RedisUtils {
|
||||
* @param <T> T
|
||||
* @return cache
|
||||
*/
|
||||
public static <T> List<List<T>> getJsonArrayList(List<String> keys, CacheKeyDefine define) {
|
||||
public static <T> List<List<T>> getJsonArrayList(Collection<String> keys, CacheKeyDefine define) {
|
||||
return getJsonArrayList(keys, (Class<T>) define.getType());
|
||||
}
|
||||
|
||||
@@ -212,7 +213,7 @@ public class RedisStrings extends RedisUtils {
|
||||
* @param <T> T
|
||||
* @return cache
|
||||
*/
|
||||
public static <T> List<List<T>> getJsonArrayList(List<String> keys, Class<T> type) {
|
||||
public static <T> List<List<T>> getJsonArrayList(Collection<String> keys, Class<T> type) {
|
||||
List<String> values = redisTemplate.opsForValue().multiGet(keys);
|
||||
if (values == null) {
|
||||
return new ArrayList<>();
|
||||
|
||||
@@ -88,6 +88,16 @@ public class SecurityUtils {
|
||||
return loginUser != null ? loginUser.getUsername() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前 timestamp
|
||||
*
|
||||
* @return timestamp
|
||||
*/
|
||||
public static Long getLoginTimestamp() {
|
||||
LoginUser loginUser = getLoginUser();
|
||||
return loginUser != null ? loginUser.getTimestamp() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前用户
|
||||
*
|
||||
|
||||
@@ -30,4 +30,19 @@ Authorization: {{token}}
|
||||
GET {{baseUrl}}/infra/mine/login-history
|
||||
Authorization: {{token}}
|
||||
|
||||
|
||||
### 获取当前用户会话列表
|
||||
GET {{baseUrl}}/infra/mine/user-session
|
||||
Authorization: {{token}}
|
||||
|
||||
|
||||
### 下线当前用户会话
|
||||
PUT {{baseUrl}}/infra/mine/offline-session
|
||||
Content-Type: application/json
|
||||
Authorization: {{token}}
|
||||
|
||||
{
|
||||
"timestamp": 1698774195296
|
||||
}
|
||||
|
||||
###
|
||||
@@ -6,10 +6,12 @@ import com.orion.ops.framework.log.core.annotation.IgnoreLog;
|
||||
import com.orion.ops.framework.log.core.enums.IgnoreLogMode;
|
||||
import com.orion.ops.framework.web.core.annotation.RestWrapper;
|
||||
import com.orion.ops.module.infra.define.operator.AuthenticationOperatorType;
|
||||
import com.orion.ops.module.infra.entity.request.user.OfflineUserSessionRequest;
|
||||
import com.orion.ops.module.infra.entity.request.user.SystemUserUpdateRequest;
|
||||
import com.orion.ops.module.infra.entity.request.user.UserUpdatePasswordRequest;
|
||||
import com.orion.ops.module.infra.entity.vo.LoginHistoryVO;
|
||||
import com.orion.ops.module.infra.entity.vo.SystemUserVO;
|
||||
import com.orion.ops.module.infra.entity.vo.UserSessionVO;
|
||||
import com.orion.ops.module.infra.service.MineService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
@@ -67,4 +69,22 @@ public class MineController {
|
||||
return mineService.getCurrentLoginHistory();
|
||||
}
|
||||
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@GetMapping("/user-session")
|
||||
@Operation(summary = "获取当前用户会话列表")
|
||||
public List<UserSessionVO> getCurrentUserSessionList() {
|
||||
return mineService.getCurrentUserSessionList();
|
||||
}
|
||||
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@PutMapping("/offline-session")
|
||||
@Operation(summary = "下线当前用户会话")
|
||||
public HttpWrapper<?> offlineCurrentUserSession(@Validated @RequestBody OfflineUserSessionRequest request) {
|
||||
mineService.offlineCurrentUserSession(request);
|
||||
return HttpWrapper.ok();
|
||||
}
|
||||
|
||||
// fixme 全部用户接口进行 设置缓存
|
||||
// fixme 操作日志
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import com.orion.ops.framework.web.core.annotation.RestWrapper;
|
||||
import com.orion.ops.module.infra.define.operator.SystemUserOperatorType;
|
||||
import com.orion.ops.module.infra.entity.request.user.*;
|
||||
import com.orion.ops.module.infra.entity.vo.SystemUserVO;
|
||||
import com.orion.ops.module.infra.entity.vo.UserSessionVO;
|
||||
import com.orion.ops.module.infra.service.SystemUserRoleService;
|
||||
import com.orion.ops.module.infra.service.SystemUserService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@@ -137,5 +138,22 @@ public class SystemUserController {
|
||||
return systemUserService.deleteSystemUserById(id);
|
||||
}
|
||||
|
||||
// fixme 权限配置
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@GetMapping("/user-session")
|
||||
@Operation(summary = "获取用户会话列表")
|
||||
public List<UserSessionVO> getUserSessionList(@RequestParam("id") Long id) {
|
||||
return systemUserService.getUserSessionList(id);
|
||||
}
|
||||
|
||||
// fixme 权限配置
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@PutMapping("/offline-session")
|
||||
@Operation(summary = "下线用户会话")
|
||||
public HttpWrapper<?> offlineUserSession(@Validated @RequestBody OfflineUserSessionRequest request) {
|
||||
systemUserService.offlineUserSession(request);
|
||||
return HttpWrapper.ok();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -38,41 +38,11 @@ public class LoginTokenDTO {
|
||||
/**
|
||||
* 原始登录身份
|
||||
*/
|
||||
private Identity origin;
|
||||
private LoginTokenIdentityDTO origin;
|
||||
|
||||
/**
|
||||
* 覆盖登录身份
|
||||
*/
|
||||
private Identity override;
|
||||
|
||||
/**
|
||||
* 身份信息
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class Identity {
|
||||
|
||||
/**
|
||||
* 原始登录时间
|
||||
*/
|
||||
private Long loginTime;
|
||||
|
||||
/**
|
||||
* 当前设备登录地址
|
||||
*/
|
||||
private String address;
|
||||
|
||||
/**
|
||||
* 当前设备登录地址
|
||||
*/
|
||||
private String location;
|
||||
|
||||
/**
|
||||
* 当前设备 userAgent
|
||||
*/
|
||||
private String userAgent;
|
||||
|
||||
}
|
||||
private LoginTokenIdentityDTO override;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.orion.ops.module.infra.entity.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 身份信息
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/11/1 1:01
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class LoginTokenIdentityDTO {
|
||||
|
||||
/**
|
||||
* 原始登录时间
|
||||
*/
|
||||
private Long loginTime;
|
||||
|
||||
/**
|
||||
* 当前设备登录地址
|
||||
*/
|
||||
private String address;
|
||||
|
||||
/**
|
||||
* 当前设备登录地址
|
||||
*/
|
||||
private String location;
|
||||
|
||||
/**
|
||||
* 当前设备 userAgent
|
||||
*/
|
||||
private String userAgent;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.orion.ops.module.infra.entity.request.user;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 用户下线请求
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023/7/17 12:19
|
||||
*/
|
||||
@Data
|
||||
@Schema(name = "OfflineUserSessionRequest", description = "用户下线请求")
|
||||
public class OfflineUserSessionRequest {
|
||||
|
||||
@Schema(description = "userId")
|
||||
private Long userId;
|
||||
|
||||
@NotNull
|
||||
@Schema(description = "时间戳")
|
||||
private Long timestamp;
|
||||
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.io.Serializable;
|
||||
|
||||
@@ -25,7 +24,6 @@ import java.io.Serializable;
|
||||
@Schema(name = "SystemUserUpdateRequest", description = "用户 更新请求对象")
|
||||
public class SystemUserUpdateRequest implements Serializable {
|
||||
|
||||
@NotNull
|
||||
@Schema(description = "id")
|
||||
private Long id;
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.orion.ops.module.infra.entity.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 用户 会话响应对象
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2023-7-13 18:42
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(name = "UserSessionVO", description = "用户 会话响应对象")
|
||||
public class UserSessionVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "是否为当前会话")
|
||||
private Boolean current;
|
||||
|
||||
@Schema(description = "请求ip")
|
||||
private String address;
|
||||
|
||||
@Schema(description = "请求地址")
|
||||
private String location;
|
||||
|
||||
@Schema(description = "userAgent")
|
||||
private String userAgent;
|
||||
|
||||
@Schema(description = "登录时间")
|
||||
private Date loginTime;
|
||||
|
||||
}
|
||||
@@ -3,8 +3,11 @@ package com.orion.ops.module.infra.framework.service.impl;
|
||||
import com.orion.lang.utils.time.Dates;
|
||||
import com.orion.ops.framework.common.constant.ErrorCode;
|
||||
import com.orion.ops.framework.common.security.LoginUser;
|
||||
import com.orion.ops.framework.redis.core.utils.RedisUtils;
|
||||
import com.orion.ops.framework.security.core.service.SecurityFrameworkService;
|
||||
import com.orion.ops.module.infra.define.cache.UserCacheKeyDefine;
|
||||
import com.orion.ops.module.infra.entity.dto.LoginTokenDTO;
|
||||
import com.orion.ops.module.infra.entity.dto.LoginTokenIdentityDTO;
|
||||
import com.orion.ops.module.infra.enums.LoginTokenStatusEnum;
|
||||
import com.orion.ops.module.infra.enums.UserStatusEnum;
|
||||
import com.orion.ops.module.infra.service.AuthenticationService;
|
||||
@@ -55,12 +58,21 @@ public class SecurityFrameworkServiceImpl implements SecurityFrameworkService {
|
||||
if (tokenInfo == null) {
|
||||
return null;
|
||||
}
|
||||
// 检查 token 状态
|
||||
this.checkTokenStatus(tokenInfo);
|
||||
try {
|
||||
// 检查 token 状态
|
||||
this.checkTokenStatus(tokenInfo);
|
||||
} catch (Exception e) {
|
||||
// token 失效则删除
|
||||
// fixme test
|
||||
RedisUtils.delete(UserCacheKeyDefine.LOGIN_TOKEN.format(tokenInfo.getId(), tokenInfo.getOrigin().getLoginTime()));
|
||||
throw e;
|
||||
}
|
||||
// 获取登录信息
|
||||
LoginUser user = authenticationService.getLoginUser(tokenInfo.getId());
|
||||
// 检查用户状态
|
||||
UserStatusEnum.checkUserStatus(user.getStatus());
|
||||
// 设置登录时间戳
|
||||
user.setTimestamp(tokenInfo.getOrigin().getLoginTime());
|
||||
return user;
|
||||
}
|
||||
|
||||
@@ -77,7 +89,7 @@ public class SecurityFrameworkServiceImpl implements SecurityFrameworkService {
|
||||
}
|
||||
// 其他设备登录
|
||||
if (LoginTokenStatusEnum.OTHER_DEVICE.getStatus().equals(tokenStatus)) {
|
||||
LoginTokenDTO.Identity override = loginToken.getOverride();
|
||||
LoginTokenIdentityDTO override = loginToken.getOverride();
|
||||
throw ErrorCode.OTHER_DEVICE_LOGIN.exception(
|
||||
Dates.format(new Date(override.getLoginTime()), Dates.MD_HM),
|
||||
override.getAddress(),
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.orion.ops.module.infra.service;
|
||||
|
||||
import com.orion.ops.module.infra.entity.request.user.OfflineUserSessionRequest;
|
||||
import com.orion.ops.module.infra.entity.request.user.SystemUserUpdateRequest;
|
||||
import com.orion.ops.module.infra.entity.request.user.UserUpdatePasswordRequest;
|
||||
import com.orion.ops.module.infra.entity.vo.LoginHistoryVO;
|
||||
import com.orion.ops.module.infra.entity.vo.SystemUserVO;
|
||||
import com.orion.ops.module.infra.entity.vo.UserSessionVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -45,4 +47,18 @@ public interface MineService {
|
||||
*/
|
||||
List<LoginHistoryVO> getCurrentLoginHistory();
|
||||
|
||||
/**
|
||||
* 获取当前用户会话列表
|
||||
*
|
||||
* @return 回话列表
|
||||
*/
|
||||
List<UserSessionVO> getCurrentUserSessionList();
|
||||
|
||||
/**
|
||||
* 下线当前用户会话
|
||||
*
|
||||
* @param request request
|
||||
*/
|
||||
void offlineCurrentUserSession(OfflineUserSessionRequest request);
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.orion.ops.module.infra.service;
|
||||
import com.orion.lang.define.wrapper.DataGrid;
|
||||
import com.orion.ops.module.infra.entity.request.user.*;
|
||||
import com.orion.ops.module.infra.entity.vo.SystemUserVO;
|
||||
import com.orion.ops.module.infra.entity.vo.UserSessionVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -84,4 +85,19 @@ public interface SystemUserService {
|
||||
*/
|
||||
void resetPassword(UserResetPasswordRequest request);
|
||||
|
||||
/**
|
||||
* 获取用户会话列表
|
||||
*
|
||||
* @param userId userId
|
||||
* @return 回话列表
|
||||
*/
|
||||
List<UserSessionVO> getUserSessionList(Long userId);
|
||||
|
||||
/**
|
||||
* 下线用户会话
|
||||
*
|
||||
* @param request request
|
||||
*/
|
||||
void offlineUserSession(OfflineUserSessionRequest request);
|
||||
|
||||
}
|
||||
|
||||
@@ -23,13 +23,13 @@ import com.orion.ops.module.infra.define.cache.UserCacheKeyDefine;
|
||||
import com.orion.ops.module.infra.entity.domain.SystemRoleDO;
|
||||
import com.orion.ops.module.infra.entity.domain.SystemUserDO;
|
||||
import com.orion.ops.module.infra.entity.dto.LoginTokenDTO;
|
||||
import com.orion.ops.module.infra.entity.dto.LoginTokenIdentityDTO;
|
||||
import com.orion.ops.module.infra.entity.request.user.UserLoginRequest;
|
||||
import com.orion.ops.module.infra.entity.vo.UserLoginVO;
|
||||
import com.orion.ops.module.infra.enums.LoginTokenStatusEnum;
|
||||
import com.orion.ops.module.infra.enums.UserStatusEnum;
|
||||
import com.orion.ops.module.infra.service.AuthenticationService;
|
||||
import com.orion.ops.module.infra.service.PermissionService;
|
||||
import com.orion.ops.module.infra.service.SystemUserService;
|
||||
import com.orion.web.servlet.web.Servlets;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -331,7 +331,7 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
for (LoginTokenDTO loginTokenInfo : loginTokenInfoList) {
|
||||
String deviceLoginKey = UserCacheKeyDefine.LOGIN_TOKEN.format(id, loginTokenInfo.getOrigin().getLoginTime());
|
||||
loginTokenInfo.setStatus(LoginTokenStatusEnum.OTHER_DEVICE.getStatus());
|
||||
loginTokenInfo.setOverride(new LoginTokenDTO.Identity(loginTime, remoteAddr, location, userAgent));
|
||||
loginTokenInfo.setOverride(new LoginTokenIdentityDTO(loginTime, remoteAddr, location, userAgent));
|
||||
RedisStrings.setJson(deviceLoginKey, UserCacheKeyDefine.LOGIN_TOKEN, loginTokenInfo);
|
||||
}
|
||||
}
|
||||
@@ -364,7 +364,7 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
.id(id)
|
||||
.status(LoginTokenStatusEnum.OK.getStatus())
|
||||
.refreshCount(0)
|
||||
.origin(new LoginTokenDTO.Identity(loginTime, remoteAddr, location, userAgent))
|
||||
.origin(new LoginTokenIdentityDTO(loginTime, remoteAddr, location, userAgent))
|
||||
.build();
|
||||
RedisStrings.setJson(loginKey, UserCacheKeyDefine.LOGIN_TOKEN, loginValue);
|
||||
// 生成 refreshToken
|
||||
|
||||
@@ -6,11 +6,13 @@ import com.orion.ops.framework.common.utils.Valid;
|
||||
import com.orion.ops.framework.security.core.utils.SecurityUtils;
|
||||
import com.orion.ops.module.infra.dao.SystemUserDAO;
|
||||
import com.orion.ops.module.infra.entity.domain.SystemUserDO;
|
||||
import com.orion.ops.module.infra.entity.request.user.OfflineUserSessionRequest;
|
||||
import com.orion.ops.module.infra.entity.request.user.SystemUserUpdateRequest;
|
||||
import com.orion.ops.module.infra.entity.request.user.UserResetPasswordRequest;
|
||||
import com.orion.ops.module.infra.entity.request.user.UserUpdatePasswordRequest;
|
||||
import com.orion.ops.module.infra.entity.vo.LoginHistoryVO;
|
||||
import com.orion.ops.module.infra.entity.vo.SystemUserVO;
|
||||
import com.orion.ops.module.infra.entity.vo.UserSessionVO;
|
||||
import com.orion.ops.module.infra.service.MineService;
|
||||
import com.orion.ops.module.infra.service.OperatorLogService;
|
||||
import com.orion.ops.module.infra.service.SystemUserService;
|
||||
@@ -73,4 +75,15 @@ public class MineServiceImpl implements MineService {
|
||||
return operatorLogService.getLoginHistory(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserSessionVO> getCurrentUserSessionList() {
|
||||
return systemUserService.getUserSessionList(SecurityUtils.getLoginUserId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offlineCurrentUserSession(OfflineUserSessionRequest request) {
|
||||
request.setUserId(SecurityUtils.getLoginUserId());
|
||||
systemUserService.offlineUserSession(request);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,8 +20,10 @@ import com.orion.ops.module.infra.dao.SystemUserRoleDAO;
|
||||
import com.orion.ops.module.infra.define.cache.TipsCacheKeyDefine;
|
||||
import com.orion.ops.module.infra.define.cache.UserCacheKeyDefine;
|
||||
import com.orion.ops.module.infra.entity.domain.SystemUserDO;
|
||||
import com.orion.ops.module.infra.entity.dto.LoginTokenDTO;
|
||||
import com.orion.ops.module.infra.entity.request.user.*;
|
||||
import com.orion.ops.module.infra.entity.vo.SystemUserVO;
|
||||
import com.orion.ops.module.infra.entity.vo.UserSessionVO;
|
||||
import com.orion.ops.module.infra.enums.UserStatusEnum;
|
||||
import com.orion.ops.module.infra.service.AuthenticationService;
|
||||
import com.orion.ops.module.infra.service.FavoriteService;
|
||||
@@ -34,8 +36,11 @@ import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 用户 服务实现类
|
||||
@@ -242,6 +247,42 @@ public class SystemUserServiceImpl implements SystemUserService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserSessionVO> getUserSessionList(Long userId) {
|
||||
// 扫描缓存
|
||||
Set<String> keys = RedisStrings.scanKeys(UserCacheKeyDefine.LOGIN_TOKEN.format(userId, "*"));
|
||||
if (Lists.isEmpty(keys)) {
|
||||
return Lists.empty();
|
||||
}
|
||||
// 查询缓存
|
||||
List<LoginTokenDTO> tokens = RedisStrings.getJsonList(keys, UserCacheKeyDefine.LOGIN_TOKEN);
|
||||
if (Lists.isEmpty(tokens)) {
|
||||
return Lists.empty();
|
||||
}
|
||||
// 返回
|
||||
return tokens.stream()
|
||||
.map(LoginTokenDTO::getOrigin)
|
||||
.map(s -> UserSessionVO.builder()
|
||||
.current(s.getLoginTime().equals(SecurityUtils.getLoginTimestamp()))
|
||||
.address(s.getAddress())
|
||||
.location(s.getLocation())
|
||||
.userAgent(s.getUserAgent())
|
||||
.loginTime(new Date(s.getLoginTime()))
|
||||
.build())
|
||||
.sorted(Comparator.comparing(UserSessionVO::getLoginTime).reversed())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offlineUserSession(OfflineUserSessionRequest request) {
|
||||
Long userId = Valid.notNull(request.getUserId());
|
||||
Long timestamp = request.getTimestamp();
|
||||
RedisStrings.delete(
|
||||
UserCacheKeyDefine.LOGIN_TOKEN.format(userId, timestamp),
|
||||
UserCacheKeyDefine.LOGIN_REFRESH.format(userId, request.getTimestamp())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户名否存在
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user