update 更新登录日志, 在线用户展示信息(增加 用户类型, 客户端, 设备类型),

update 修改相关方法传参 ;
update sql ;
This commit is contained in:
Michelle.Chung 2023-10-21 17:56:32 +08:00
parent f708492681
commit db6e868e30
16 changed files with 155 additions and 28 deletions

View File

@ -99,7 +99,7 @@ public class SysLoginService {
// 超级管理员 登出清除动态租户
TenantHelper.clearDynamic();
}
recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success"));
recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), loginUser.getUserType(), Constants.LOGOUT, MessageUtils.message("user.logout.success"));
} catch (NotLoginException ignored) {
} finally {
try {
@ -114,13 +114,15 @@ public class SysLoginService {
*
* @param tenantId 租户ID
* @param username 用户名
* @param userType 用户类型
* @param status 状态
* @param message 消息内容
*/
public void recordLogininfor(String tenantId, String username, String status, String message) {
public void recordLogininfor(String tenantId, String username, String userType, String status, String message) {
LogininforEvent logininforEvent = new LogininforEvent();
logininforEvent.setTenantId(tenantId);
logininforEvent.setUsername(username);
logininforEvent.setUserType(userType);
logininforEvent.setStatus(status);
logininforEvent.setMessage(message);
logininforEvent.setRequest(ServletUtils.getRequest());
@ -131,7 +133,7 @@ public class SysLoginService {
/**
* 构建登录用户
*/
public LoginUser buildLoginUser(SysUserVo user) {
public LoginUser buildLoginUser(SysUserVo user, String client, String deviceType) {
LoginUser loginUser = new LoginUser();
loginUser.setTenantId(user.getTenantId());
loginUser.setUserId(user.getUserId());
@ -139,6 +141,8 @@ public class SysLoginService {
loginUser.setUsername(user.getUserName());
loginUser.setNickname(user.getNickName());
loginUser.setUserType(user.getUserType());
loginUser.setClient(client);
loginUser.setDeviceType(deviceType);
loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId()));
loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId()));
loginUser.setDeptName(ObjectUtil.isNull(user.getDept()) ? "" : user.getDept().getDeptName());
@ -164,7 +168,7 @@ public class SysLoginService {
/**
* 登录校验
*/
public void checkLogin(LoginType loginType, String tenantId, String username, Supplier<Boolean> supplier) {
public void checkLogin(LoginType loginType, String tenantId, String username, String userType, Supplier<Boolean> supplier) {
String errorKey = GlobalConstants.PWD_ERR_CNT_KEY + username;
String loginFail = Constants.LOGIN_FAIL;
@ -172,7 +176,7 @@ public class SysLoginService {
int errorNumber = ObjectUtil.defaultIfNull(RedisUtils.getCacheObject(errorKey), 0);
// 锁定时间内登录 则踢出
if (errorNumber >= maxRetryCount) {
recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime));
recordLogininfor(tenantId, username, userType, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime));
throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime);
}
@ -182,11 +186,11 @@ public class SysLoginService {
RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime));
// 达到规定错误次数 则锁定登录
if (errorNumber >= maxRetryCount) {
recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime));
recordLogininfor(tenantId, username, userType, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime));
throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime);
} else {
// 未达到规定错误次数
recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber));
recordLogininfor(tenantId, username, userType, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber));
throw new UserException(loginType.getRetryLimitCount(), errorNumber);
}
}

View File

@ -56,10 +56,11 @@ public class EmailAuthStrategy implements IAuthStrategy {
// 通过邮箱查找用户
SysUserVo user = loadUserByEmail(tenantId, email);
String userType = user.getUserType();
loginService.checkLogin(LoginType.EMAIL, tenantId, user.getUserName(), () -> !validateEmailCode(tenantId, email, emailCode));
loginService.checkLogin(LoginType.EMAIL, tenantId, user.getUserName(), userType, () -> !validateEmailCode(tenantId, email, emailCode, userType));
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
LoginUser loginUser = loginService.buildLoginUser(user);
LoginUser loginUser = loginService.buildLoginUser(user, client.getClientKey(), client.getDeviceType());
SaLoginModel model = new SaLoginModel();
model.setDevice(client.getDeviceType());
// 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
@ -70,7 +71,7 @@ public class EmailAuthStrategy implements IAuthStrategy {
// 生成token
LoginHelper.login(loginUser, model);
loginService.recordLogininfor(loginUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
loginService.recordLogininfor(loginUser.getTenantId(), user.getUserName(), userType, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
loginService.recordLoginInfo(user.getUserId());
LoginVo loginVo = new LoginVo();
@ -83,10 +84,10 @@ public class EmailAuthStrategy implements IAuthStrategy {
/**
* 校验邮箱验证码
*/
private boolean validateEmailCode(String tenantId, String email, String emailCode) {
private boolean validateEmailCode(String tenantId, String email, String emailCode, String userType) {
String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + email);
if (StringUtils.isBlank(code)) {
loginService.recordLogininfor(tenantId, email, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
loginService.recordLogininfor(tenantId, email, userType, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
throw new CaptchaExpireException();
}
return code.equals(emailCode);

View File

@ -60,16 +60,18 @@ public class PasswordAuthStrategy implements IAuthStrategy {
String code = loginBody.getCode();
String uuid = loginBody.getUuid();
SysUserVo user = loadUserByUsername(tenantId, username);
String userType = user.getUserType();
boolean captchaEnabled = captchaProperties.getEnable();
// 验证码开关
if (captchaEnabled) {
validateCaptcha(tenantId, username, code, uuid);
validateCaptcha(tenantId, username, userType, code, uuid);
}
SysUserVo user = loadUserByUsername(tenantId, username);
loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword()));
loginService.checkLogin(LoginType.PASSWORD, tenantId, username, userType, () -> !BCrypt.checkpw(password, user.getPassword()));
// 此处可根据登录用户的数据不同 自行创建 loginUser
LoginUser loginUser = loginService.buildLoginUser(user);
LoginUser loginUser = loginService.buildLoginUser(user, client.getClientKey(), client.getDeviceType());
SaLoginModel model = new SaLoginModel();
model.setDevice(client.getDeviceType());
// 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
@ -80,7 +82,7 @@ public class PasswordAuthStrategy implements IAuthStrategy {
// 生成token
LoginHelper.login(loginUser, model);
loginService.recordLogininfor(loginUser.getTenantId(), username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
loginService.recordLogininfor(loginUser.getTenantId(), username, userType, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
loginService.recordLoginInfo(user.getUserId());
LoginVo loginVo = new LoginVo();
@ -97,16 +99,16 @@ public class PasswordAuthStrategy implements IAuthStrategy {
* @param code 验证码
* @param uuid 唯一标识
*/
private void validateCaptcha(String tenantId, String username, String code, String uuid) {
private void validateCaptcha(String tenantId, String username, String userType, String code, String uuid) {
String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, "");
String captcha = RedisUtils.getCacheObject(verifyKey);
RedisUtils.deleteObject(verifyKey);
if (captcha == null) {
loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
loginService.recordLogininfor(tenantId, username, userType, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
throw new CaptchaExpireException();
}
if (!code.equalsIgnoreCase(captcha)) {
loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"));
loginService.recordLogininfor(tenantId, username, userType, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"));
throw new CaptchaException();
}
}

View File

@ -56,10 +56,11 @@ public class SmsAuthStrategy implements IAuthStrategy {
// 通过手机号查找用户
SysUserVo user = loadUserByPhonenumber(tenantId, phonenumber);
String userType = user.getUserType();
loginService.checkLogin(LoginType.SMS, tenantId, user.getUserName(), () -> !validateSmsCode(tenantId, phonenumber, smsCode));
loginService.checkLogin(LoginType.SMS, tenantId, user.getUserName(), userType, () -> !validateSmsCode(tenantId, phonenumber, smsCode, userType));
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
LoginUser loginUser = loginService.buildLoginUser(user);
LoginUser loginUser = loginService.buildLoginUser(user, client.getClientKey(), client.getDeviceType());
SaLoginModel model = new SaLoginModel();
model.setDevice(client.getDeviceType());
// 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
@ -70,7 +71,7 @@ public class SmsAuthStrategy implements IAuthStrategy {
// 生成token
LoginHelper.login(loginUser, model);
loginService.recordLogininfor(loginUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
loginService.recordLogininfor(loginUser.getTenantId(), user.getUserName(), userType, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
loginService.recordLoginInfo(user.getUserId());
LoginVo loginVo = new LoginVo();
@ -83,10 +84,10 @@ public class SmsAuthStrategy implements IAuthStrategy {
/**
* 校验短信验证码
*/
private boolean validateSmsCode(String tenantId, String phonenumber, String smsCode) {
private boolean validateSmsCode(String tenantId, String phonenumber, String smsCode, String userType) {
String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber);
if (StringUtils.isBlank(code)) {
loginService.recordLogininfor(tenantId, phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
loginService.recordLogininfor(tenantId, phonenumber, userType, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
throw new CaptchaExpireException();
}
return code.equals(smsCode);

View File

@ -96,7 +96,7 @@ public class SocialAuthStrategy implements IAuthStrategy {
SysUserVo user = loadUser(tenantId, social.getUserId());
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
LoginUser loginUser = loginService.buildLoginUser(user);
LoginUser loginUser = loginService.buildLoginUser(user, client.getClientKey(), client.getDeviceType());
SaLoginModel model = new SaLoginModel();
model.setDevice(client.getDeviceType());
// 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
@ -107,7 +107,7 @@ public class SocialAuthStrategy implements IAuthStrategy {
// 生成token
LoginHelper.login(loginUser, model);
loginService.recordLogininfor(loginUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
loginService.recordLogininfor(loginUser.getTenantId(), user.getUserName(), user.getUserType(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
loginService.recordLoginInfo(user.getUserId());
LoginVo loginVo = new LoginVo();

View File

@ -66,7 +66,7 @@ public class XcxAuthStrategy implements IAuthStrategy {
// 生成token
LoginHelper.login(loginUser, model);
loginService.recordLogininfor(loginUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
loginService.recordLogininfor(loginUser.getTenantId(), user.getUserName(), user.getUserType(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
loginService.recordLoginInfo(user.getUserId());
LoginVo loginVo = new LoginVo();

View File

@ -34,6 +34,21 @@ public class UserOnlineDTO implements Serializable {
*/
private String userName;
/**
* 用户类型
*/
private String userType;
/**
* 客户端
*/
private String client;
/**
* 设备类型
*/
private String deviceType;
/**
* 登录IP地址
*/

View File

@ -112,6 +112,16 @@ public class LoginUser implements Serializable {
*/
private Long roleId;
/**
* 客户端
*/
private String client;
/**
* 设备类型
*/
private String deviceType;
/**
* 获取登录id
*/

View File

@ -29,6 +29,11 @@ public class LogininforEvent implements Serializable {
*/
private String username;
/**
* 用户类型
*/
private String userType;
/**
* 登录状态 0成功 1失败
*/

View File

@ -49,6 +49,9 @@ public class UserActionListener implements SaTokenListener {
dto.setLoginTime(System.currentTimeMillis());
dto.setTokenId(tokenValue);
dto.setUserName(user.getUsername());
dto.setUserType(user.getUserType());
dto.setClient(user.getClient());
dto.setDeviceType(user.getDeviceType());
dto.setDeptName(user.getDeptName());
if(tokenConfig.getTimeout() == -1) {
RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto);

View File

@ -37,6 +37,21 @@ public class SysLogininfor implements Serializable {
*/
private String userName;
/**
* 用户类型
*/
private String userType;
/**
* 客户端
*/
private String client;
/**
* 设备类型
*/
private String deviceType;
/**
* 登录状态 0成功 1失败
*/

View File

@ -26,6 +26,21 @@ public class SysUserOnline {
*/
private String userName;
/**
* 用户类型
*/
private String userType;
/**
* 客户端
*/
private String client;
/**
* 设备类型
*/
private String deviceType;
/**
* 登录IP地址
*/

View File

@ -33,6 +33,21 @@ public class SysLogininforBo {
*/
private String userName;
/**
* 用户类型
*/
private String userType;
/**
* 客户端
*/
private String client;
/**
* 设备类型
*/
private String deviceType;
/**
* 登录IP地址
*/

View File

@ -45,6 +45,25 @@ public class SysLogininforVo implements Serializable {
@ExcelProperty(value = "用户账号")
private String userName;
/**
* 用户类型
*/
@ExcelProperty(value = "用户类型")
private String userType;
/**
* 客户端
*/
@ExcelProperty(value = "客户端")
private String client;
/**
* 设备类型
*/
@ExcelProperty(value = "设备类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "sys_device_type")
private String deviceType;
/**
* 登录状态0成功 1失败
*/

View File

@ -1,5 +1,6 @@
package org.dromara.system.service.impl;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@ -12,10 +13,13 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.core.utils.ServletUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.ip.AddressUtils;
import org.dromara.system.domain.SysClient;
import org.dromara.system.domain.SysLogininfor;
import org.dromara.system.domain.bo.SysLogininforBo;
import org.dromara.system.domain.vo.SysLogininforVo;
import org.dromara.system.mapper.SysClientMapper;
import org.dromara.system.mapper.SysLogininforMapper;
import org.dromara.system.service.ISysClientService;
import org.dromara.system.service.ISysLogininforService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -41,6 +45,8 @@ public class SysLogininforServiceImpl implements ISysLogininforService {
private final SysLogininforMapper baseMapper;
private final ISysClientService iSysClientService;
/**
* 记录登录信息
*
@ -52,6 +58,12 @@ public class SysLogininforServiceImpl implements ISysLogininforService {
HttpServletRequest request = logininforEvent.getRequest();
final UserAgent userAgent = UserAgentUtil.parse(request.getHeader("User-Agent"));
final String ip = ServletUtils.getClientIP(request);
// 客户端信息
String clientid = request.getHeader("Clientid");
SysClient client = null;
if (StringUtils.isNotBlank(clientid)) {
client = iSysClientService.queryByClientId(clientid);
}
String address = AddressUtils.getRealAddressByIP(ip);
StringBuilder s = new StringBuilder();
@ -70,6 +82,11 @@ public class SysLogininforServiceImpl implements ISysLogininforService {
SysLogininforBo logininfor = new SysLogininforBo();
logininfor.setTenantId(logininforEvent.getTenantId());
logininfor.setUserName(logininforEvent.getUsername());
logininfor.setUserType(logininforEvent.getUserType());
if (ObjectUtil.isNotNull(client)) {
logininfor.setClient(client.getClientKey());
logininfor.setDeviceType(client.getDeviceType());
}
logininfor.setIpaddr(ip);
logininfor.setLoginLocation(address);
logininfor.setBrowser(browser);

View File

@ -99,3 +99,8 @@ insert into sys_role_menu values ('2', '1065');
update sys_dept set leader = null;
alter table sys_dept modify column leader bigint null default null comment '负责人' after order_num;
ALTER TABLE sys_logininfor
ADD COLUMN user_type VARCHAR(10) NULL DEFAULT 'sys_user' COMMENT '用户类型sys_user系统用户' AFTER `user_name`,
ADD COLUMN client VARCHAR(32) NULL DEFAULT NULL COMMENT '客户端' AFTER `user_type`,
ADD COLUMN device_type VARCHAR(32) NULL DEFAULT NULL COMMENT '设备类型' AFTER `client`;