Bladeren bron

初始化 c 端的登录逻辑

YunaiV 3 jaren geleden
bovenliggende
commit
e999cc31c6
36 gewijzigde bestanden met toevoegingen van 612 en 96 verwijderingen
  1. 0 19
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/logger/vo/loginlog/SysLoginLogCreateReqVO.java
  2. 2 2
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/convert/logger/SysLoginLogConvert.java
  3. 6 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/dataobject/auth/SysUserSessionDO.java
  4. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/dataobject/logger/SysLoginLogDO.java
  5. 1 3
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/SysErrorCodeConstants.java
  6. 2 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/logger/SysLoginLogTypeEnum.java
  7. 2 2
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/logger/SysLoginResultEnum.java
  8. 0 7
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/SysUserSessionService.java
  9. 19 19
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java
  10. 16 26
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysUserSessionServiceImpl.java
  11. 3 3
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/logger/SysLoginLogService.java
  12. 57 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/logger/dto/SysLoginLogCreateReqDTO.java
  13. 5 7
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/logger/impl/SysLoginLogServiceImpl.java
  14. 8 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/SysUserService.java
  15. 5 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/impl/SysUserServiceImpl.java
  16. 4 4
      yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/logger/SysLoginLogServiceImplTest.java
  17. 6 1
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/convert/package-info.java
  18. 1 0
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md
  19. 17 0
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/enums/MbrErrorCodeConstants.java
  20. 75 1
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/auth/impl/MbrAuthServiceImpl.java
  21. 8 0
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/MbrUserService.java
  22. 6 0
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/impl/MbrUserServiceImpl.java
  23. 15 0
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/convert/logger/SysLoginLogConvert.java
  24. 5 0
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/convert/package-info.java
  25. 1 0
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md
  26. 10 0
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/dal/dataobject/logger/SysLoginLogMapper.java
  27. 70 0
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/dal/mysql/logger/SysLoginLogDO.java
  28. 0 1
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/dal/mysql/package-info.java
  29. 29 0
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/enums/logger/SysLoginLogTypeEnum.java
  30. 27 0
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/enums/logger/SysLoginResultEnum.java
  31. 1 0
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/enums/package-info.java
  32. 59 0
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/auth/SysUserSessionService.java
  33. 47 0
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/auth/impl/SysUserSessionServiceImpl.java
  34. 17 0
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/logger/SysLoginLogService.java
  35. 57 0
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/logger/dto/SysLoginLogCreateReqDTO.java
  36. 30 0
      yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/logger/impl/SysLoginLogServiceImpl.java

+ 0 - 19
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/logger/vo/loginlog/SysLoginLogCreateReqVO.java

@@ -1,19 +0,0 @@
-package cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-@ApiModel(value = "登录日志创建 Request VO",
-        description = "暂时提供给前端,仅仅后端记录登录日志时,进行使用")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class SysLoginLogCreateReqVO extends SysLoginLogBaseVO {
-
-    @ApiModelProperty(value = "用户编号", example = "1")
-    private Long userId;
-
-}

+ 2 - 2
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/convert/logger/SysLoginLogConvert.java

@@ -1,7 +1,7 @@
 package cn.iocoder.yudao.adminserver.modules.system.convert.logger;
 
+import cn.iocoder.yudao.adminserver.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog.SysLoginLogCreateReqVO;
 import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog.SysLoginLogExcelVO;
 import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog.SysLoginLogRespVO;
 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.logger.SysLoginLogDO;
@@ -15,7 +15,7 @@ public interface SysLoginLogConvert {
 
     SysLoginLogConvert INSTANCE = Mappers.getMapper(SysLoginLogConvert.class);
 
-    SysLoginLogDO convert(SysLoginLogCreateReqVO bean);
+    SysLoginLogDO convert(SysLoginLogCreateReqDTO bean);
 
     PageResult<SysLoginLogRespVO> convertPage(PageResult<SysLoginLogDO> page);
 

+ 6 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/dataobject/auth/SysUserSessionDO.java

@@ -38,6 +38,12 @@ public class SysUserSessionDO extends BaseDO {
      * 关联 {@link SysUserDO#getId()}
      */
     private Long userId;
+    /**
+     * 用户类型
+     *
+     * 枚举 {@link UserTypeEnum}
+     */
+    private Integer userType;
 
     /**
      * 用户账号

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/dataobject/logger/SysLoginLogDO.java

@@ -14,7 +14,7 @@ import lombok.ToString;
  *
  * 注意,包括登录和登出两种行为
  *
- * @author ruoyi
+ * @author 芋道源码
  */
 @TableName("sys_login_log")
 @Data

+ 1 - 3
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/SysErrorCodeConstants.java

@@ -1,8 +1,6 @@
 package cn.iocoder.yudao.adminserver.modules.system.enums;
 
-import cn.iocoder.yudao.adminserver.modules.tool.framework.errorcode.config.ErrorCodeConfiguration;
 import cn.iocoder.yudao.framework.common.exception.ErrorCode;
-import org.springframework.validation.Errors;
 
 /**
  * System 错误码枚举类
@@ -14,7 +12,7 @@ public interface SysErrorCodeConstants {
     // ========== AUTH 模块 1002000000 ==========
     ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1002000000, "登录失败,账号密码不正确");
     ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1002000001, "登录失败,账号被禁用");
-    ErrorCode AUTH_LOGIN_FAIL_UNKNOWN = new ErrorCode(1002000002, "登录失败"); // 登录失败的兜底,位置原因
+    ErrorCode AUTH_LOGIN_FAIL_UNKNOWN = new ErrorCode(1002000002, "登录失败"); // 登录失败的兜底,未知原因
     ErrorCode AUTH_LOGIN_CAPTCHA_NOT_FOUND = new ErrorCode(1002000003, "验证码不存在");
     ErrorCode AUTH_LOGIN_CAPTCHA_CODE_ERROR = new ErrorCode(1002000004, "验证码不正确");
     ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1002000005, "未绑定账号,需要进行绑定");

+ 2 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/logger/SysLoginLogTypeEnum.java

@@ -13,6 +13,8 @@ public enum SysLoginLogTypeEnum {
     LOGIN_USERNAME(100), // 使用账号登录
     LOGIN_SOCIAL(101), // 使用社交登录
     LOGIN_MOCK(102), // 使用 Mock 登录
+    LOGIN_MOBILE(103), // 使用手机登陆
+    LOGIN_SMS(104), // 使用短信登陆
 
     LOGOUT_SELF(200),  // 自己主动登出
     LOGOUT_TIMEOUT(201), // 超时登出

+ 2 - 2
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/logger/SysLoginResultEnum.java

@@ -13,8 +13,8 @@ public enum SysLoginResultEnum {
     SUCCESS(0), // 成功
     BAD_CREDENTIALS(10), // 账号或密码不正确
     USER_DISABLED(20), // 用户被禁用
-    CAPTCHA_NOT_FOUND(30), // 验证码不存在
-    CAPTCHA_CODE_ERROR(31), // 验证码不正确
+    CAPTCHA_NOT_FOUND(30), // 图片验证码不存在
+    CAPTCHA_CODE_ERROR(31), // 图片验证码不正确
 
     UNKNOWN_ERROR(100), // 未知异常
     ;

+ 0 - 7
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/SysUserSessionService.java

@@ -46,13 +46,6 @@ public interface SysUserSessionService {
     LoginUser getLoginUser(String sessionId);
 
     /**
-     * 获取当前登录用户信息
-     * @param username 用户名称
-     * @return 在线用户
-     */
-    String getSessionId(String username);
-
-    /**
      * 获得 Session 超时时间,单位:毫秒
      *
      * @return 超时时间

+ 19 - 19
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java

@@ -5,7 +5,6 @@ import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAu
 import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthSocialBindReqVO;
 import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthSocialLogin2ReqVO;
 import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthSocialLoginReqVO;
-import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog.SysLoginLogCreateReqVO;
 import cn.iocoder.yudao.adminserver.modules.system.convert.auth.SysAuthConvert;
 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.social.SysSocialUserDO;
 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserDO;
@@ -15,6 +14,7 @@ import cn.iocoder.yudao.adminserver.modules.system.service.auth.SysAuthService;
 import cn.iocoder.yudao.adminserver.modules.system.service.auth.SysUserSessionService;
 import cn.iocoder.yudao.adminserver.modules.system.service.common.SysCaptchaService;
 import cn.iocoder.yudao.adminserver.modules.system.service.logger.SysLoginLogService;
+import cn.iocoder.yudao.adminserver.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
 import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
 import cn.iocoder.yudao.adminserver.modules.system.service.social.SysSocialService;
 import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
@@ -158,20 +158,20 @@ public class SysAuthServiceImpl implements SysAuthService {
         // 获得用户
         SysUserDO user = userService.getUserByUsername(username);
         // 插入登录日志
-        SysLoginLogCreateReqVO reqVO = new SysLoginLogCreateReqVO();
-        reqVO.setLogType(logTypeEnum.getType());
-        reqVO.setTraceId(TracerUtils.getTraceId());
+        SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO();
+        reqDTO.setLogType(logTypeEnum.getType());
+        reqDTO.setTraceId(TracerUtils.getTraceId());
         if (user != null) {
-            reqVO.setUserId(user.getId());
+            reqDTO.setUserId(user.getId());
         }
-        reqVO.setUsername(username);
-        reqVO.setUserAgent(ServletUtils.getUserAgent());
-        reqVO.setUserIp(ServletUtils.getClientIP());
-        reqVO.setResult(loginResult.getResult());
-        loginLogService.createLoginLog(reqVO);
+        reqDTO.setUsername(username);
+        reqDTO.setUserAgent(ServletUtils.getUserAgent());
+        reqDTO.setUserIp(ServletUtils.getClientIP());
+        reqDTO.setResult(loginResult.getResult());
+        loginLogService.createLoginLog(reqDTO);
         // 更新最后登录时间
         if (user != null && Objects.equals(SysLoginResultEnum.SUCCESS.getResult(), loginResult.getResult())) {
-
+            userService.updateUserLogin(user.getId(), ServletUtils.getClientIP());
         }
     }
 
@@ -258,14 +258,14 @@ public class SysAuthServiceImpl implements SysAuthService {
     }
 
     private void createLogoutLog(String username) {
-        SysLoginLogCreateReqVO reqVO = new SysLoginLogCreateReqVO();
-        reqVO.setLogType(SysLoginLogTypeEnum.LOGOUT_SELF.getType());
-        reqVO.setTraceId(TracerUtils.getTraceId());
-        reqVO.setUsername(username);
-        reqVO.setUserAgent(ServletUtils.getUserAgent());
-        reqVO.setUserIp(ServletUtils.getClientIP());
-        reqVO.setResult(SysLoginResultEnum.SUCCESS.getResult());
-        loginLogService.createLoginLog(reqVO);
+        SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO();
+        reqDTO.setLogType(SysLoginLogTypeEnum.LOGOUT_SELF.getType());
+        reqDTO.setTraceId(TracerUtils.getTraceId());
+        reqDTO.setUsername(username);
+        reqDTO.setUserAgent(ServletUtils.getUserAgent());
+        reqDTO.setUserIp(ServletUtils.getClientIP());
+        reqDTO.setResult(SysLoginResultEnum.SUCCESS.getResult());
+        loginLogService.createLoginLog(reqDTO);
     }
 
     @Override

+ 16 - 26
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysUserSessionServiceImpl.java

@@ -3,12 +3,7 @@ package cn.iocoder.yudao.adminserver.modules.system.service.auth.impl;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.StrUtil;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.security.config.SecurityProperties;
-import cn.iocoder.yudao.framework.security.core.LoginUser;
-import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
 import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO;
-import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog.SysLoginLogCreateReqVO;
 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.auth.SysUserSessionDO;
 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserDO;
 import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.auth.SysUserSessionMapper;
@@ -17,10 +12,13 @@ import cn.iocoder.yudao.adminserver.modules.system.enums.logger.SysLoginLogTypeE
 import cn.iocoder.yudao.adminserver.modules.system.enums.logger.SysLoginResultEnum;
 import cn.iocoder.yudao.adminserver.modules.system.service.auth.SysUserSessionService;
 import cn.iocoder.yudao.adminserver.modules.system.service.logger.SysLoginLogService;
+import cn.iocoder.yudao.adminserver.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
 import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
-import com.baomidou.mybatisplus.core.conditions.Wrapper;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
+import cn.iocoder.yudao.framework.security.config.SecurityProperties;
+import cn.iocoder.yudao.framework.security.core.LoginUser;
 import com.google.common.collect.Lists;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -62,7 +60,8 @@ public class SysUserSessionServiceImpl implements SysUserSessionService {
         loginUserRedisDAO.set(sessionId, loginUser);
         // 写入 DB 中
         SysUserSessionDO userSession = SysUserSessionDO.builder().id(sessionId)
-                .userId(loginUser.getId()).userIp(userIp).userAgent(userAgent).username(loginUser.getUsername())
+                .userId(loginUser.getId()).userType(UserTypeEnum.ADMIN.getValue())
+                .userIp(userIp).userAgent(userAgent).username(loginUser.getUsername())
                 .sessionTimeout(addTime(Duration.ofMillis(getSessionTimeoutMillis())))
                 .build();
         userSessionMapper.insert(userSession);
@@ -97,15 +96,6 @@ public class SysUserSessionServiceImpl implements SysUserSessionService {
     }
 
     @Override
-    public String getSessionId(String username) {
-        QueryWrapper<SysUserSessionDO> wrapper = new QueryWrapper<>();
-        wrapper.eq("username", username);
-        wrapper.orderByDesc("create_time");
-        SysUserSessionDO sysUserSessionDO = userSessionMapper.selectOne(wrapper);
-        return sysUserSessionDO.getId();
-    }
-
-    @Override
     public Long getSessionTimeoutMillis() {
         return securityProperties.getSessionTimeout().toMillis();
     }
@@ -142,14 +132,14 @@ public class SysUserSessionServiceImpl implements SysUserSessionService {
 
     private void createTimeoutLogoutLog(Collection<SysUserSessionDO> timeoutSessionDOS) {
         for (SysUserSessionDO timeoutSessionDO : timeoutSessionDOS) {
-            SysLoginLogCreateReqVO reqVO = new SysLoginLogCreateReqVO();
-            reqVO.setLogType(SysLoginLogTypeEnum.LOGOUT_TIMEOUT.getType());
-            reqVO.setTraceId(TracerUtils.getTraceId());
-            reqVO.setUsername(timeoutSessionDO.getUsername());
-            reqVO.setUserAgent(timeoutSessionDO.getUserAgent());
-            reqVO.setUserIp(timeoutSessionDO.getUserIp());
-            reqVO.setResult(SysLoginResultEnum.SUCCESS.getResult());
-            loginLogService.createLoginLog(reqVO);
+            SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO();
+            reqDTO.setLogType(SysLoginLogTypeEnum.LOGOUT_TIMEOUT.getType());
+            reqDTO.setTraceId(TracerUtils.getTraceId());
+            reqDTO.setUsername(timeoutSessionDO.getUsername());
+            reqDTO.setUserAgent(timeoutSessionDO.getUserAgent());
+            reqDTO.setUserIp(timeoutSessionDO.getUserIp());
+            reqDTO.setResult(SysLoginResultEnum.SUCCESS.getResult());
+            loginLogService.createLoginLog(reqDTO);
         }
     }
 

+ 3 - 3
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/logger/SysLoginLogService.java

@@ -1,7 +1,7 @@
 package cn.iocoder.yudao.adminserver.modules.system.service.logger;
 
+import cn.iocoder.yudao.adminserver.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog.SysLoginLogCreateReqVO;
 import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog.SysLoginLogExportReqVO;
 import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog.SysLoginLogPageReqVO;
 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.logger.SysLoginLogDO;
@@ -16,9 +16,9 @@ public interface SysLoginLogService {
     /**
      * 创建登录日志
      *
-     * @param reqVO 日志信息
+     * @param reqDTO 日志信息
      */
-    void createLoginLog(SysLoginLogCreateReqVO reqVO);
+    void createLoginLog(SysLoginLogCreateReqDTO reqDTO);
 
     /**
      * 获得登录日志分页

+ 57 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/logger/dto/SysLoginLogCreateReqDTO.java

@@ -0,0 +1,57 @@
+package cn.iocoder.yudao.adminserver.modules.system.service.logger.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+/**
+ * 登录日志创建 Request DTO
+ *
+ * @author 芋道源码
+ */
+@Data
+public class SysLoginLogCreateReqDTO {
+
+    /**
+     * 日志类型
+     */
+    @NotNull(message = "日志类型不能为空")
+    private Integer logType;
+    /**
+     * 链路追踪编号
+     */
+    @NotEmpty(message = "链路追踪编号不能为空")
+    private String traceId;
+
+    /**
+     * 用户编号
+     */
+    private Long userId;
+    /**
+     * 用户账号
+     */
+    @NotBlank(message = "用户账号不能为空")
+    @Size(max = 30, message = "用户账号长度不能超过30个字符")
+    private String username;
+
+    /**
+     * 登录结果
+     */
+    @NotNull(message = "登录结果不能为空")
+    private Integer result;
+
+    /**
+     * 用户 IP
+     */
+    @NotEmpty(message = "用户 IP 不能为空")
+    private String userIp;
+    /**
+     * 浏览器 UserAgent
+     */
+    @NotEmpty(message = "浏览器 UserAgent 不能为空")
+    private String userAgent;
+
+}

+ 5 - 7
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/logger/impl/SysLoginLogServiceImpl.java

@@ -1,16 +1,14 @@
 package cn.iocoder.yudao.adminserver.modules.system.service.logger.impl;
 
-import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserDO;
-import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
-import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog.SysLoginLogCreateReqVO;
 import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog.SysLoginLogExportReqVO;
 import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog.SysLoginLogPageReqVO;
 import cn.iocoder.yudao.adminserver.modules.system.convert.logger.SysLoginLogConvert;
 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.logger.SysLoginLogDO;
 import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.logger.SysLoginLogMapper;
 import cn.iocoder.yudao.adminserver.modules.system.service.logger.SysLoginLogService;
+import cn.iocoder.yudao.adminserver.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
+import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
@@ -26,8 +24,8 @@ public class SysLoginLogServiceImpl implements SysLoginLogService {
     private SysLoginLogMapper loginLogMapper;
 
     @Override
-    public void createLoginLog(SysLoginLogCreateReqVO reqVO) {
-        SysLoginLogDO loginLog = SysLoginLogConvert.INSTANCE.convert(reqVO);
+    public void createLoginLog(SysLoginLogCreateReqDTO reqDTO) {
+        SysLoginLogDO loginLog = SysLoginLogConvert.INSTANCE.convert(reqDTO);
         loginLog.setUserType(UserTypeEnum.ADMIN.getValue());
         // 插入
         loginLogMapper.insert(loginLog);

+ 8 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/SysUserService.java

@@ -42,6 +42,14 @@ public interface SysUserService {
     void updateUser(SysUserUpdateReqVO reqVO);
 
     /**
+     * 更新用户的最后登陆信息
+     *
+     * @param id 用户编号
+     * @param loginIp 登陆 IP
+     */
+    void updateUserLogin(Long id, String loginIp);
+
+    /**
      * 修改用户个人信息
      *
      * @param id 用户编号

+ 5 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/impl/SysUserServiceImpl.java

@@ -85,6 +85,11 @@ public class SysUserServiceImpl implements SysUserService {
     }
 
     @Override
+    public void updateUserLogin(Long id, String loginIp) {
+        userMapper.updateById(new SysUserDO().setId(id).setLoginIp(loginIp).setLoginDate(new Date()));
+    }
+
+    @Override
     public void updateUserProfile(Long id, SysUserProfileUpdateReqVO reqVO) {
         // 校验正确性
         this.checkUserExists(id);

+ 4 - 4
yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/logger/SysLoginLogServiceImplTest.java

@@ -2,9 +2,9 @@ package cn.iocoder.yudao.adminserver.modules.system.service.logger;
 
 import cn.hutool.core.util.RandomUtil;
 import cn.iocoder.yudao.adminserver.BaseDbUnitTest;
+import cn.iocoder.yudao.adminserver.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
-import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog.SysLoginLogCreateReqVO;
 import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog.SysLoginLogExportReqVO;
 import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog.SysLoginLogPageReqVO;
 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.logger.SysLoginLogDO;
@@ -36,7 +36,7 @@ public class SysLoginLogServiceImplTest extends BaseDbUnitTest {
     @Test
     public void testCreateLoginLog() {
         String traceId = TracerUtils.getTraceId();
-        SysLoginLogCreateReqVO reqVO = RandomUtils.randomPojo(SysLoginLogCreateReqVO.class, vo -> {
+        SysLoginLogCreateReqDTO reqDTO = RandomUtils.randomPojo(SysLoginLogCreateReqDTO.class, vo -> {
             // 指定随机的范围,避免超出范围入库失败
             vo.setLogType(RandomUtil.randomEle(SysLoginLogTypeEnum.values()).getType());
             vo.setResult(RandomUtil.randomEle(SysLoginResultEnum.values()).getResult());
@@ -45,11 +45,11 @@ public class SysLoginLogServiceImplTest extends BaseDbUnitTest {
         });
 
         // 执行service方法
-        sysLoginLogService.createLoginLog(reqVO);
+        sysLoginLogService.createLoginLog(reqDTO);
 
         // 断言,忽略基本字段
         SysLoginLogDO sysLoginLogDO = loginLogMapper.selectOne(null);
-        assertPojoEquals(reqVO, sysLoginLogDO);
+        assertPojoEquals(reqDTO, sysLoginLogDO);
     }
 
 

+ 6 - 1
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/convert/package-info.java

@@ -1 +1,6 @@
-package cn.iocoder.yudao.userserver.modules.member.convert;
+/**
+ * 提供 POJO 类的实体转换
+ *
+ * 目前使用 MapStruct 框架
+ */
+package cn.iocoder.yudao.userserver.modules.member.convert;

+ 1 - 0
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md

@@ -0,0 +1 @@
+<http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao>

+ 17 - 0
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/enums/MbrErrorCodeConstants.java

@@ -0,0 +1,17 @@
+package cn.iocoder.yudao.userserver.modules.member.enums;
+
+import cn.iocoder.yudao.framework.common.exception.ErrorCode;
+
+/**
+ * Member 错误码枚举类
+ *
+ * member 系统,使用 1-004-000-000 段
+ */
+public interface MbrErrorCodeConstants {
+
+    // ========== AUTH 模块 1004000000 ==========
+    ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1004000000, "登录失败,账号密码不正确");
+    ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1004000001, "登录失败,账号被禁用");
+    ErrorCode AUTH_LOGIN_FAIL_UNKNOWN = new ErrorCode(1004000002, "登录失败"); // 登录失败的兜底,未知原因
+
+}

+ 75 - 1
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/auth/impl/MbrAuthServiceImpl.java

@@ -1,20 +1,40 @@
 package cn.iocoder.yudao.userserver.modules.member.service.auth.impl;
 
+import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
+import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
 import cn.iocoder.yudao.framework.security.core.LoginUser;
 import cn.iocoder.yudao.userserver.modules.member.controller.auth.vo.MbrAuthLoginReqVO;
 import cn.iocoder.yudao.userserver.modules.member.convert.user.MbrAuthConvert;
 import cn.iocoder.yudao.userserver.modules.member.dal.dataobject.user.MbrUserDO;
+import cn.iocoder.yudao.userserver.modules.member.enums.MbrErrorCodeConstants;
 import cn.iocoder.yudao.userserver.modules.member.service.auth.MbrAuthService;
 import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService;
+import cn.iocoder.yudao.userserver.modules.system.enums.logger.SysLoginLogTypeEnum;
+import cn.iocoder.yudao.userserver.modules.system.enums.logger.SysLoginResultEnum;
+import cn.iocoder.yudao.userserver.modules.system.service.auth.SysUserSessionService;
+import cn.iocoder.yudao.userserver.modules.system.service.logger.SysLoginLogService;
+import cn.iocoder.yudao.userserver.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
+import cn.iocoder.yudao.userserver.modules.system.service.logger.impl.SysLoginLogServiceImpl;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.DisabledException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.stereotype.Service;
+import org.springframework.util.Assert;
 
 import javax.annotation.Resource;
 
+import java.util.Objects;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.userserver.modules.member.enums.MbrErrorCodeConstants.*;
+
 /**
  * Auth Service 实现类
  *
@@ -30,6 +50,10 @@ public class MbrAuthServiceImpl implements MbrAuthService {
 
     @Resource
     private MbrUserService userService;
+    @Resource
+    private SysLoginLogService loginLogService;
+    @Resource
+    private SysUserSessionService userSessionService;
 
     @Override
     public UserDetails loadUserByUsername(String mobile) throws UsernameNotFoundException {
@@ -44,7 +68,57 @@ public class MbrAuthServiceImpl implements MbrAuthService {
 
     @Override
     public String login(MbrAuthLoginReqVO reqVO, String userIp, String userAgent) {
-        return null;
+        // 使用手机 + 密码,进行登录。
+        LoginUser loginUser = this.login0(reqVO.getMobile(), reqVO.getPassword());
+
+        // 缓存登录用户到 Redis 中,返回 sessionId 编号
+        return userSessionService.createUserSession(loginUser, userIp, userAgent);
+    }
+
+    private LoginUser login0(String username, String password) {
+        final SysLoginLogTypeEnum logTypeEnum = SysLoginLogTypeEnum.LOGIN_USERNAME;
+        // 用户验证
+        Authentication authentication;
+        try {
+            // 调用 Spring Security 的 AuthenticationManager#authenticate(...) 方法,使用账号密码进行认证
+            // 在其内部,会调用到 loadUserByUsername 方法,获取 User 信息
+            authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
+        } catch (BadCredentialsException badCredentialsException) {
+            this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.BAD_CREDENTIALS);
+            throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
+        } catch (DisabledException disabledException) {
+            this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.USER_DISABLED);
+            throw exception(AUTH_LOGIN_USER_DISABLED);
+        } catch (AuthenticationException authenticationException) {
+            log.error("[login0][username({}) 发生未知异常]", username, authenticationException);
+            this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.UNKNOWN_ERROR);
+            throw exception(AUTH_LOGIN_FAIL_UNKNOWN);
+        }
+        // 登录成功的日志
+        Assert.notNull(authentication.getPrincipal(), "Principal 不会为空");
+        this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.SUCCESS);
+        return (LoginUser) authentication.getPrincipal();
+    }
+
+    private void createLoginLog(String mobile, SysLoginLogTypeEnum logTypeEnum, SysLoginResultEnum loginResult) {
+        // 获得用户
+        MbrUserDO user = userService.getUserByMobile(mobile);
+        // 插入登录日志
+        SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO();
+        reqDTO.setLogType(logTypeEnum.getType());
+        reqDTO.setTraceId(TracerUtils.getTraceId());
+        if (user != null) {
+            reqDTO.setUserId(user.getId());
+        }
+        reqDTO.setUsername(mobile);
+        reqDTO.setUserAgent(ServletUtils.getUserAgent());
+        reqDTO.setUserIp(ServletUtils.getClientIP());
+        reqDTO.setResult(loginResult.getResult());
+        loginLogService.createLoginLog(reqDTO);
+        // 更新最后登录时间
+        if (user != null && Objects.equals(SysLoginResultEnum.SUCCESS.getResult(), loginResult.getResult())) {
+            userService.updateUserLogin(user.getId(), ServletUtils.getClientIP());
+        }
     }
 
     @Override

+ 8 - 0
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/MbrUserService.java

@@ -17,4 +17,12 @@ public interface MbrUserService {
      */
     MbrUserDO getUserByMobile(String mobile);
 
+    /**
+     * 更新用户的最后登陆信息
+     *
+     * @param id 用户编号
+     * @param loginIp 登陆 IP
+     */
+    void updateUserLogin(Long id, String loginIp);
+
 }

+ 6 - 0
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/impl/MbrUserServiceImpl.java

@@ -8,6 +8,7 @@ import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
 import javax.validation.Valid;
+import java.util.Date;
 
 /**
  * User Service 实现类
@@ -27,4 +28,9 @@ public class MbrUserServiceImpl implements MbrUserService {
         return userMapper.selectByMobile(mobile);
     }
 
+    @Override
+    public void updateUserLogin(Long id, String loginIp) {
+        userMapper.updateById(new MbrUserDO().setId(id).setLoginIp(loginIp).setLoginDate(new Date()));
+    }
+
 }

+ 15 - 0
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/convert/logger/SysLoginLogConvert.java

@@ -0,0 +1,15 @@
+package cn.iocoder.yudao.userserver.modules.system.convert.logger;
+
+import cn.iocoder.yudao.userserver.modules.system.dal.mysql.logger.SysLoginLogDO;
+import cn.iocoder.yudao.userserver.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+@Mapper
+public interface SysLoginLogConvert {
+
+    SysLoginLogConvert INSTANCE = Mappers.getMapper(SysLoginLogConvert.class);
+
+    SysLoginLogDO convert(SysLoginLogCreateReqDTO bean);
+
+}

+ 5 - 0
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/convert/package-info.java

@@ -1 +1,6 @@
+/**
+ * 提供 POJO 类的实体转换
+ *
+ * 目前使用 MapStruct 框架
+ */
 package cn.iocoder.yudao.userserver.modules.system.convert;

+ 1 - 0
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/convert/《芋道 Spring Boot 对象转换 MapStruct 入门》.md

@@ -0,0 +1 @@
+<http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao>

+ 10 - 0
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/dal/dataobject/logger/SysLoginLogMapper.java

@@ -0,0 +1,10 @@
+package cn.iocoder.yudao.userserver.modules.system.dal.dataobject.logger;
+
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.userserver.modules.system.dal.mysql.logger.SysLoginLogDO;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface SysLoginLogMapper extends BaseMapperX<SysLoginLogDO> {
+
+}

+ 70 - 0
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/dal/mysql/logger/SysLoginLogDO.java

@@ -0,0 +1,70 @@
+package cn.iocoder.yudao.userserver.modules.system.dal.mysql.logger;
+
+import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.userserver.modules.system.enums.logger.SysLoginLogTypeEnum;
+import cn.iocoder.yudao.userserver.modules.system.enums.logger.SysLoginResultEnum;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+/**
+ * 登录日志表
+ *
+ * 注意,包括登录和登出两种行为
+ *
+ * @author 芋道源码
+ */
+@TableName("sys_login_log")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class SysLoginLogDO extends BaseDO {
+
+    /**
+     * 日志主键
+     */
+    private Long id;
+    /**
+     * 日志类型
+     *
+     * 枚举 {@link SysLoginLogTypeEnum}
+     */
+    private Integer logType;
+    /**
+     * 链路追踪编号
+     */
+    private String traceId;
+    /**
+     * 用户编号
+     */
+    private Long userId;
+    /**
+     * 用户类型
+     *
+     * 枚举 {@link UserTypeEnum}
+     */
+    private Integer userType;
+    /**
+     * 用户账号
+     *
+     * 冗余,因为账号可以变更
+     */
+    private String username;
+    /**
+     * 登录结果
+     *
+     * 枚举 {@link SysLoginResultEnum}
+     */
+    private Integer result;
+    /**
+     * 用户 IP
+     */
+    private String userIp;
+    /**
+     * 浏览器 UA
+     */
+    private String userAgent;
+
+}

+ 0 - 1
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/dal/mysql/package-info.java

@@ -1 +0,0 @@
-package cn.iocoder.yudao.userserver.modules.system.dal.mysql;

+ 29 - 0
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/enums/logger/SysLoginLogTypeEnum.java

@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.userserver.modules.system.enums.logger;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 登录日志的类型枚举
+ */
+@Getter
+@AllArgsConstructor
+public enum SysLoginLogTypeEnum {
+
+    LOGIN_USERNAME(100), // 使用账号登录
+    LOGIN_SOCIAL(101), // 使用社交登录
+    LOGIN_MOCK(102), // 使用 Mock 登录
+    LOGIN_MOBILE(103), // 使用手机登陆
+    LOGIN_SMS(104), // 使用短信登陆
+
+    LOGOUT_SELF(200),  // 自己主动登出
+    LOGOUT_TIMEOUT(201), // 超时登出
+    LOGOUT_DELETE(202), // 强制退出
+    ;
+
+    /**
+     * 日志类型
+     */
+    private final Integer type;
+
+}

+ 27 - 0
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/enums/logger/SysLoginResultEnum.java

@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.userserver.modules.system.enums.logger;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 登录结果的枚举类
+ */
+@Getter
+@AllArgsConstructor
+public enum SysLoginResultEnum {
+
+    SUCCESS(0), // 成功
+    BAD_CREDENTIALS(10), // 账号或密码不正确
+    USER_DISABLED(20), // 用户被禁用
+    CAPTCHA_NOT_FOUND(30), // 图片验证码不存在
+    CAPTCHA_CODE_ERROR(31), // 图片验证码不正确
+
+    UNKNOWN_ERROR(100), // 未知异常
+    ;
+
+    /**
+     * 结果
+     */
+    private final Integer result;
+
+}

+ 1 - 0
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/enums/package-info.java

@@ -0,0 +1 @@
+package cn.iocoder.yudao.userserver.modules.system.enums;

+ 59 - 0
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/auth/SysUserSessionService.java

@@ -0,0 +1,59 @@
+package cn.iocoder.yudao.userserver.modules.system.service.auth;
+
+import cn.iocoder.yudao.framework.security.core.LoginUser;
+
+/**
+ * 在线用户 Session Service 接口
+ *
+ * @author 芋道源码
+ */
+public interface SysUserSessionService {
+
+    /**
+     * 创建在线用户 Session
+     *
+     * @param loginUser 登录用户
+     * @param userIp 用户 IP
+     * @param userAgent 用户 UA
+     * @return Session 编号
+     */
+    String createUserSession(LoginUser loginUser, String userIp, String userAgent);
+
+    /**
+     * 刷新在线用户 Session 的更新时间
+     *
+     * @param sessionId Session 编号
+     * @param loginUser 登录用户
+     */
+    void refreshUserSession(String sessionId, LoginUser loginUser);
+
+    /**
+     * 删除在线用户 Session
+     *
+     * @param sessionId Session 编号
+     */
+    void deleteUserSession(String sessionId);
+
+    /**
+     * 获得 Session 编号对应的在线用户
+     *
+     * @param sessionId Session 编号
+     * @return 在线用户
+     */
+    LoginUser getLoginUser(String sessionId);
+
+    /**
+     * 获取当前登录用户信息
+     * @param username 用户名称
+     * @return 在线用户
+     */
+    String getSessionId(String username);
+
+    /**
+     * 获得 Session 超时时间,单位:毫秒
+     *
+     * @return 超时时间
+     */
+    Long getSessionTimeoutMillis();
+
+}

+ 47 - 0
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/auth/impl/SysUserSessionServiceImpl.java

@@ -0,0 +1,47 @@
+package cn.iocoder.yudao.userserver.modules.system.service.auth.impl;
+
+import cn.iocoder.yudao.framework.security.core.LoginUser;
+import cn.iocoder.yudao.userserver.modules.system.service.auth.SysUserSessionService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * 在线用户 Session Service 实现类
+ *
+ * @author 芋道源码
+ */
+@Service
+@Slf4j
+public class SysUserSessionServiceImpl implements SysUserSessionService {
+
+    @Override
+    public String createUserSession(LoginUser loginUser, String userIp, String userAgent) {
+        return null;
+    }
+
+    @Override
+    public void refreshUserSession(String sessionId, LoginUser loginUser) {
+
+    }
+
+    @Override
+    public void deleteUserSession(String sessionId) {
+
+    }
+
+    @Override
+    public LoginUser getLoginUser(String sessionId) {
+        return null;
+    }
+
+    @Override
+    public String getSessionId(String username) {
+        return null;
+    }
+
+    @Override
+    public Long getSessionTimeoutMillis() {
+        return null;
+    }
+
+}

+ 17 - 0
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/logger/SysLoginLogService.java

@@ -0,0 +1,17 @@
+package cn.iocoder.yudao.userserver.modules.system.service.logger;
+
+import cn.iocoder.yudao.userserver.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
+
+/**
+ * 登录日志 Service 接口
+ */
+public interface SysLoginLogService {
+
+    /**
+     * 创建登录日志
+     *
+     * @param reqDTO 日志信息
+     */
+    void createLoginLog(SysLoginLogCreateReqDTO reqDTO);
+
+}

+ 57 - 0
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/logger/dto/SysLoginLogCreateReqDTO.java

@@ -0,0 +1,57 @@
+package cn.iocoder.yudao.userserver.modules.system.service.logger.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+/**
+ * 登录日志创建 Request DTO
+ *
+ * @author 芋道源码
+ */
+@Data
+public class SysLoginLogCreateReqDTO {
+
+    /**
+     * 日志类型
+     */
+    @NotNull(message = "日志类型不能为空")
+    private Integer logType;
+    /**
+     * 链路追踪编号
+     */
+    @NotEmpty(message = "链路追踪编号不能为空")
+    private String traceId;
+
+    /**
+     * 用户编号
+     */
+    private Long userId;
+    /**
+     * 用户账号
+     */
+    @NotBlank(message = "用户账号不能为空")
+    @Size(max = 30, message = "用户账号长度不能超过30个字符")
+    private String username;
+
+    /**
+     * 登录结果
+     */
+    @NotNull(message = "登录结果不能为空")
+    private Integer result;
+
+    /**
+     * 用户 IP
+     */
+    @NotEmpty(message = "用户 IP 不能为空")
+    private String userIp;
+    /**
+     * 浏览器 UserAgent
+     */
+    @NotEmpty(message = "浏览器 UserAgent 不能为空")
+    private String userAgent;
+
+}

+ 30 - 0
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/logger/impl/SysLoginLogServiceImpl.java

@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.userserver.modules.system.service.logger.impl;
+
+import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
+import cn.iocoder.yudao.userserver.modules.system.convert.logger.SysLoginLogConvert;
+import cn.iocoder.yudao.userserver.modules.system.dal.dataobject.logger.SysLoginLogMapper;
+import cn.iocoder.yudao.userserver.modules.system.dal.mysql.logger.SysLoginLogDO;
+import cn.iocoder.yudao.userserver.modules.system.service.logger.SysLoginLogService;
+import cn.iocoder.yudao.userserver.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+/**
+ * 登录日志 Service 实现
+ */
+@Service
+public class SysLoginLogServiceImpl implements SysLoginLogService {
+
+    @Resource
+    private SysLoginLogMapper loginLogMapper;
+
+    @Override
+    public void createLoginLog(SysLoginLogCreateReqDTO reqDTO) {
+        SysLoginLogDO loginLog = SysLoginLogConvert.INSTANCE.convert(reqDTO);
+        loginLog.setUserType(UserTypeEnum.MEMBER.getValue());
+        // 插入
+        loginLogMapper.insert(loginLog);
+    }
+
+}