Commit 083dac77e1ef5e6bc04ce09fe03c31258e2ed93a

Authored by YunaiV
1 parent cbb11986

接入登陆日志

Showing 17 changed files with 236 additions and 52 deletions
ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java
1 package com.ruoyi.web.controller.monitor; 1 package com.ruoyi.web.controller.monitor;
2 2
3 import java.util.List; 3 import java.util.List;
  4 +
4 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.beans.factory.annotation.Autowired;
5 import org.springframework.security.access.prepost.PreAuthorize; 6 import org.springframework.security.access.prepost.PreAuthorize;
6 import org.springframework.web.bind.annotation.DeleteMapping; 7 import org.springframework.web.bind.annotation.DeleteMapping;
@@ -24,15 +25,14 @@ import com.ruoyi.system.service.ISysLogininforService; @@ -24,15 +25,14 @@ import com.ruoyi.system.service.ISysLogininforService;
24 */ 25 */
25 @RestController 26 @RestController
26 @RequestMapping("/monitor/logininfor") 27 @RequestMapping("/monitor/logininfor")
27 -public class SysLogininforController extends BaseController  
28 -{ 28 +public class SysLogininforController extends BaseController {
  29 +
29 @Autowired 30 @Autowired
30 private ISysLogininforService logininforService; 31 private ISysLogininforService logininforService;
31 32
32 @PreAuthorize("@ss.hasPermi('monitor:logininfor:list')") 33 @PreAuthorize("@ss.hasPermi('monitor:logininfor:list')")
33 @GetMapping("/list") 34 @GetMapping("/list")
34 - public TableDataInfo list(SysLogininfor logininfor)  
35 - { 35 + public TableDataInfo list(SysLogininfor logininfor) {
36 startPage(); 36 startPage();
37 List<SysLogininfor> list = logininforService.selectLogininforList(logininfor); 37 List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
38 return getDataTable(list); 38 return getDataTable(list);
@@ -41,8 +41,7 @@ public class SysLogininforController extends BaseController @@ -41,8 +41,7 @@ public class SysLogininforController extends BaseController
41 @Log(title = "登录日志", businessType = BusinessType.EXPORT) 41 @Log(title = "登录日志", businessType = BusinessType.EXPORT)
42 @PreAuthorize("@ss.hasPermi('monitor:logininfor:export')") 42 @PreAuthorize("@ss.hasPermi('monitor:logininfor:export')")
43 @GetMapping("/export") 43 @GetMapping("/export")
44 - public AjaxResult export(SysLogininfor logininfor)  
45 - { 44 + public AjaxResult export(SysLogininfor logininfor) {
46 List<SysLogininfor> list = logininforService.selectLogininforList(logininfor); 45 List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
47 ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class); 46 ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class);
48 return util.exportExcel(list, "登录日志"); 47 return util.exportExcel(list, "登录日志");
src/main/java/cn/iocoder/dashboard/framework/logger/operatelog/core/aop/OperateLogAspect.java
@@ -24,9 +24,6 @@ import org.aspectj.lang.reflect.MethodSignature; @@ -24,9 +24,6 @@ import org.aspectj.lang.reflect.MethodSignature;
24 import org.springframework.core.annotation.AnnotationUtils; 24 import org.springframework.core.annotation.AnnotationUtils;
25 import org.springframework.web.bind.annotation.RequestMapping; 25 import org.springframework.web.bind.annotation.RequestMapping;
26 import org.springframework.web.bind.annotation.RequestMethod; 26 import org.springframework.web.bind.annotation.RequestMethod;
27 -import org.springframework.web.context.request.RequestAttributes;  
28 -import org.springframework.web.context.request.RequestContextHolder;  
29 -import org.springframework.web.context.request.ServletRequestAttributes;  
30 import org.springframework.web.multipart.MultipartFile; 27 import org.springframework.web.multipart.MultipartFile;
31 28
32 import javax.annotation.Resource; 29 import javax.annotation.Resource;
@@ -196,11 +193,10 @@ public class OperateLogAspect { @@ -196,11 +193,10 @@ public class OperateLogAspect {
196 193
197 private static void fillRequestFields(SysOperateLogCreateReqVO operateLogVO) { 194 private static void fillRequestFields(SysOperateLogCreateReqVO operateLogVO) {
198 // 获得 Request 对象 195 // 获得 Request 对象
199 - RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();  
200 - if (!(requestAttributes instanceof ServletRequestAttributes)) { 196 + HttpServletRequest request = ServletUtils.getRequest();
  197 + if (request == null) {
201 return; 198 return;
202 } 199 }
203 - HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();  
204 // 补全请求信息 200 // 补全请求信息
205 operateLogVO.setRequestMethod(request.getMethod()); 201 operateLogVO.setRequestMethod(request.getMethod());
206 operateLogVO.setRequestUrl(request.getRequestURI()); 202 operateLogVO.setRequestUrl(request.getRequestURI());
src/main/java/cn/iocoder/dashboard/modules/system/controller/logger/SysLoginLogController.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.logger;
  2 +
  3 +public class SysLoginLogController {
  4 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/logger/vo/loginlog/SysLoginLogBaseVO.java
@@ -15,27 +15,23 @@ import javax.validation.constraints.Size; @@ -15,27 +15,23 @@ import javax.validation.constraints.Size;
15 @Data 15 @Data
16 public class SysLoginLogBaseVO { 16 public class SysLoginLogBaseVO {
17 17
  18 + @ApiModelProperty(value = "日志类型", required = true, example = "1", notes = "参见 SysLoginLogTypeEnum 枚举类")
  19 + @NotNull(message = "日志类型不能为空")
  20 + private Integer logType;
  21 +
18 @ApiModelProperty(value = "链路追踪编号", required = true, example = "89aca178-a370-411c-ae02-3f0d672be4ab") 22 @ApiModelProperty(value = "链路追踪编号", required = true, example = "89aca178-a370-411c-ae02-3f0d672be4ab")
19 @NotEmpty(message = "链路追踪编号不能为空") 23 @NotEmpty(message = "链路追踪编号不能为空")
20 private String traceId; 24 private String traceId;
21 25
22 - @ApiModelProperty(value = "用户编号", required = true, example = "1024")  
23 - @NotNull(message = "用户编号不能为空")  
24 - private Long userId;  
25 -  
26 @ApiModelProperty(value = "用户账号", required = true, example = "yudao") 26 @ApiModelProperty(value = "用户账号", required = true, example = "yudao")
27 @NotBlank(message = "用户账号不能为空") 27 @NotBlank(message = "用户账号不能为空")
28 @Size(max = 30, message = "用户账号长度不能超过30个字符") 28 @Size(max = 30, message = "用户账号长度不能超过30个字符")
29 private String username; 29 private String username;
30 30
31 -  
32 @ApiModelProperty(value = "登陆结果", required = true, example = "1", notes = "参见 SysLoginResultEnum 枚举类") 31 @ApiModelProperty(value = "登陆结果", required = true, example = "1", notes = "参见 SysLoginResultEnum 枚举类")
33 @NotNull(message = "登陆结果不能为空") 32 @NotNull(message = "登陆结果不能为空")
34 private Integer result; 33 private Integer result;
35 34
36 - @ApiModelProperty(value = "操作明细", example = "修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。")  
37 - private String content;  
38 -  
39 @ApiModelProperty(value = "用户 IP", required = true, example = "127.0.0.1") 35 @ApiModelProperty(value = "用户 IP", required = true, example = "127.0.0.1")
40 @NotEmpty(message = "用户 IP 不能为空") 36 @NotEmpty(message = "用户 IP 不能为空")
41 private String userIp; 37 private String userIp;
src/main/java/cn/iocoder/dashboard/modules/system/controller/logger/vo/loginlog/SysLoginLogCreateReqVO.java
1 package cn.iocoder.dashboard.modules.system.controller.logger.vo.loginlog; 1 package cn.iocoder.dashboard.modules.system.controller.logger.vo.loginlog;
2 2
3 -import cn.iocoder.dashboard.modules.system.controller.logger.vo.operatelog.SysOperateLogCreateReqVO;  
4 import io.swagger.annotations.ApiModel; 3 import io.swagger.annotations.ApiModel;
5 import lombok.Data; 4 import lombok.Data;
6 import lombok.EqualsAndHashCode; 5 import lombok.EqualsAndHashCode;
@@ -11,5 +10,5 @@ import lombok.ToString; @@ -11,5 +10,5 @@ import lombok.ToString;
11 @Data 10 @Data
12 @EqualsAndHashCode(callSuper = true) 11 @EqualsAndHashCode(callSuper = true)
13 @ToString(callSuper = true) 12 @ToString(callSuper = true)
14 -public class SysLoginLogCreateReqVO extends SysOperateLogCreateReqVO { 13 +public class SysLoginLogCreateReqVO extends SysLoginLogBaseVO {
15 } 14 }
src/main/java/cn/iocoder/dashboard/modules/system/convert/logger/SysLoginLogConvert.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.convert.logger;
  2 +
  3 +import cn.iocoder.dashboard.modules.system.controller.logger.vo.loginlog.SysLoginLogCreateReqVO;
  4 +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysLoginLogDO;
  5 +import org.mapstruct.Mapper;
  6 +import org.mapstruct.factory.Mappers;
  7 +
  8 +@Mapper
  9 +public interface SysLoginLogConvert {
  10 +
  11 + SysLoginLogConvert INSTANCE = Mappers.getMapper(SysLoginLogConvert.class);
  12 +
  13 + SysLoginLogDO convert(SysLoginLogCreateReqVO bean);
  14 +
  15 +}
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/logger/SysLoginLogMapper.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.dal.mysql.dao.logger;
  2 +
  3 +import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX;
  4 +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysLoginLogDO;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +
  7 +@Mapper
  8 +public interface SysLoginLogMapper extends BaseMapperX<SysLoginLogDO> {
  9 +}
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/logger/SysLoginLogDO.java
1 package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger; 1 package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger;
2 2
3 import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; 3 import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
4 -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO; 4 +import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginLogTypeEnum;
5 import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginResultEnum; 5 import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginResultEnum;
6 import com.baomidou.mybatisplus.annotation.TableName; 6 import com.baomidou.mybatisplus.annotation.TableName;
  7 +import lombok.Data;
  8 +import lombok.EqualsAndHashCode;
  9 +import lombok.ToString;
7 10
8 /** 11 /**
9 - * 系统访问记录表 12 + * 登陆日志表
  13 + *
  14 + * 注意,包括登陆和登出两种行为
10 * 15 *
11 * @author ruoyi 16 * @author ruoyi
12 */ 17 */
13 -@TableName("用户登陆日志") 18 +@TableName("sys_login_log")
  19 +@Data
  20 +@EqualsAndHashCode(callSuper = true)
  21 +@ToString(callSuper = true)
14 public class SysLoginLogDO extends BaseDO { 22 public class SysLoginLogDO extends BaseDO {
15 23
16 /** 24 /**
@@ -18,15 +26,15 @@ public class SysLoginLogDO extends BaseDO { @@ -18,15 +26,15 @@ public class SysLoginLogDO extends BaseDO {
18 */ 26 */
19 private Long id; 27 private Long id;
20 /** 28 /**
21 - * 链路追踪编号 29 + * 日志类型
  30 + *
  31 + * 枚举 {@link SysLoginLogTypeEnum}
22 */ 32 */
23 - private String traceId; 33 + private Integer logType;
24 /** 34 /**
25 - * 用户编号  
26 - *  
27 - * 外键 {@link SysUserDO#getId()} 35 + * 链路追踪编号
28 */ 36 */
29 - private Long userId; 37 + private String traceId;
30 /** 38 /**
31 * 用户账号 39 * 用户账号
32 * 40 *
@@ -39,12 +47,10 @@ public class SysLoginLogDO extends BaseDO { @@ -39,12 +47,10 @@ public class SysLoginLogDO extends BaseDO {
39 * 枚举 {@link SysLoginResultEnum} 47 * 枚举 {@link SysLoginResultEnum}
40 */ 48 */
41 private Integer result; 49 private Integer result;
42 -  
43 /** 50 /**
44 * 用户 IP 51 * 用户 IP
45 */ 52 */
46 private String userIp; 53 private String userIp;
47 -  
48 /** 54 /**
49 * 浏览器 UA 55 * 浏览器 UA
50 */ 56 */
src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java
@@ -13,6 +13,8 @@ public interface SysErrorCodeConstants { @@ -13,6 +13,8 @@ public interface SysErrorCodeConstants {
13 ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1002000000, "登录失败,账号密码不正确"); 13 ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1002000000, "登录失败,账号密码不正确");
14 ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1002000001, "登录失败,账号被禁用"); 14 ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1002000001, "登录失败,账号被禁用");
15 ErrorCode AUTH_LOGIN_FAIL_UNKNOWN = new ErrorCode(1002000002, "登录失败"); // 登陆失败的兜底,位置原因 15 ErrorCode AUTH_LOGIN_FAIL_UNKNOWN = new ErrorCode(1002000002, "登录失败"); // 登陆失败的兜底,位置原因
  16 + ErrorCode AUTH_LOGIN_CAPTCHA_NOT_FOUND = new ErrorCode(1002000003, "验证码不存在");
  17 + ErrorCode AUTH_LOGIN_CAPTCHA_CODE_ERROR = new ErrorCode(1002000004, "验证码不正确");
16 18
17 // ========== TOKEN 模块 1002001000 ========== 19 // ========== TOKEN 模块 1002001000 ==========
18 ErrorCode TOKEN_EXPIRED = new ErrorCode(1002001000, "Token 已经过期"); 20 ErrorCode TOKEN_EXPIRED = new ErrorCode(1002001000, "Token 已经过期");
src/main/java/cn/iocoder/dashboard/modules/system/enums/logger/SysLoginLogTypeEnum.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.enums.logger;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * 登陆日志的类型枚举
  8 + */
  9 +@Getter
  10 +@AllArgsConstructor
  11 +public enum SysLoginLogTypeEnum {
  12 +
  13 + LOGIN(1),
  14 + LOGOUT(2);
  15 +
  16 + /**
  17 + * 日志类型
  18 + */
  19 + private final Integer type;
  20 +
  21 +}
src/main/java/cn/iocoder/dashboard/modules/system/enums/logger/SysLoginResultEnum.java
@@ -11,6 +11,12 @@ import lombok.Getter; @@ -11,6 +11,12 @@ import lombok.Getter;
11 public enum SysLoginResultEnum { 11 public enum SysLoginResultEnum {
12 12
13 SUCCESS(0), // 成功 13 SUCCESS(0), // 成功
  14 + BAD_CREDENTIALS(10), // 账号或密码不正确
  15 + USER_DISABLED(20), // 账号或密码不正确
  16 + CAPTCHA_NOT_FOUND(30), // 验证码不存在
  17 + CAPTCHA_CODE_ERROR(31), // 验证码不正确
  18 +
  19 + UNKNOWN_ERROR(100), // 未知异常
14 ; 20 ;
15 21
16 /** 22 /**
src/main/java/cn/iocoder/dashboard/modules/system/service/auth/impl/SysAuthServiceImpl.java
@@ -3,16 +3,24 @@ package cn.iocoder.dashboard.modules.system.service.auth.impl; @@ -3,16 +3,24 @@ package cn.iocoder.dashboard.modules.system.service.auth.impl;
3 import cn.hutool.core.util.IdUtil; 3 import cn.hutool.core.util.IdUtil;
4 import cn.hutool.core.util.StrUtil; 4 import cn.hutool.core.util.StrUtil;
5 import cn.iocoder.dashboard.common.enums.CommonStatusEnum; 5 import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
  6 +import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
6 import cn.iocoder.dashboard.framework.security.config.SecurityProperties; 7 import cn.iocoder.dashboard.framework.security.config.SecurityProperties;
7 import cn.iocoder.dashboard.framework.security.core.LoginUser; 8 import cn.iocoder.dashboard.framework.security.core.LoginUser;
  9 +import cn.iocoder.dashboard.framework.tracer.core.util.TracerUtils;
  10 +import cn.iocoder.dashboard.modules.system.controller.logger.vo.loginlog.SysLoginLogCreateReqVO;
8 import cn.iocoder.dashboard.modules.system.convert.auth.SysAuthConvert; 11 import cn.iocoder.dashboard.modules.system.convert.auth.SysAuthConvert;
9 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO; 12 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
10 import cn.iocoder.dashboard.modules.system.dal.redis.dao.auth.SysLoginUserRedisDAO; 13 import cn.iocoder.dashboard.modules.system.dal.redis.dao.auth.SysLoginUserRedisDAO;
  14 +import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginLogTypeEnum;
  15 +import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginResultEnum;
11 import cn.iocoder.dashboard.modules.system.service.auth.SysAuthService; 16 import cn.iocoder.dashboard.modules.system.service.auth.SysAuthService;
12 import cn.iocoder.dashboard.modules.system.service.auth.SysTokenService; 17 import cn.iocoder.dashboard.modules.system.service.auth.SysTokenService;
  18 +import cn.iocoder.dashboard.modules.system.service.common.SysCaptchaService;
  19 +import cn.iocoder.dashboard.modules.system.service.logger.SysLoginLogService;
13 import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; 20 import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService;
14 import cn.iocoder.dashboard.modules.system.service.user.SysUserService; 21 import cn.iocoder.dashboard.modules.system.service.user.SysUserService;
15 import cn.iocoder.dashboard.util.date.DateUtils; 22 import cn.iocoder.dashboard.util.date.DateUtils;
  23 +import cn.iocoder.dashboard.util.servlet.ServletUtils;
16 import io.jsonwebtoken.Claims; 24 import io.jsonwebtoken.Claims;
17 import io.jsonwebtoken.JwtException; 25 import io.jsonwebtoken.JwtException;
18 import lombok.extern.slf4j.Slf4j; 26 import lombok.extern.slf4j.Slf4j;
@@ -55,6 +63,10 @@ public class SysAuthServiceImpl implements SysAuthService { @@ -55,6 +63,10 @@ public class SysAuthServiceImpl implements SysAuthService {
55 private SysUserService userService; 63 private SysUserService userService;
56 @Resource 64 @Resource
57 private SysPermissionService permissionService; 65 private SysPermissionService permissionService;
  66 + @Resource
  67 + private SysCaptchaService captchaService;
  68 + @Resource
  69 + private SysLoginLogService loginLogService;
58 70
59 @Resource 71 @Resource
60 private SysLoginUserRedisDAO loginUserRedisDAO; 72 private SysLoginUserRedisDAO loginUserRedisDAO;
@@ -87,7 +99,7 @@ public class SysAuthServiceImpl implements SysAuthService { @@ -87,7 +99,7 @@ public class SysAuthServiceImpl implements SysAuthService {
87 @Override 99 @Override
88 public String login(String username, String password, String captchaUUID, String captchaCode) { 100 public String login(String username, String password, String captchaUUID, String captchaCode) {
89 // 判断验证码是否正确 101 // 判断验证码是否正确
90 - this.verifyCaptcha(captchaUUID, captchaCode); 102 + this.verifyCaptcha(username, captchaUUID, captchaCode);
91 103
92 // 使用账号密码,进行登陆。 104 // 使用账号密码,进行登陆。
93 LoginUser loginUser = this.login0(username, password); 105 LoginUser loginUser = this.login0(username, password);
@@ -102,18 +114,20 @@ public class SysAuthServiceImpl implements SysAuthService { @@ -102,18 +114,20 @@ public class SysAuthServiceImpl implements SysAuthService {
102 return tokenService.createToken(sessionId); 114 return tokenService.createToken(sessionId);
103 } 115 }
104 116
105 - private void verifyCaptcha(String captchaUUID, String captchaCode) {  
106 - // String verifyKey = Constants.CAPTCHA_CODE_KEY + captchaUUID;  
107 -// String captcha = redisCache.getCacheObject(verifyKey);  
108 -// redisCache.deleteObject(verifyKey);  
109 -// if (captcha == null) {  
110 -// AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));  
111 -// throw new CaptchaExpireException();  
112 -// }  
113 -// if (!code.equalsIgnoreCase(captcha)) {  
114 -// AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));  
115 -// throw new CaptchaException();  
116 -// } 117 + private void verifyCaptcha(String username, String captchaUUID, String captchaCode) {
  118 + String code = captchaService.getCaptchaCode(captchaUUID);
  119 + // 验证码不存在
  120 + if (code == null) {
  121 + this.createLoginLog(username, SysLoginResultEnum.CAPTCHA_NOT_FOUND);
  122 + throw ServiceExceptionUtil.exception(AUTH_LOGIN_CAPTCHA_NOT_FOUND);
  123 + }
  124 + // 验证码不正确
  125 + if (!code.equals(captchaCode)) {
  126 + this.createLoginLog(username, SysLoginResultEnum.CAPTCHA_CODE_ERROR);
  127 + throw ServiceExceptionUtil.exception(AUTH_LOGIN_CAPTCHA_CODE_ERROR);
  128 + }
  129 + // 正确,所以要删除下验证码
  130 + captchaService.deleteCaptchaCode(captchaUUID);
117 } 131 }
118 132
119 private LoginUser login0(String username, String password) { 133 private LoginUser login0(String username, String password) {
@@ -124,22 +138,33 @@ public class SysAuthServiceImpl implements SysAuthService { @@ -124,22 +138,33 @@ public class SysAuthServiceImpl implements SysAuthService {
124 // 在其内部,会调用到 loadUserByUsername 方法,获取 User 信息 138 // 在其内部,会调用到 loadUserByUsername 方法,获取 User 信息
125 authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password)); 139 authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
126 } catch (BadCredentialsException badCredentialsException) { 140 } catch (BadCredentialsException badCredentialsException) {
127 - // TODO 日志优化  
128 -// AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); 141 + this.createLoginLog(username, SysLoginResultEnum.BAD_CREDENTIALS);
129 throw exception(AUTH_LOGIN_BAD_CREDENTIALS); 142 throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
130 } catch (DisabledException disabledException) { 143 } catch (DisabledException disabledException) {
131 - // TODO 日志优化 144 + this.createLoginLog(username, SysLoginResultEnum.USER_DISABLED);
132 throw exception(AUTH_LOGIN_USER_DISABLED); 145 throw exception(AUTH_LOGIN_USER_DISABLED);
133 } catch (AuthenticationException authenticationException) { 146 } catch (AuthenticationException authenticationException) {
134 - // TODO 日志优化 147 + log.error("[login0][username({}) 发生未知异常]", username, authenticationException);
  148 + this.createLoginLog(username, SysLoginResultEnum.UNKNOWN_ERROR);
135 throw exception(AUTH_LOGIN_FAIL_UNKNOWN); 149 throw exception(AUTH_LOGIN_FAIL_UNKNOWN);
136 } 150 }
137 - // TODO 需要优化  
138 -// AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"))); 151 + // 登陆成功
139 Assert.notNull(authentication.getPrincipal(), "Principal 不会为空"); 152 Assert.notNull(authentication.getPrincipal(), "Principal 不会为空");
  153 + this.createLoginLog(username, SysLoginResultEnum.SUCCESS);
140 return (LoginUser) authentication.getPrincipal(); 154 return (LoginUser) authentication.getPrincipal();
141 } 155 }
142 156
  157 + private void createLoginLog(String username, SysLoginResultEnum loginResult) {
  158 + SysLoginLogCreateReqVO reqVO = new SysLoginLogCreateReqVO();
  159 + reqVO.setLogType(SysLoginLogTypeEnum.LOGIN.getType());
  160 + reqVO.setTraceId(TracerUtils.getTraceId());
  161 + reqVO.setUsername(username);
  162 + reqVO.setUserAgent(ServletUtils.getUserAgent());
  163 + reqVO.setUserIp(ServletUtils.getClientIP());
  164 + reqVO.setResult(loginResult.getResult());
  165 + loginLogService.createLoginLog(reqVO);
  166 + }
  167 +
143 /** 168 /**
144 * 获得 User 拥有的角色编号数组 169 * 获得 User 拥有的角色编号数组
145 * 170 *
src/main/java/cn/iocoder/dashboard/modules/system/service/common/SysCaptchaService.java
@@ -7,6 +7,26 @@ import cn.iocoder.dashboard.modules.system.controller.common.vo.SysCaptchaImageR @@ -7,6 +7,26 @@ import cn.iocoder.dashboard.modules.system.controller.common.vo.SysCaptchaImageR
7 */ 7 */
8 public interface SysCaptchaService { 8 public interface SysCaptchaService {
9 9
  10 + /**
  11 + * 获得验证码图片
  12 + *
  13 + * @return 验证码图片
  14 + */
10 SysCaptchaImageRespVO getCaptchaImage(); 15 SysCaptchaImageRespVO getCaptchaImage();
11 16
  17 + /**
  18 + * 获得 uuid 对应的验证码
  19 + *
  20 + * @param uuid 验证码编号
  21 + * @return 验证码
  22 + */
  23 + String getCaptchaCode(String uuid);
  24 +
  25 + /**
  26 + * 删除 uuid 对应的验证码
  27 + *
  28 + * @param uuid 验证码编号
  29 + */
  30 + void deleteCaptchaCode(String uuid);
  31 +
12 } 32 }
src/main/java/cn/iocoder/dashboard/modules/system/service/common/impl/SysCaptchaServiceImpl.java
@@ -35,4 +35,14 @@ public class SysCaptchaServiceImpl implements SysCaptchaService { @@ -35,4 +35,14 @@ public class SysCaptchaServiceImpl implements SysCaptchaService {
35 return SysCaptchaConvert.INSTANCE.convert(uuid, captcha); 35 return SysCaptchaConvert.INSTANCE.convert(uuid, captcha);
36 } 36 }
37 37
  38 + @Override
  39 + public String getCaptchaCode(String uuid) {
  40 + return captchaRedisDAO.get(uuid);
  41 + }
  42 +
  43 + @Override
  44 + public void deleteCaptchaCode(String uuid) {
  45 + captchaRedisDAO.delete(uuid);
  46 + }
  47 +
38 } 48 }
src/main/java/cn/iocoder/dashboard/modules/system/service/logger/SysLoginLogService.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.service.logger;
  2 +
  3 +import cn.iocoder.dashboard.modules.system.controller.logger.vo.loginlog.SysLoginLogCreateReqVO;
  4 +
  5 +/**
  6 + * 登陆日志 Service 接口
  7 + */
  8 +public interface SysLoginLogService {
  9 +
  10 + /**
  11 + * 创建登陆日志
  12 + *
  13 + * @param reqVO 日志信息
  14 + */
  15 + void createLoginLog(SysLoginLogCreateReqVO reqVO);
  16 +
  17 +}
src/main/java/cn/iocoder/dashboard/modules/system/service/logger/impl/SysLoginLogServiceImpl.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.service.logger.impl;
  2 +
  3 +import cn.iocoder.dashboard.modules.system.controller.logger.vo.loginlog.SysLoginLogCreateReqVO;
  4 +import cn.iocoder.dashboard.modules.system.convert.logger.SysLoginLogConvert;
  5 +import cn.iocoder.dashboard.modules.system.dal.mysql.dao.logger.SysLoginLogMapper;
  6 +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysLoginLogDO;
  7 +import cn.iocoder.dashboard.modules.system.service.logger.SysLoginLogService;
  8 +import org.springframework.stereotype.Service;
  9 +
  10 +import javax.annotation.Resource;
  11 +
  12 +/**
  13 + * 登陆日志 Service 实现
  14 + */
  15 +@Service
  16 +public class SysLoginLogServiceImpl implements SysLoginLogService {
  17 +
  18 + @Resource
  19 + private SysLoginLogMapper loginLogMapper;
  20 +
  21 + @Override
  22 + public void createLoginLog(SysLoginLogCreateReqVO reqVO) {
  23 + SysLoginLogDO loginLog = SysLoginLogConvert.INSTANCE.convert(reqVO);
  24 + loginLogMapper.insert(loginLog);
  25 + }
  26 +
  27 +}
src/main/java/cn/iocoder/dashboard/util/servlet/ServletUtils.java
@@ -4,6 +4,9 @@ import cn.hutool.core.io.IoUtil; @@ -4,6 +4,9 @@ import cn.hutool.core.io.IoUtil;
4 import cn.hutool.extra.servlet.ServletUtil; 4 import cn.hutool.extra.servlet.ServletUtil;
5 import com.alibaba.fastjson.JSON; 5 import com.alibaba.fastjson.JSON;
6 import org.springframework.http.MediaType; 6 import org.springframework.http.MediaType;
  7 +import org.springframework.web.context.request.RequestAttributes;
  8 +import org.springframework.web.context.request.RequestContextHolder;
  9 +import org.springframework.web.context.request.ServletRequestAttributes;
7 10
8 import javax.servlet.http.HttpServletRequest; 11 import javax.servlet.http.HttpServletRequest;
9 import javax.servlet.http.HttpServletResponse; 12 import javax.servlet.http.HttpServletResponse;
@@ -54,4 +57,33 @@ public class ServletUtils { @@ -54,4 +57,33 @@ public class ServletUtils {
54 return ua != null ? ua : ""; 57 return ua != null ? ua : "";
55 } 58 }
56 59
  60 + /**
  61 + * 获得请求
  62 + *
  63 + * @return HttpServletRequest
  64 + */
  65 + public static HttpServletRequest getRequest() {
  66 + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
  67 + if (!(requestAttributes instanceof ServletRequestAttributes)) {
  68 + return null;
  69 + }
  70 + return ((ServletRequestAttributes) requestAttributes).getRequest();
  71 + }
  72 +
  73 + public static String getUserAgent() {
  74 + HttpServletRequest request = getRequest();
  75 + if (request == null) {
  76 + return null;
  77 + }
  78 + return getUserAgent(request);
  79 + }
  80 +
  81 + public static String getClientIP() {
  82 + HttpServletRequest request = getRequest();
  83 + if (request == null) {
  84 + return null;
  85 + }
  86 + return ServletUtil.getClientIP(request);
  87 + }
  88 +
57 } 89 }