diff --git a/orion-ops-framework/orion-ops-framework-common/src/main/java/com/orion/ops/framework/common/constant/Const.java b/orion-ops-framework/orion-ops-framework-common/src/main/java/com/orion/ops/framework/common/constant/Const.java index 1f3ca46b..7ad8a785 100644 --- a/orion-ops-framework/orion-ops-framework-common/src/main/java/com/orion/ops/framework/common/constant/Const.java +++ b/orion-ops-framework/orion-ops-framework-common/src/main/java/com/orion/ops/framework/common/constant/Const.java @@ -25,6 +25,8 @@ public interface Const extends com.orion.lang.constant.Const, FieldConst { Integer DEFAULT_SORT = 10; + int LOGIN_HISTORY_COUNT = 30; + Long NONE_ID = -1L; Integer DEFAULT_VERSION = 1; diff --git a/orion-ops-framework/orion-ops-framework-common/src/main/java/com/orion/ops/framework/common/constant/ErrorCode.java b/orion-ops-framework/orion-ops-framework-common/src/main/java/com/orion/ops/framework/common/constant/ErrorCode.java index 2c55335a..83d148a2 100644 --- a/orion-ops-framework/orion-ops-framework-common/src/main/java/com/orion/ops/framework/common/constant/ErrorCode.java +++ b/orion-ops-framework/orion-ops-framework-common/src/main/java/com/orion/ops/framework/common/constant/ErrorCode.java @@ -46,7 +46,7 @@ public enum ErrorCode implements CodeInfo { // -------------------- 自定义 - 业务 -------------------- - OTHER_DEVICE_LOGIN(700, "该账号于 {} 已在其他设备登陆 {}({})"), + OTHER_DEVICE_LOGIN(700, "该账号于 {} 已在其他设备登录 {}({})"), USER_DISABLED(701, "当前用户已禁用"), diff --git a/orion-ops-framework/orion-ops-framework-common/src/main/java/com/orion/ops/framework/common/constant/ErrorMessage.java b/orion-ops-framework/orion-ops-framework-common/src/main/java/com/orion/ops/framework/common/constant/ErrorMessage.java index d05d2696..696b9244 100644 --- a/orion-ops-framework/orion-ops-framework-common/src/main/java/com/orion/ops/framework/common/constant/ErrorMessage.java +++ b/orion-ops-framework/orion-ops-framework-common/src/main/java/com/orion/ops/framework/common/constant/ErrorMessage.java @@ -49,7 +49,7 @@ public interface ErrorMessage { String USERNAME_PASSWORD_ERROR = "用户名或密码错误"; - String MAX_LOGIN_FAILED = "登陆失败次数已上限"; + String MAX_LOGIN_FAILED = "登录失败次数已上限"; String HISTORY_ABSENT = "历史值不存在"; diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-log/src/main/java/com/orion/ops/framework/log/core/interceptor/PrettyLogPrinterInterceptor.java b/orion-ops-framework/orion-ops-spring-boot-starter-log/src/main/java/com/orion/ops/framework/log/core/interceptor/PrettyLogPrinterInterceptor.java index f9fa54d8..8c4a9d0f 100644 --- a/orion-ops-framework/orion-ops-spring-boot-starter-log/src/main/java/com/orion/ops/framework/log/core/interceptor/PrettyLogPrinterInterceptor.java +++ b/orion-ops-framework/orion-ops-spring-boot-starter-log/src/main/java/com/orion/ops/framework/log/core/interceptor/PrettyLogPrinterInterceptor.java @@ -52,7 +52,7 @@ public class PrettyLogPrinterInterceptor extends AbstractLogPrinterInterceptor { if (!Strings.isEmpty(summary)) { requestLog.append("\tsummary: ").append(summary).append('\n'); } - // 登陆用户 + // 登录用户 Long loginUserId = securityHolder.getLoginUserId(); if (loginUserId != null) { requestLog.append("\tuser: ").append(loginUserId).append('\n'); diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-log/src/main/java/com/orion/ops/framework/log/core/interceptor/RowLogPrinterInterceptor.java b/orion-ops-framework/orion-ops-spring-boot-starter-log/src/main/java/com/orion/ops/framework/log/core/interceptor/RowLogPrinterInterceptor.java index 5c69d606..a48fe7e2 100644 --- a/orion-ops-framework/orion-ops-spring-boot-starter-log/src/main/java/com/orion/ops/framework/log/core/interceptor/RowLogPrinterInterceptor.java +++ b/orion-ops-framework/orion-ops-spring-boot-starter-log/src/main/java/com/orion/ops/framework/log/core/interceptor/RowLogPrinterInterceptor.java @@ -56,7 +56,7 @@ public class RowLogPrinterInterceptor extends AbstractLogPrinterInterceptor impl if (!Strings.isEmpty(summary)) { fields.put(SUMMARY, summary); } - // 登陆用户 + // 登录用户 fields.put(USER, securityHolder.getLoginUserId()); // http if (request != null) { diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-mybatis/src/main/java/com/orion/ops/framework/mybatis/core/query/DataQuery.java b/orion-ops-framework/orion-ops-spring-boot-starter-mybatis/src/main/java/com/orion/ops/framework/mybatis/core/query/DataQuery.java index f8fed2d6..ca8ad9c6 100644 --- a/orion-ops-framework/orion-ops-spring-boot-starter-mybatis/src/main/java/com/orion/ops/framework/mybatis/core/query/DataQuery.java +++ b/orion-ops-framework/orion-ops-spring-boot-starter-mybatis/src/main/java/com/orion/ops/framework/mybatis/core/query/DataQuery.java @@ -106,6 +106,14 @@ public class DataQuery { return then; } + public DataQuery limit(int limit) { + return this.last(Const.LIMIT + Const.SPACE + limit); + } + + public DataQuery limit(int offset, int limit) { + return this.last(Const.LIMIT + Const.SPACE + offset + Const.COMMA + limit); + } + public DataQuery only() { return this.last(Const.LIMIT_1); } diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-security/src/main/java/com/orion/ops/framework/security/core/utils/SecurityUtils.java b/orion-ops-framework/orion-ops-spring-boot-starter-security/src/main/java/com/orion/ops/framework/security/core/utils/SecurityUtils.java index 7fae4b98..b3b4f1f9 100644 --- a/orion-ops-framework/orion-ops-spring-boot-starter-security/src/main/java/com/orion/ops/framework/security/core/utils/SecurityUtils.java +++ b/orion-ops-framework/orion-ops-spring-boot-starter-security/src/main/java/com/orion/ops/framework/security/core/utils/SecurityUtils.java @@ -69,7 +69,7 @@ public class SecurityUtils { } /** - * 获取当前用户id + * 获取当前 userId * * @return id */ @@ -78,6 +78,16 @@ public class SecurityUtils { return loginUser != null ? loginUser.getId() : null; } + /** + * 获取当前 username + * + * @return username + */ + public static String getLoginUsername() { + LoginUser loginUser = getLoginUser(); + return loginUser != null ? loginUser.getUsername() : null; + } + /** * 设置当前用户 * diff --git a/orion-ops-launch/src/main/resources/application.yaml b/orion-ops-launch/src/main/resources/application.yaml index 95d8cd49..8bab7805 100644 --- a/orion-ops-launch/src/main/resources/application.yaml +++ b/orion-ops-launch/src/main/resources/application.yaml @@ -161,7 +161,7 @@ orion: # 下面引用了 需要注意 field: ignore: - - password,newPassword,useNewPassword,publicKey,privateKey + - password,beforePassword,newPassword,useNewPassword,publicKey,privateKey - metrics desensitize: storage: diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/AuthenticationController.http b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/AuthenticationController.http index e617afde..b001570e 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/AuthenticationController.http +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/AuthenticationController.http @@ -1,4 +1,4 @@ -### 登陆 - admin 用户 +### 登录 - admin 用户 POST {{baseUrl}}/infra/auth/login Content-Type: application/json @@ -8,7 +8,7 @@ Content-Type: application/json } -### 登陆 +### 登录 POST {{baseUrl}}/infra/auth/login Content-Type: application/json diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/AuthenticationController.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/AuthenticationController.java index d80f3c81..6fb4146c 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/AuthenticationController.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/AuthenticationController.java @@ -10,7 +10,6 @@ import com.orion.ops.module.infra.entity.request.user.UserLoginRequest; import com.orion.ops.module.infra.entity.request.user.UserUpdatePasswordRequest; import com.orion.ops.module.infra.entity.vo.UserLoginVO; import com.orion.ops.module.infra.service.AuthenticationService; -import com.orion.ops.module.infra.service.SystemUserService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; @@ -40,12 +39,9 @@ public class AuthenticationController { @Resource private AuthenticationService authenticationService; - @Resource - private SystemUserService systemUserService; - @OperatorLog(AuthenticationOperatorType.LOGIN) @PermitAll - @Operation(summary = "登陆") + @Operation(summary = "登录") @PostMapping("/login") public UserLoginVO login(@Validated @RequestBody UserLoginRequest request, HttpServletRequest servletRequest) { diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/OperatorLogController.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/OperatorLogController.java index 0d677928..8ac16c36 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/OperatorLogController.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/OperatorLogController.java @@ -4,8 +4,10 @@ import com.orion.lang.define.wrapper.DataGrid; import com.orion.ops.framework.common.validator.group.Page; import com.orion.ops.framework.log.core.annotation.IgnoreLog; import com.orion.ops.framework.log.core.enums.IgnoreLogMode; +import com.orion.ops.framework.security.core.utils.SecurityUtils; import com.orion.ops.framework.web.core.annotation.RestWrapper; import com.orion.ops.module.infra.entity.request.operator.OperatorLogQueryRequest; +import com.orion.ops.module.infra.entity.vo.LoginHistoryVO; import com.orion.ops.module.infra.entity.vo.OperatorLogVO; import com.orion.ops.module.infra.service.OperatorLogService; import io.swagger.v3.oas.annotations.Operation; @@ -13,12 +15,10 @@ import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; +import java.util.List; /** * 操作日志 api @@ -47,5 +47,22 @@ public class OperatorLogController { return operatorLogService.getOperatorLogPage(request); } + // fixme 权限配置 + + @IgnoreLog(IgnoreLogMode.RET) + @GetMapping("/login-history") + @Operation(summary = "查询用户登录日志") + public List getLoginHistory(@RequestParam("username") String username) { + return operatorLogService.getLoginHistory(username); + } + + @IgnoreLog(IgnoreLogMode.RET) + @GetMapping("/current-login-history") + @Operation(summary = "查询当前用户登录日志") + public List getCurrentLoginHistory() { + String username = SecurityUtils.getLoginUsername(); + return operatorLogService.getLoginHistory(username); + } + } diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/SystemUserController.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/SystemUserController.java index 18812203..e9c5cdb2 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/SystemUserController.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/controller/SystemUserController.java @@ -7,6 +7,7 @@ import com.orion.ops.framework.biz.operator.log.core.annotation.OperatorLog; import com.orion.ops.framework.common.validator.group.Page; import com.orion.ops.framework.log.core.annotation.IgnoreLog; import com.orion.ops.framework.log.core.enums.IgnoreLogMode; +import com.orion.ops.framework.security.core.utils.SecurityUtils; 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.*; @@ -95,6 +96,20 @@ public class SystemUserController { return HttpWrapper.ok(); } + @IgnoreLog(IgnoreLogMode.RET) + @GetMapping("/get-current") + @Operation(summary = "查询当前用户信息") + public SystemUserVO getCurrentUserInfo() { + return systemUserService.getSystemUserById(SecurityUtils.getLoginUserId()); + } + + @PutMapping("/update-current") + @Operation(summary = "更新当前用户信息") + public Integer updateCurrentUser(@Validated @RequestBody SystemUserUpdateRequest request) { + request.setId(SecurityUtils.getLoginUserId()); + return systemUserService.updateSystemUserById(request); + } + @IgnoreLog(IgnoreLogMode.RET) @GetMapping("/get") @Operation(summary = "通过 id 查询用户") diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/convert/OperatorLogConvert.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/convert/OperatorLogConvert.java index 8254b033..cd3448b2 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/convert/OperatorLogConvert.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/convert/OperatorLogConvert.java @@ -3,6 +3,7 @@ package com.orion.ops.module.infra.convert; import com.orion.ops.framework.biz.operator.log.core.model.OperatorLogModel; import com.orion.ops.module.infra.entity.domain.OperatorLogDO; import com.orion.ops.module.infra.entity.request.operator.OperatorLogQueryRequest; +import com.orion.ops.module.infra.entity.vo.LoginHistoryVO; import com.orion.ops.module.infra.entity.vo.OperatorLogVO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @@ -25,4 +26,6 @@ public interface OperatorLogConvert { OperatorLogVO to(OperatorLogDO domain); + LoginHistoryVO toLoginHistory(OperatorLogDO domain); + } diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/define/cache/UserCacheKeyDefine.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/define/cache/UserCacheKeyDefine.java index cda74851..322af55d 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/define/cache/UserCacheKeyDefine.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/define/cache/UserCacheKeyDefine.java @@ -24,13 +24,13 @@ public interface UserCacheKeyDefine { CacheKeyDefine LOGIN_FAILED_COUNT = new CacheKeyBuilder() .key("user:failed:{}") - .desc("用户登陆失败次数 ${username}") + .desc("用户登录失败次数 ${username}") .timeout(3, TimeUnit.DAYS) .build(); CacheKeyDefine LOGIN_TOKEN = new CacheKeyBuilder() .key("user:token:{}:{}") - .desc("用户登陆 token ${id} ${time}") + .desc("用户登录 token ${id} ${time}") .type(LoginTokenDTO.class) .timeout(24, TimeUnit.HOURS) .build(); diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/define/operator/AuthenticationOperatorType.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/define/operator/AuthenticationOperatorType.java index be7f5e1c..a6729a0f 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/define/operator/AuthenticationOperatorType.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/define/operator/AuthenticationOperatorType.java @@ -25,7 +25,7 @@ public class AuthenticationOperatorType extends InitializingOperatorTypes { @Override public OperatorType[] types() { return new OperatorType[]{ - new OperatorType(L, LOGIN, "登陆系统"), + new OperatorType(L, LOGIN, "登录系统"), new OperatorType(L, LOGOUT, "登出系统"), new OperatorType(L, UPDATE_PASSWORD, "修改密码"), }; diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/dto/LoginTokenDTO.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/dto/LoginTokenDTO.java index 86e281dd..233ef8ee 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/dto/LoginTokenDTO.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/dto/LoginTokenDTO.java @@ -6,7 +6,7 @@ import lombok.Data; import lombok.NoArgsConstructor; /** - * 登陆 token 缓存 + * 登录 token 缓存 * * @author Jiahang Li * @version 1.0.0 @@ -28,7 +28,7 @@ public class LoginTokenDTO { * * @see com.orion.ops.module.infra.enums.LoginTokenStatusEnum */ - private Integer tokenStatus; + private Integer status; /** * 已续签次数 @@ -36,18 +36,43 @@ public class LoginTokenDTO { private Integer refreshCount; /** - * 登陆时间/其他设备登陆时间 + * 原始登录身份 */ - private Long loginTime; + private Identity origin; /** - * 登陆 ip/其他设备登陆 ip + * 覆盖登录身份 */ - private String ip; + private Identity override; /** - * 登陆地址/其他设备登陆地址 + * 身份信息 */ - private String location; + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Identity { + + /** + * 原始登录时间 + */ + private Long loginTime; + + /** + * 当前设备登录地址 + */ + private String address; + + /** + * 当前设备登录地址 + */ + private String location; + + /** + * 当前设备 userAgent + */ + private String userAgent; + + } } diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/request/operator/OperatorLogQueryRequest.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/request/operator/OperatorLogQueryRequest.java index 9b434b43..01441fef 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/request/operator/OperatorLogQueryRequest.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/request/operator/OperatorLogQueryRequest.java @@ -26,6 +26,9 @@ public class OperatorLogQueryRequest extends PageRequest { @Schema(description = "用户id") private Long userId; + @Schema(description = "用户名") + private String username; + @Size(max = 32) @Schema(description = "模块") private String module; diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/request/user/UserLoginRequest.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/request/user/UserLoginRequest.java index 96527e2b..4fceb7bb 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/request/user/UserLoginRequest.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/request/user/UserLoginRequest.java @@ -6,14 +6,14 @@ import lombok.Data; import javax.validation.constraints.NotEmpty; /** - * 登陆请求 + * 登录请求 * * @author Jiahang Li * @version 1.0.0 * @since 2023/7/13 22:16 */ @Data -@Schema(name = "UserLoginRequest", description = "登陆请求") +@Schema(name = "UserLoginRequest", description = "登录请求") public class UserLoginRequest { @NotEmpty diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/vo/LoginHistoryVO.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/vo/LoginHistoryVO.java new file mode 100644 index 00000000..cfd845dd --- /dev/null +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/vo/LoginHistoryVO.java @@ -0,0 +1,49 @@ +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-10-10 17:08 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "LoginHistoryVO", description = "登录日志 视图响应对象") +public class LoginHistoryVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "请求ip") + private String address; + + @Schema(description = "请求地址") + private String location; + + @Schema(description = "userAgent") + private String userAgent; + + @Schema(description = "操作结果 0失败 1成功") + private Integer result; + + @Schema(description = "错误信息") + private String errorMessage; + + @Schema(description = "创建时间") + private Date createTime; + +} diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/vo/UserLoginVO.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/vo/UserLoginVO.java index d949103f..0b064851 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/vo/UserLoginVO.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/entity/vo/UserLoginVO.java @@ -7,7 +7,7 @@ import lombok.Data; import lombok.NoArgsConstructor; /** - * 用户登陆响应 + * 用户登录响应 * * @author Jiahang Li * @version 1.0.0 @@ -20,7 +20,7 @@ import lombok.NoArgsConstructor; @Schema(name = "SystemUserVO", description = "用户 视图响应对象") public class UserLoginVO { - @Schema(description = "登陆 token") + @Schema(description = "登录 token") private String token; } diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/enums/LoginTokenStatusEnum.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/enums/LoginTokenStatusEnum.java index 8ca91ebd..1ce5dd00 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/enums/LoginTokenStatusEnum.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/enums/LoginTokenStatusEnum.java @@ -3,7 +3,7 @@ package com.orion.ops.module.infra.enums; import lombok.Getter; /** - * 登陆 token 状态 + * 登录 token 状态 * * @author Jiahang Li * @version 1.0.0 @@ -18,9 +18,9 @@ public enum LoginTokenStatusEnum { OK(0), /** - * 已在其他设备登陆 + * 已在其他设备登录 */ - OTHER_DEVICE(1, "已在其他设备登陆"), + OTHER_DEVICE(1, "已在其他设备登录"), ; diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/framework/service/impl/SecurityFrameworkServiceImpl.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/framework/service/impl/SecurityFrameworkServiceImpl.java index 76bcfc85..069b21e0 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/framework/service/impl/SecurityFrameworkServiceImpl.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/framework/service/impl/SecurityFrameworkServiceImpl.java @@ -57,7 +57,7 @@ public class SecurityFrameworkServiceImpl implements SecurityFrameworkService { } // 检查 token 状态 this.checkTokenStatus(tokenInfo); - // 获取登陆信息 + // 获取登录信息 LoginUser user = authenticationService.getLoginUser(tokenInfo.getId()); // 检查用户状态 UserStatusEnum.checkUserStatus(user.getStatus()); @@ -70,17 +70,18 @@ public class SecurityFrameworkServiceImpl implements SecurityFrameworkService { * @param loginToken loginToken */ private void checkTokenStatus(LoginTokenDTO loginToken) { - Integer tokenStatus = loginToken.getTokenStatus(); + Integer tokenStatus = loginToken.getStatus(); // 正常状态 if (LoginTokenStatusEnum.OK.getStatus().equals(tokenStatus)) { return; } - // 其他设备登陆 + // 其他设备登录 if (LoginTokenStatusEnum.OTHER_DEVICE.getStatus().equals(tokenStatus)) { + LoginTokenDTO.Identity override = loginToken.getOverride(); throw ErrorCode.OTHER_DEVICE_LOGIN.exception( - Dates.format(new Date(loginToken.getLoginTime()), Dates.MD_HM), - loginToken.getIp(), - loginToken.getLocation()); + Dates.format(new Date(override.getLoginTime()), Dates.MD_HM), + override.getAddress(), + override.getLocation()); } } diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/AuthenticationService.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/AuthenticationService.java index 4cda1c2a..7559d565 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/AuthenticationService.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/AuthenticationService.java @@ -18,7 +18,7 @@ import javax.servlet.http.HttpServletRequest; public interface AuthenticationService { // TODO 配置化 - // 允许多端登陆 + // 允许多端登录 boolean allowMultiDevice = true; // 允许凭证续签 boolean allowRefresh = true; @@ -28,7 +28,7 @@ public interface AuthenticationService { int maxFailedLoginCount = 5; /** - * 登陆 + * 登录 * * @param request request * @param servletRequest servletRequest @@ -51,7 +51,7 @@ public interface AuthenticationService { void updatePassword(UserUpdatePasswordRequest request); /** - * 获取登陆用户信息 + * 获取登录用户信息 * * @param userId userId * @return loginUser diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/OperatorLogService.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/OperatorLogService.java index faad8285..35322bed 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/OperatorLogService.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/OperatorLogService.java @@ -3,8 +3,11 @@ package com.orion.ops.module.infra.service; import com.orion.lang.define.wrapper.DataGrid; import com.orion.ops.framework.biz.operator.log.core.model.OperatorLogModel; import com.orion.ops.module.infra.entity.request.operator.OperatorLogQueryRequest; +import com.orion.ops.module.infra.entity.vo.LoginHistoryVO; import com.orion.ops.module.infra.entity.vo.OperatorLogVO; +import java.util.List; + /** * 操作日志 服务类 * @@ -29,4 +32,12 @@ public interface OperatorLogService { */ DataGrid getOperatorLogPage(OperatorLogQueryRequest request); + /** + * 查询用户登录日志 + * + * @param username username + * @return rows + */ + List getLoginHistory(String username); + } diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/AuthenticationServiceImpl.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/AuthenticationServiceImpl.java index b2bb1b4d..f6efcb86 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/AuthenticationServiceImpl.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/AuthenticationServiceImpl.java @@ -71,9 +71,9 @@ public class AuthenticationServiceImpl implements AuthenticationService { @Override public UserLoginVO login(UserLoginRequest request, HttpServletRequest servletRequest) { - // 登陆前检查 + // 登录前检查 this.preCheckLogin(request); - // 获取登陆用户 + // 获取登录用户 LambdaQueryWrapper wrapper = systemUserDAO.wrapper() .eq(SystemUserDO::getUsername, request.getUsername()); SystemUserDO user = systemUserDAO.of(wrapper).getOne(); @@ -90,17 +90,18 @@ public class AuthenticationServiceImpl implements AuthenticationService { this.deleteUserCache(user); // 重设用户缓存 this.setUserCache(user); - // 获取登陆 ip + // 获取登录信息 String remoteAddr = Servlets.getRemoteAddr(servletRequest); String location = IpUtils.getLocation(remoteAddr); + String userAgent = Servlets.getUserAgent(servletRequest); long current = System.currentTimeMillis(); - // 不允许多端登陆 + // 不允许多端登录 if (!allowMultiDevice) { // 无效化其他缓存 - this.invalidOtherDeviceToken(user.getId(), current, remoteAddr, location); + this.invalidOtherDeviceToken(user.getId(), current, remoteAddr, location, userAgent); } // 生成 loginToken - String token = this.generatorLoginToken(user, current, remoteAddr, location); + String token = this.generatorLoginToken(user, current, remoteAddr, location, userAgent); return UserLoginVO.builder() .token(token) .build(); @@ -108,7 +109,7 @@ public class AuthenticationServiceImpl implements AuthenticationService { @Override public void logout(HttpServletRequest request) { - // 获取登陆 token + // 获取登录 token String loginToken = SecurityUtils.obtainAuthorization(request); if (loginToken == null) { return; @@ -156,12 +157,12 @@ public class AuthenticationServiceImpl implements AuthenticationService { @Override public LoginTokenDTO getLoginTokenInfo(String loginToken, boolean checkRefresh) { - // 获取登陆 key pair + // 获取登录 key pair Pair pair = this.getLoginTokenPair(loginToken); if (pair == null) { return null; } - // 获取登陆 key value + // 获取登录 key value String loginKey = UserCacheKeyDefine.LOGIN_TOKEN.format(pair.getKey(), pair.getValue()); String loginCache = redisTemplate.opsForValue().get(loginKey); if (loginCache != null) { @@ -181,7 +182,7 @@ public class AuthenticationServiceImpl implements AuthenticationService { LoginTokenDTO refresh = JSON.parseObject(refreshCache, LoginTokenDTO.class); int refreshCount = refresh.getRefreshCount() + 1; refresh.setRefreshCount(refreshCount); - // 设置登陆缓存 + // 设置登录缓存 RedisStrings.setJson(loginKey, UserCacheKeyDefine.LOGIN_TOKEN, refresh); if (refreshCount < maxRefreshCount) { // 小于续签最大次数 则再次设置 refreshToken @@ -213,7 +214,7 @@ public class AuthenticationServiceImpl implements AuthenticationService { } /** - * 登陆预检查 + * 登录预检查 * * @param request request */ @@ -222,7 +223,7 @@ public class AuthenticationServiceImpl implements AuthenticationService { if (request.getPassword().length() != Const.MD5_LEN) { throw Exceptions.argument(ErrorMessage.USERNAME_PASSWORD_ERROR); } - // 检查登陆失败次数 + // 检查登录失败次数 String failedCountKey = UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(request.getUsername()); String failedCount = redisTemplate.opsForValue().get(failedCountKey); if (failedCount != null && Integer.parseInt(failedCount) >= maxFailedLoginCount) { @@ -243,7 +244,7 @@ public class AuthenticationServiceImpl implements AuthenticationService { if (user != null && user.getPassword().equals(Signatures.md5(request.getPassword()))) { return true; } - // 刷新登陆失败缓存 + // 刷新登录失败缓存 String failedCountKey = UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(request.getUsername()); Long failedLoginCount = redisTemplate.opsForValue().increment(failedCountKey); RedisUtils.setExpire(failedCountKey, UserCacheKeyDefine.LOGIN_FAILED_COUNT); @@ -293,7 +294,7 @@ public class AuthenticationServiceImpl implements AuthenticationService { private void deleteUserCache(SystemUserDO user) { // 用户信息缓存 String userInfoKey = UserCacheKeyDefine.USER_INFO.format(user.getId()); - // 登陆失败次数缓存 + // 登录失败次数缓存 String loginFailedCountKey = UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(user.getUsername()); // 删除缓存 redisTemplate.delete(Lists.of(userInfoKey, loginFailedCountKey)); @@ -324,34 +325,34 @@ public class AuthenticationServiceImpl implements AuthenticationService { } /** - * 无效化其他登陆信息 + * 无效化其他登录信息 * * @param id id * @param loginTime loginTime * @param remoteAddr remoteAddr * @param location location + * @param userAgent userAgent */ @SuppressWarnings("ALL") - private void invalidOtherDeviceToken(Long id, long loginTime, String remoteAddr, String location) { + private void invalidOtherDeviceToken(Long id, long loginTime, + String remoteAddr, String location, String userAgent) { String loginKey = UserCacheKeyDefine.LOGIN_TOKEN.format(id, "*"); - // 获取登陆信息 + // 获取登录信息 Set loginKeyList = RedisUtils.scanKeys(loginKey); if (!loginKeyList.isEmpty()) { - // 获取有效登陆信息 + // 获取有效登录信息 List loginTokenInfoList = redisTemplate.opsForValue() .multiGet(loginKeyList) .stream() .filter(Objects::nonNull) .map(s -> JSON.parseObject(s, LoginTokenDTO.class)) - .filter(s -> LoginTokenStatusEnum.OK.getStatus().equals(s.getTokenStatus())) + .filter(s -> LoginTokenStatusEnum.OK.getStatus().equals(s.getStatus())) .collect(Collectors.toList()); - // 修改登陆信息 + // 修改登录信息 for (LoginTokenDTO loginTokenInfo : loginTokenInfoList) { - String deviceLoginKey = UserCacheKeyDefine.LOGIN_TOKEN.format(id, loginTokenInfo.getLoginTime()); - loginTokenInfo.setTokenStatus(LoginTokenStatusEnum.OTHER_DEVICE.getStatus()); - loginTokenInfo.setLoginTime(loginTime); - loginTokenInfo.setIp(remoteAddr); - loginTokenInfo.setLocation(location); + 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)); RedisStrings.setJson(deviceLoginKey, UserCacheKeyDefine.LOGIN_TOKEN, loginTokenInfo); } } @@ -372,20 +373,19 @@ public class AuthenticationServiceImpl implements AuthenticationService { * @param loginTime loginTime * @param remoteAddr remoteAddr * @param location location + * @param userAgent userAgent * @return loginToken */ private String generatorLoginToken(SystemUserDO user, long loginTime, - String remoteAddr, String location) { + String remoteAddr, String location, String userAgent) { Long id = user.getId(); // 生成 loginToken String loginKey = UserCacheKeyDefine.LOGIN_TOKEN.format(id, loginTime); LoginTokenDTO loginValue = LoginTokenDTO.builder() .id(id) - .tokenStatus(LoginTokenStatusEnum.OK.getStatus()) + .status(LoginTokenStatusEnum.OK.getStatus()) .refreshCount(0) - .ip(remoteAddr) - .loginTime(loginTime) - .location(location) + .origin(new LoginTokenDTO.Identity(loginTime, remoteAddr, location, userAgent)) .build(); RedisStrings.setJson(loginKey, UserCacheKeyDefine.LOGIN_TOKEN, loginValue); // 生成 refreshToken diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/OperatorLogServiceImpl.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/OperatorLogServiceImpl.java index 5646f83d..e1318bc2 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/OperatorLogServiceImpl.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/OperatorLogServiceImpl.java @@ -3,16 +3,20 @@ package com.orion.ops.module.infra.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.orion.lang.define.wrapper.DataGrid; import com.orion.ops.framework.biz.operator.log.core.model.OperatorLogModel; +import com.orion.ops.framework.common.constant.Const; import com.orion.ops.module.infra.convert.OperatorLogConvert; import com.orion.ops.module.infra.dao.OperatorLogDAO; +import com.orion.ops.module.infra.define.operator.AuthenticationOperatorType; import com.orion.ops.module.infra.entity.domain.OperatorLogDO; import com.orion.ops.module.infra.entity.request.operator.OperatorLogQueryRequest; +import com.orion.ops.module.infra.entity.vo.LoginHistoryVO; import com.orion.ops.module.infra.entity.vo.OperatorLogVO; import com.orion.ops.module.infra.service.OperatorLogService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import javax.annotation.Resource; +import java.util.List; /** * 操作日志 服务实现类 @@ -46,6 +50,19 @@ public class OperatorLogServiceImpl implements OperatorLogService { .dataGrid(OperatorLogConvert.MAPPER::to); } + @Override + public List getLoginHistory(String username) { + // 条件 + OperatorLogQueryRequest request = new OperatorLogQueryRequest(); + request.setUsername(username); + request.setType(AuthenticationOperatorType.LOGIN); + LambdaQueryWrapper wrapper = this.buildQueryWrapper(request); + // 查询 + return operatorLogDAO.of(wrapper) + .limit(Const.LOGIN_HISTORY_COUNT) + .list(OperatorLogConvert.MAPPER::toLoginHistory); + } + /** * 构建查询 wrapper * @@ -55,12 +72,14 @@ public class OperatorLogServiceImpl implements OperatorLogService { private LambdaQueryWrapper buildQueryWrapper(OperatorLogQueryRequest request) { return operatorLogDAO.wrapper() .eq(OperatorLogDO::getUserId, request.getUserId()) + .eq(OperatorLogDO::getUsername, request.getUsername()) .eq(OperatorLogDO::getRiskLevel, request.getRiskLevel()) .eq(OperatorLogDO::getModule, request.getModule()) .eq(OperatorLogDO::getType, request.getType()) .eq(OperatorLogDO::getResult, request.getResult()) .ge(OperatorLogDO::getStartTime, request.getStartTimeStart()) - .le(OperatorLogDO::getStartTime, request.getStartTimeEnd()); + .le(OperatorLogDO::getStartTime, request.getStartTimeEnd()) + .orderByDesc(OperatorLogDO::getId); } } diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/SystemUserServiceImpl.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/SystemUserServiceImpl.java index ae97e84c..45b32fd2 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/SystemUserServiceImpl.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/SystemUserServiceImpl.java @@ -124,7 +124,7 @@ public class SystemUserServiceImpl implements SystemUserService { // 更新用户 int effect = systemUserDAO.updateById(updateRecord); log.info("SystemUserService-updateUserStatus effect: {}, updateRecord: {}", effect, JSON.toJSONString(updateRecord)); - // 如果之前是锁定则删除登陆失败次数缓存 + // 如果之前是锁定则删除登录失败次数缓存 if (UserStatusEnum.LOCKED.getStatus().equals(record.getStatus())) { redisTemplate.delete(UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(record.getUsername())); } @@ -224,9 +224,9 @@ public class SystemUserServiceImpl implements SystemUserService { update.setPassword(Signatures.md5(request.getPassword())); int effect = systemUserDAO.updateById(update); log.info("SystemUserService-resetPassword record: {}, effect: {}", JSON.toJSONString(update), effect); - // 删除登陆失败次数缓存 + // 删除登录失败次数缓存 redisTemplate.delete(UserCacheKeyDefine.LOGIN_FAILED_COUNT.format(record.getUsername())); - // 删除登陆缓存 + // 删除登录缓存 String loginKey = UserCacheKeyDefine.LOGIN_TOKEN.format(id, "*"); Set loginKeyList = RedisUtils.scanKeys(loginKey); if (!loginKeyList.isEmpty()) { diff --git a/orion-ops-ui/src/api/user/auth.ts b/orion-ops-ui/src/api/user/auth.ts index fc11ea08..3a9daec2 100644 --- a/orion-ops-ui/src/api/user/auth.ts +++ b/orion-ops-ui/src/api/user/auth.ts @@ -1,7 +1,7 @@ import axios from 'axios'; /** - * 登陆请求 + * 登录请求 */ export interface LoginRequest { username?: string; @@ -9,7 +9,7 @@ export interface LoginRequest { } /** - * 登陆响应 + * 登录响应 */ export interface LoginResponse { token: string; @@ -24,7 +24,7 @@ export interface UserUpdatePasswordRequest { } /** - * 登陆 + * 登录 */ export function login(data: LoginRequest) { return axios.post('/infra/auth/login', data); diff --git a/orion-ops-ui/src/api/user/operator-log.ts b/orion-ops-ui/src/api/user/operator-log.ts new file mode 100644 index 00000000..2b713dd4 --- /dev/null +++ b/orion-ops-ui/src/api/user/operator-log.ts @@ -0,0 +1,75 @@ +import type { DataGrid, Pagination } from '@/types/global'; +import axios from 'axios'; + +/** + * 操作日志查询参数 + */ +export interface OperatorLogQueryRequest extends Pagination { + userId?: number; + username?: string; + module?: string; + type?: string; + riskLevel?: string; + result?: number; + startTimeStart?: string; + startTimeEnd?: string; +} + +/** + * 操作日志查询响应 + */ +export interface OperatorLogQueryResponse { + id: number; + userId: number; + username: string; + traceId: string; + address: string; + location: string; + userAgent: string; + riskLevel: string; + module: string; + type: string; + logInfo: string; + extra: string; + result: number; + errorMessage: string; + returnValue: string; + duration: number; + startTime: number; + endTime: number; + createTime: number; +} + +/** + * 登录日志查询响应 + */ +export interface LoginHistoryQueryResponse { + id: number; + address: string; + location: string; + userAgent: string; + result: number; + errorMessage: string; + createTime: number; +} + +/** + * 分页操作日志 + */ +export function getOperatorLogPage(request: OperatorLogQueryRequest) { + return axios.post>('/infra/operator-log/query', request); +} + +/** + * 查询登录日志 + */ +export function getLoginHistory(username: string) { + return axios.get('/infra/operator-log/login-history', { params: { username } }); +} + +/** + * 查询当前用户登录日志 + */ +export function getCurrentLoginHistory() { + return axios.get('/infra/operator-log/current-login-history'); +} diff --git a/orion-ops-ui/src/api/user/user.ts b/orion-ops-ui/src/api/user/user.ts index d53179db..a7e4031b 100644 --- a/orion-ops-ui/src/api/user/user.ts +++ b/orion-ops-ui/src/api/user/user.ts @@ -12,8 +12,6 @@ export interface UserCreateRequest { avatar?: string; mobile?: string; email?: string; - status?: number; - lastLoginTime?: string; } /** @@ -93,6 +91,20 @@ export function resetUserPassword(request: UserUpdateRequest) { return axios.put('/infra/system-user/reset-password', request); } +/** + * 查询当前用户 + */ +export function getCurrentUser() { + return axios.get('/infra/system-user/get-current'); +} + +/** + * 更新当前用户 + */ +export function updateCurrentUser(request: UserUpdateRequest) { + return axios.put('/infra/system-user/update-current', request); +} + /** * 通过 id 查询用户 */ diff --git a/orion-ops-ui/src/components/app/navbar/index.vue b/orion-ops-ui/src/components/app/navbar/index.vue index 6ec6b394..77dc8912 100644 --- a/orion-ops-ui/src/components/app/navbar/index.vue +++ b/orion-ops-ui/src/components/app/navbar/index.vue @@ -154,7 +154,7 @@