Commit e9ff696a authored by 施翔轲's avatar 施翔轲

三方平台跳转登录相关改造

parent 8e8fb36d
package com.dsk.web.controller.system; package com.dsk.web.controller.system;
import cn.dev33.satoken.annotation.SaCheckLogin; import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaIgnore; import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.RegexPool;
import cn.hutool.core.lang.RegexPool; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.ReUtil; import com.dsk.common.constant.Constants;
import com.dsk.common.constant.Constants; import com.dsk.common.constant.GlobalConstants;
import com.dsk.common.constant.GlobalConstants; import com.dsk.common.core.domain.R;
import com.dsk.common.core.domain.R; import com.dsk.common.core.domain.model.*;
import com.dsk.common.exception.ServiceException; import com.dsk.common.helper.LoginHelper;
import com.dsk.common.tenant.helper.TenantHelper; import com.dsk.common.utils.redis.RedisUtils;
import com.dsk.common.utils.StringUtils; import com.dsk.jsk.util.IpUtil;
import com.dsk.common.utils.redis.RedisUtils; import com.dsk.system.domain.SysMenu;
import com.dsk.jsk.util.IpUtil; import com.dsk.system.domain.SysUser;
import com.dsk.system.domain.SysMenu; import com.dsk.system.domain.vo.LoginVo;
import com.dsk.system.domain.SysUser; import com.dsk.system.domain.vo.RouterVo;
import com.dsk.common.core.domain.model.EmailLoginBody; import com.dsk.system.domain.vo.SysTenantVo;
import com.dsk.common.core.domain.model.LoginBody; import com.dsk.system.service.ISysMenuService;
import com.dsk.common.core.domain.model.LoginUser; import com.dsk.system.service.ISysUserService;
import com.dsk.common.core.domain.model.SmsLoginBody; import com.dsk.system.service.SysLoginService;
import com.dsk.common.helper.LoginHelper; import lombok.RequiredArgsConstructor;
import com.dsk.system.domain.vo.LoginVo; import org.springframework.validation.annotation.Validated;
import com.dsk.system.domain.vo.RouterVo; import org.springframework.web.bind.annotation.GetMapping;
import com.dsk.system.domain.vo.SysTenantVo; import org.springframework.web.bind.annotation.PostMapping;
import com.dsk.system.service.ISysMenuService; import org.springframework.web.bind.annotation.RequestBody;
import com.dsk.system.service.ISysUserService; import org.springframework.web.bind.annotation.RestController;
import com.dsk.system.service.SysLoginService;
import lombok.RequiredArgsConstructor; import javax.servlet.http.HttpServletRequest;
import org.dromara.sms4j.api.SmsBlend; import javax.validation.constraints.NotBlank;
import org.dromara.sms4j.api.entity.SmsResponse; import java.time.Duration;
import org.dromara.sms4j.core.factory.SmsFactory; import java.util.ArrayList;
import org.dromara.sms4j.provider.enumerate.SupplierType; import java.util.HashMap;
import org.springframework.validation.annotation.Validated; import java.util.List;
import org.springframework.web.bind.annotation.*; import java.util.Map;
import javax.servlet.ServletRequest; /**
import javax.servlet.http.HttpServletRequest; * 登录验证
import javax.validation.constraints.NotBlank; *
import java.time.Duration; * @author Lion Li
import java.util.*; */
@Validated
/** @RequiredArgsConstructor
* 登录验证 @RestController
* public class SysLoginController {
* @author Lion Li
*/ private final SysLoginService loginService;
@Validated private final ISysMenuService menuService;
@RequiredArgsConstructor private final ISysUserService userService;
@RestController
public class SysLoginController { /**
* 登录方法
private final SysLoginService loginService; *
private final ISysMenuService menuService; * @param loginBody 登录信息
private final ISysUserService userService; * @return 结果
*/
/** @SaIgnore
* 登录方法 @PostMapping("/login")
* public R<LoginVo> login(@Validated @RequestBody LoginBody loginBody, HttpServletRequest request) {
* @param loginBody 登录信息 // Map<String, Object> ajax = new HashMap<>();
* @return 结果 // 生成令牌
*/ // LoginVo loginVo = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
@SaIgnore // loginBody.getUuid());
@PostMapping("/login") // ajax.put(Constants.TOKEN, token);
public R<LoginVo> login(@Validated @RequestBody LoginBody loginBody, HttpServletRequest request) { // return R.ok(ajax);
// Map<String, Object> ajax = new HashMap<>(); String ipAddr = IpUtil.getIpAddr(request);
// 生成令牌 LoginVo loginVo = loginService.passwordLogin(loginBody, ipAddr);
// LoginVo loginVo = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(), return R.ok(loginVo);
// loginBody.getUuid()); }
// ajax.put(Constants.TOKEN, token);
// return R.ok(ajax); /**
String ipAddr = IpUtil.getIpAddr(request); * 三方平台跳转登录方法
LoginVo loginVo = loginService.passwordLogin(loginBody, ipAddr); *
return R.ok(loginVo); * @param tpLoginBody 登录信息
} * @return 结果
*/
@SaIgnore
// /** @PostMapping("/thirdPlatformLogin")
// * 发送短信验证码 public R<LoginVo> thirdPlatformLogin(@Validated @RequestBody ThirdPlatformLoginBody tpLoginBody, HttpServletRequest request) {
// * String ipAddr = IpUtil.getIpAddr(request);
// * @param phones 电话号 LoginVo loginVo = loginService.thirdPlatformLogin(tpLoginBody, ipAddr);
// * @param templateId 模板ID
// */ //设置三方登录标识
// @SaIgnore RedisUtils.setCacheObject(GlobalConstants.SOCIAL_AUTH_CODE_KEY + loginVo.getTenantId(), loginVo.getTenantId(), Duration.ofMinutes(5));
// @GetMapping("/send/sms/code")
// public R<Object> sendAliyun(String phones, String templateId) { return R.ok(loginVo);
// LinkedHashMap<String, String> map = new LinkedHashMap<>(1); }
// map.put("code", RandomUtil.randomNumbers(4));
// SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.ALIBABA);
// SmsResponse smsResponse = smsBlend.sendMessage(phones, templateId, map); // /**
// return R.ok(smsResponse); // * 发送短信验证码
// } // *
// * @param phones 电话号
/** // * @param templateId 模板ID
* 短信登录 // */
* // @SaIgnore
* @param smsLoginBody 登录信息 // @GetMapping("/send/sms/code")
* @return 结果 // public R<Object> sendAliyun(String phones, String templateId) {
*/ // LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
@SaIgnore // map.put("code", RandomUtil.randomNumbers(4));
@PostMapping("/smsLogin") // SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.ALIBABA);
public R<LoginVo> smsLogin(@Validated @RequestBody SmsLoginBody smsLoginBody) { // SmsResponse smsResponse = smsBlend.sendMessage(phones, templateId, map);
// 生成令牌 // return R.ok(smsResponse);
LoginVo loginVo = loginService.smsLogin(smsLoginBody.getPhonenumber(), smsLoginBody.getSmsCode()); // }
return R.ok(loginVo);
} /**
* 短信登录
*
/** * @param smsLoginBody 登录信息
* 动态切换租户 * @return 结果
*/ */
@SaCheckLogin @SaIgnore
@PostMapping("/switch/tenant") @PostMapping("/smsLogin")
public R<LoginVo> switchTenant(String tenantId) { public R<LoginVo> smsLogin(@Validated @RequestBody SmsLoginBody smsLoginBody) {
LoginVo loginVo = loginService.switchTenant(tenantId); // 生成令牌
return R.ok(loginVo); LoginVo loginVo = loginService.smsLogin(smsLoginBody.getPhonenumber(), smsLoginBody.getSmsCode());
} return R.ok(loginVo);
}
/**
* 用户租户列表:根据用户账号获取用户绑定的租户列表 /**
* * 动态切换租户
* @return 结果 */
*/ @SaCheckLogin
@SaCheckLogin @PostMapping("/switch/tenant")
@PostMapping("/user/tenants") public R<LoginVo> switchTenant(String tenantId) {
public R<List<SysTenantVo>> userTenants() { LoginVo loginVo = loginService.switchTenant(tenantId);
LoginUser loginUser = LoginHelper.getLoginUser(); return R.ok(loginVo);
List<SysTenantVo> tenantList = loginService.tenantListByAccount(loginUser.getUserPhone()); }
return R.ok(tenantList);
}
/**
* 用户租户列表:根据用户账号获取用户绑定的租户列表
/** *
* 用户租户列表:根据用户账号获取用户绑定的租户列表 * @return 结果
* */
* @return 结果 @SaCheckLogin
*/ @PostMapping("/user/tenants")
@SaIgnore public R<List<SysTenantVo>> userTenants() {
@PostMapping("/user/tenant/list") LoginUser loginUser = LoginHelper.getLoginUser();
public R<List<SysTenantVo>> userTenantList(String phone) { List<SysTenantVo> tenantList = loginService.tenantListByAccount(loginUser.getUserPhone());
if (!ReUtil.isMatch(RegexPool.MOBILE, phone)) { return R.ok(tenantList);
return R.ok(new ArrayList<>()); }
}
List<SysTenantVo> tenantList = loginService.tenantListByAccount(phone);
if (CollectionUtil.isNotEmpty(tenantList)) { /**
for (SysTenantVo sysTenantVo : tenantList) { * 用户租户列表:根据用户账号获取用户绑定的租户列表
sysTenantVo.setCompanyName(""); *
} * @return 结果
} */
return R.ok(tenantList); @SaIgnore
} @PostMapping("/user/tenant/list")
public R<List<SysTenantVo>> userTenantList(String phone) {
/** if (!ReUtil.isMatch(RegexPool.MOBILE, phone)) {
* 获取当前用户默认租户 return R.ok(new ArrayList<>());
* }
* @return List<SysTenantVo> tenantList = loginService.tenantListByAccount(phone);
*/ if (CollectionUtil.isNotEmpty(tenantList)) {
@SaCheckLogin for (SysTenantVo sysTenantVo : tenantList) {
@PostMapping("/user/default/tenant") sysTenantVo.setCompanyName("");
public R<Map> userDefaultTenant() { }
LoginUser loginUser = LoginHelper.getLoginUser(); }
Assert.notNull(loginUser, "用户信息不存在!"); return R.ok(tenantList);
String defaultTenantKey = GlobalConstants.PHONE_DEFAULT_TENANT + loginUser.getUserPhone(); }
String defaultTenant = RedisUtils.getCacheObject(defaultTenantKey);
return R.ok(MapUtil.of("tenantId", defaultTenant)); /**
} * 获取当前用户默认租户
*
* @return
/** */
* 获取当前用户默认租户 @SaCheckLogin
* @PostMapping("/user/default/tenant")
* @return public R<Map> userDefaultTenant() {
*/ LoginUser loginUser = LoginHelper.getLoginUser();
@SaIgnore Assert.notNull(loginUser, "用户信息不存在!");
@PostMapping("/user/default/tenant/phone") String defaultTenantKey = GlobalConstants.PHONE_DEFAULT_TENANT + loginUser.getUserPhone();
public R<Map> userDefaultTenant(String phone) { String defaultTenant = RedisUtils.getCacheObject(defaultTenantKey);
// LoginUser loginUser = LoginHelper.getLoginUser(); return R.ok(MapUtil.of("tenantId", defaultTenant));
// Assert.notNull(loginUser,"用户信息不存在!"); }
String defaultTenantKey = GlobalConstants.PHONE_DEFAULT_TENANT + phone;
String defaultTenant = RedisUtils.getCacheObject(defaultTenantKey);
return R.ok(MapUtil.of("tenantId", defaultTenant)); /**
} * 获取当前用户默认租户
*
/** * @return
* 邮件登录 */
* @SaIgnore
* @param body 登录信息 @PostMapping("/user/default/tenant/phone")
* @return 结果 public R<Map> userDefaultTenant(String phone) {
*/ // LoginUser loginUser = LoginHelper.getLoginUser();
@PostMapping("/emailLogin") // Assert.notNull(loginUser,"用户信息不存在!");
public R<Map<String, Object>> emailLogin(@Validated @RequestBody EmailLoginBody body) { String defaultTenantKey = GlobalConstants.PHONE_DEFAULT_TENANT + phone;
Map<String, Object> ajax = new HashMap<>(); String defaultTenant = RedisUtils.getCacheObject(defaultTenantKey);
// 生成令牌 return R.ok(MapUtil.of("tenantId", defaultTenant));
String token = loginService.emailLogin(body.getEmail(), body.getEmailCode()); }
ajax.put(Constants.TOKEN, token);
return R.ok(ajax); /**
} * 邮件登录
*
/** * @param body 登录信息
* 小程序登录(示例) * @return 结果
* */
* @param xcxCode 小程序code @PostMapping("/emailLogin")
* @return 结果 public R<Map<String, Object>> emailLogin(@Validated @RequestBody EmailLoginBody body) {
*/ Map<String, Object> ajax = new HashMap<>();
@SaIgnore // 生成令牌
@PostMapping("/xcxLogin") String token = loginService.emailLogin(body.getEmail(), body.getEmailCode());
public R<Map<String, Object>> xcxLogin(@NotBlank(message = "{xcx.code.not.blank}") String xcxCode) { ajax.put(Constants.TOKEN, token);
Map<String, Object> ajax = new HashMap<>(); return R.ok(ajax);
// 生成令牌 }
String token = loginService.xcxLogin(xcxCode);
ajax.put(Constants.TOKEN, token); /**
return R.ok(ajax); * 小程序登录(示例)
} *
* @param xcxCode 小程序code
/** * @return 结果
* 退出登录 */
*/ @SaIgnore
@SaIgnore @PostMapping("/xcxLogin")
@PostMapping("/logout") public R<Map<String, Object>> xcxLogin(@NotBlank(message = "{xcx.code.not.blank}") String xcxCode) {
public R<Void> logout() { Map<String, Object> ajax = new HashMap<>();
loginService.logout(); // 生成令牌
return R.ok("退出成功"); String token = loginService.xcxLogin(xcxCode);
} ajax.put(Constants.TOKEN, token);
return R.ok(ajax);
/** }
* 获取用户信息
* /**
* @return 用户信息 * 退出登录
*/ */
@GetMapping("getInfo") @SaIgnore
public R<Map<String, Object>> getInfo(HttpServletRequest request) { @PostMapping("/logout")
LoginUser loginUser = LoginHelper.getLoginUser(); public R<Void> logout() {
//校验当前发请求的IP与登录账号的IP是否相同 loginService.logout();
// String loginUserIpaddr = loginUser.getIpaddr(); return R.ok("退出成功");
// if (StringUtils.isNotBlank(loginUserIpaddr) && !Objects.equals(IpUtil.getIpAddr(request), loginUserIpaddr)) { }
// throw new ServiceException("该账号已在其他地方登录,请求失败!", 401);
// } /**
SysUser user = userService.selectUserById(loginUser.getUserId()); * 获取用户信息
Map<String, Object> ajax = new HashMap<>(); *
ajax.put("user", user); * @return 用户信息
ajax.put("roles", loginUser.getRolePermission()); */
ajax.put("permissions", loginUser.getMenuPermission()); @GetMapping("getInfo")
return R.ok(ajax); public R<Map<String, Object>> getInfo(HttpServletRequest request) {
} LoginUser loginUser = LoginHelper.getLoginUser();
//校验当前发请求的IP与登录账号的IP是否相同
/** // String loginUserIpaddr = loginUser.getIpaddr();
* 获取路由信息 // if (StringUtils.isNotBlank(loginUserIpaddr) && !Objects.equals(IpUtil.getIpAddr(request), loginUserIpaddr)) {
* // throw new ServiceException("该账号已在其他地方登录,请求失败!", 401);
* @return 路由信息 // }
*/ SysUser user = userService.selectUserById(loginUser.getUserId());
@GetMapping("getRouters") Map<String, Object> ajax = new HashMap<>();
public R<List<RouterVo>> getRouters() { ajax.put("user", user);
Long userId = LoginHelper.getUserId(); ajax.put("roles", loginUser.getRolePermission());
List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId); ajax.put("permissions", loginUser.getMenuPermission());
return R.ok(menuService.buildMenus(menus)); String key = GlobalConstants.SOCIAL_AUTH_CODE_KEY + loginUser.getTenantId();
} ajax.put("isThirdPlatformLogin", ObjectUtil.isNotNull(RedisUtils.getCacheObject(key)) ? "true" : "false");
} //删除三方平台登录标识
RedisUtils.deleteObject(key);
return R.ok(ajax);
}
/**
* 获取路由信息
*
* @return 路由信息
*/
@GetMapping("getRouters")
public R<List<RouterVo>> getRouters() {
Long userId = LoginHelper.getUserId();
List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
return R.ok(menuService.buildMenus(menus));
}
}
package com.dsk.common.core.domain.model;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* 三方平台用户登录对象
*
* @author sxk
*/
@Data
public class ThirdPlatformLoginBody {
/**
* 三方平台跳转本系统所需秘钥
*/
@NotBlank(message = "桑芳平台登录秘钥不能为空")
private String thirdPlatformKey;
}
package com.dsk.system.domain; package com.dsk.system.domain;
import com.baomidou.mybatisplus.annotation.*; import com.baomidou.mybatisplus.annotation.*;
import com.dsk.common.annotation.Sensitive; import com.dsk.common.annotation.Sensitive;
import com.dsk.common.constant.UserConstants; import com.dsk.common.constant.UserConstants;
import com.dsk.common.enums.SensitiveStrategy; import com.dsk.common.enums.SensitiveStrategy;
import com.dsk.common.tenant.core.TenantEntity; import com.dsk.common.tenant.core.TenantEntity;
import com.dsk.common.xss.Xss; import com.dsk.common.xss.Xss;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import javax.validation.constraints.Email; import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size; import javax.validation.constraints.Size;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
/** /**
* 用户对象 sys_user * 用户对象 sys_user
* *
* @author Lion Li * @author Lion Li
*/ */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@TableName("sys_user") @TableName("sys_user")
public class SysUser extends TenantEntity { public class SysUser extends TenantEntity {
/** /**
* 用户ID * 用户ID
*/ */
@TableId(value = "user_id") @TableId(value = "user_id")
private Long userId; private Long userId;
/** /**
* 部门ID * 三方平台跳转本系统所需秘钥
*/ */
private Long deptId; private String thirdPlatformKey;
/** /**
* 用户账号 * 部门ID
*/ */
@Xss(message = "用户账号不能包含脚本字符") private Long deptId;
@NotBlank(message = "用户账号不能为空")
@Size(min = 0, max = 30, message = "用户账号长度不能超过{max}个字符") /**
private String userName; * 用户账号
*/
/** @Xss(message = "用户账号不能包含脚本字符")
* 用户昵称 @NotBlank(message = "用户账号不能为空")
*/ @Size(min = 0, max = 30, message = "用户账号长度不能超过{max}个字符")
@Xss(message = "用户昵称不能包含脚本字符") private String userName;
@NotBlank(message = "用户昵称不能为空")
@Size(min = 0, max = 30, message = "用户昵称长度不能超过{max}个字符") /**
private String nickName; * 用户昵称
*/
/** @Xss(message = "用户昵称不能包含脚本字符")
* 用户类型(sys_user系统用户) @NotBlank(message = "用户昵称不能为空")
*/ @Size(min = 0, max = 30, message = "用户昵称长度不能超过{max}个字符")
private String userType; private String nickName;
/** /**
* 用户邮箱 * 用户类型(sys_user系统用户)
*/ */
@Sensitive(strategy = SensitiveStrategy.EMAIL) private String userType;
@Email(message = "邮箱格式不正确")
@Size(min = 0, max = 50, message = "邮箱长度不能超过{max}个字符") /**
private String email; * 用户邮箱
*/
/** @Sensitive(strategy = SensitiveStrategy.EMAIL)
* 手机号码 @Email(message = "邮箱格式不正确")
*/ @Size(min = 0, max = 50, message = "邮箱长度不能超过{max}个字符")
@Sensitive(strategy = SensitiveStrategy.PHONE) private String email;
private String phonenumber;
/**
/** * 手机号码
* 用户性别 */
*/ @Sensitive(strategy = SensitiveStrategy.PHONE)
private String sex; private String phonenumber;
/** /**
* 用户头像 * 用户性别
*/ */
private String avatar; private String sex;
/** /**
* 密码 * 用户头像
*/ */
@TableField( private String avatar;
insertStrategy = FieldStrategy.NOT_EMPTY,
updateStrategy = FieldStrategy.NOT_EMPTY, /**
whereStrategy = FieldStrategy.NOT_EMPTY * 密码
) */
private String password; @TableField(
insertStrategy = FieldStrategy.NOT_EMPTY,
@JsonIgnore updateStrategy = FieldStrategy.NOT_EMPTY,
@JsonProperty whereStrategy = FieldStrategy.NOT_EMPTY
public String getPassword() { )
return password; private String password;
}
@JsonIgnore
/** @JsonProperty
* 帐号状态(0正常 1停用) public String getPassword() {
*/ return password;
private String status; }
/** /**
* 删除标志(0代表存在 2代表删除) * 帐号状态(0正常 1停用)
*/ */
@TableLogic private String status;
private String delFlag;
/**
/** * 删除标志(0代表存在 2代表删除)
* 最后登录IP */
*/ @TableLogic
private String loginIp; private String delFlag;
/** /**
* 最后登录时间 * 最后登录IP
*/ */
private Date loginDate; private String loginIp;
/** /**
* 备注 * 最后登录时间
*/ */
private String remark; private Date loginDate;
/** /**
* 创建时间 * 备注
*/ */
private Date createTime; private String remark;
/** /**
* 部门对象 * 创建时间
*/ */
@TableField(exist = false) private Date createTime;
private SysDept dept;
/**
/** * 部门对象
* 角色对象 */
*/ @TableField(exist = false)
@TableField(exist = false) private SysDept dept;
private List<SysRole> roles;
/**
/** * 角色对象
* 角色组 */
*/ @TableField(exist = false)
@TableField(exist = false) private List<SysRole> roles;
private Long[] roleIds;
/**
/** * 角色组
* 岗位组 */
*/ @TableField(exist = false)
@TableField(exist = false) private Long[] roleIds;
private Long[] postIds;
/**
/** * 岗位组
* 数据权限 当前角色ID */
*/ @TableField(exist = false)
@TableField(exist = false) private Long[] postIds;
private Long roleId;
/**
* 数据权限 当前角色ID
public SysUser(Long userId) { */
this.userId = userId; @TableField(exist = false)
} private Long roleId;
public boolean isAdmin() {
return UserConstants.ADMIN_ID.equals(this.userId); public SysUser(Long userId) {
} this.userId = userId;
}
public boolean isSuperAdmin() {
return UserConstants.SUPER_ADMIN_ID.equals(this.userId); public boolean isAdmin() {
} return UserConstants.ADMIN_ID.equals(this.userId);
}
}
public boolean isSuperAdmin() {
return UserConstants.SUPER_ADMIN_ID.equals(this.userId);
}
}
package com.dsk.system.service; package com.dsk.system.service;
import cn.dev33.satoken.exception.NotLoginException; import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.secure.BCrypt; import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.secure.SaBase64Util; import cn.dev33.satoken.secure.SaBase64Util;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.RegexPool; import cn.hutool.core.lang.RegexPool;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReUtil; import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.dsk.common.constant.Constants;
import com.dsk.common.constant.CacheConstants; import com.dsk.common.constant.GlobalConstants;
import com.dsk.common.constant.Constants; import com.dsk.common.constant.TenantConstants;
import com.dsk.common.constant.GlobalConstants; import com.dsk.common.core.domain.dto.RoleDTO;
import com.dsk.common.constant.TenantConstants; import com.dsk.common.core.domain.event.LogininforEvent;
import com.dsk.common.core.domain.dto.RoleDTO; import com.dsk.common.core.domain.model.LoginBody;
import com.dsk.common.core.domain.event.LogininforEvent; import com.dsk.common.core.domain.model.LoginUser;
import com.dsk.common.core.domain.model.LoginBody; import com.dsk.common.core.domain.model.ThirdPlatformLoginBody;
import com.dsk.common.core.domain.model.LoginUser; import com.dsk.common.core.domain.model.XcxLoginUser;
import com.dsk.common.core.domain.model.XcxLoginUser; import com.dsk.common.enums.DeviceType;
import com.dsk.common.enums.DeviceType; import com.dsk.common.enums.LoginType;
import com.dsk.common.enums.LoginType; import com.dsk.common.enums.TenantStatus;
import com.dsk.common.enums.TenantStatus; import com.dsk.common.enums.UserStatus;
import com.dsk.common.enums.UserStatus; import com.dsk.common.exception.user.CaptchaException;
import com.dsk.common.exception.user.CaptchaException; import com.dsk.common.exception.user.CaptchaExpireException;
import com.dsk.common.exception.user.CaptchaExpireException; import com.dsk.common.exception.user.UserException;
import com.dsk.common.exception.user.UserException; import com.dsk.common.helper.LoginHelper;
import com.dsk.common.helper.LoginHelper; import com.dsk.common.tenant.exception.TenantException;
import com.dsk.common.tenant.exception.TenantException; import com.dsk.common.tenant.helper.TenantHelper;
import com.dsk.common.tenant.helper.TenantBroker; import com.dsk.common.utils.DateUtils;
import com.dsk.common.tenant.helper.TenantHelper; import com.dsk.common.utils.MessageUtils;
import com.dsk.common.utils.DateUtils; import com.dsk.common.utils.ServletUtils;
import com.dsk.common.utils.MessageUtils; import com.dsk.common.utils.StringUtils;
import com.dsk.common.utils.ServletUtils; import com.dsk.common.utils.redis.RedisUtils;
import com.dsk.common.utils.StringUtils; import com.dsk.common.utils.spring.SpringUtils;
import com.dsk.common.utils.redis.RedisUtils; import com.dsk.system.domain.SysUser;
import com.dsk.common.utils.spring.SpringUtils; import com.dsk.system.domain.vo.LoginVo;
import com.dsk.system.domain.SysTenant; import com.dsk.system.domain.vo.SysTenantVo;
import com.dsk.system.domain.SysUser; import com.dsk.system.mapper.SysUserMapper;
import com.dsk.system.domain.vo.LoginVo; import lombok.RequiredArgsConstructor;
import com.dsk.system.domain.vo.SysTenantVo; import lombok.extern.slf4j.Slf4j;
import com.dsk.system.mapper.SysTenantMapper; import org.springframework.beans.factory.annotation.Value;
import com.dsk.system.mapper.SysUserMapper; import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import java.time.Duration;
import org.springframework.beans.factory.annotation.Value; import java.util.Date;
import org.springframework.stereotype.Service; import java.util.List;
import java.util.function.Supplier;
import java.time.Duration;
import java.util.Date; /**
import java.util.List; * 登录校验方法
import java.util.function.Supplier; *
* @author Lion Li
/** */
* 登录校验方法 @RequiredArgsConstructor
* @Slf4j
* @author Lion Li @Service
*/ public class SysLoginService {
@RequiredArgsConstructor
@Slf4j private final SysUserMapper userMapper;
@Service private final ISysConfigService configService;
public class SysLoginService { private final SysPermissionService permissionService;
private final ISysTenantService sysTenantService;
private final SysUserMapper userMapper;
private final ISysConfigService configService; @Value("${captcha.enable}")
private final SysPermissionService permissionService; private boolean captchaEnabled;
private final ISysTenantService sysTenantService;
@Value("${user.password.maxRetryCount}")
@Value("${captcha.enable}") private Integer maxRetryCount;
private boolean captchaEnabled;
@Value("${user.password.lockTime}")
@Value("${user.password.maxRetryCount}") private Integer lockTime;
private Integer maxRetryCount;
/**
@Value("${user.password.lockTime}") * 登录验证
private Integer lockTime; *
* @param loginBody 唯一标识
/** * @param ipAddr IP地址
* 登录验证 * @return 结果
* */
* @param loginBody 唯一标识 public LoginVo passwordLogin(LoginBody loginBody, String ipAddr) {
* @param ipAddr IP地址 String tenantId = loginBody.getTenantId();
* @return 结果 String username = loginBody.getUsername();
*/ String password = SaBase64Util.decode(loginBody.getPassword());
public LoginVo passwordLogin(LoginBody loginBody, String ipAddr) { String code = loginBody.getCode();
String tenantId = loginBody.getTenantId(); String uuid = loginBody.getUuid();
String username = loginBody.getUsername(); // 验证码开关
String password = SaBase64Util.decode(loginBody.getPassword()); if (captchaEnabled) {
String code = loginBody.getCode(); validateCaptcha(username, code, uuid);
String uuid = loginBody.getUuid(); }
// 验证码开关
if (captchaEnabled) { if (ReUtil.isMatch(RegexPool.MOBILE, username)) {
validateCaptcha(username, code, uuid); String defaultTenantId = RedisUtils.getCacheObject(GlobalConstants.PHONE_DEFAULT_TENANT + username);
} log.info("登录用户:{} 获取缓存默认租户:" + tenantId, username);
if (StrUtil.isEmpty(tenantId) && StrUtil.isNotBlank(defaultTenantId)) {
if (ReUtil.isMatch(RegexPool.MOBILE, username)) { defaultTenantId = checkDefaultTenant(defaultTenantId, username);
String defaultTenantId = RedisUtils.getCacheObject(GlobalConstants.PHONE_DEFAULT_TENANT + username); tenantId = defaultTenantId;
log.info("登录用户:{} 获取缓存默认租户:" + tenantId, username); }
if (StrUtil.isEmpty(tenantId) && StrUtil.isNotBlank(defaultTenantId)) { }
defaultTenantId = checkDefaultTenant(defaultTenantId, username);
tenantId = defaultTenantId; //查询手机号绑定的所有用户
} if (StrUtil.isEmpty(tenantId)) {
} List<SysUser> sysUsers = queryListByPhone(username);
if (CollectionUtil.isEmpty(sysUsers)) {
//查询手机号绑定的所有用户 log.info("登录用户:{} 不存在.", username);
if (StrUtil.isEmpty(tenantId)) { throw new UserException("user.not.exists", username);
List<SysUser> sysUsers = queryListByPhone(username); } else if (sysUsers.size() > 1) {
if (CollectionUtil.isEmpty(sysUsers)) { //处理存在多个用户的情况,取一个最新租户
log.info("登录用户:{} 不存在.", username); SysUser sysUser = sysUsers.get(0);
throw new UserException("user.not.exists", username); if (ObjectUtil.isEmpty(sysUser)) {
} else if (sysUsers.size() > 1) { log.info("登录用户:{} 不存在.", username);
//处理存在多个用户的情况,取一个最新租户 throw new UserException("user.not.exists", username);
SysUser sysUser = sysUsers.get(0); }
if (ObjectUtil.isEmpty(sysUser)) { tenantId = sysUser.getTenantId();
log.info("登录用户:{} 不存在.", username); } else {
throw new UserException("user.not.exists", username); SysUser sysUser = sysUsers.get(0);
} tenantId = sysUser.getTenantId();
tenantId = sysUser.getTenantId(); }
} else { }
SysUser sysUser = sysUsers.get(0);
tenantId = sysUser.getTenantId(); // 校验租户
} if (tenantId != null) {
} checkTenant(tenantId);
}
// 校验租户 if (tenantId == null || "".equals(tenantId)) {
if (tenantId != null) { tenantId = TenantConstants.DEFAULT_TENANT_ID;
checkTenant(tenantId); }
} TenantHelper.setTenantId(tenantId);
if (tenantId == null || "".equals(tenantId)) { // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
tenantId = TenantConstants.DEFAULT_TENANT_ID; // SysUser user = loadUserByUsername(username);
} // return TenantBroker.applyAs(tenantId, (id -> {
TenantHelper.setTenantId(tenantId);
// 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可 // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
// SysUser user = loadUserByUsername(username); SysUser user = loadUserByUsername(username);
// return TenantBroker.applyAs(tenantId, (id -> { checkLogin(LoginType.PASSWORD, username, () -> !BCrypt.checkpw(password, user.getPassword()));
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
// 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可 LoginUser loginUser = buildLoginUser(user);
SysUser user = loadUserByUsername(username); // 生成token
checkLogin(LoginType.PASSWORD, username, () -> !BCrypt.checkpw(password, user.getPassword())); loginUser.setIpaddr(ipAddr);
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 LoginHelper.loginByDevice(loginUser, DeviceType.PC);
LoginUser loginUser = buildLoginUser(user);
// 生成token recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
loginUser.setIpaddr(ipAddr); recordLoginInfo(user.getUserId(), username);
LoginHelper.loginByDevice(loginUser, DeviceType.PC);
// RedisUtils.setCacheObject(GlobalConstants.PHONE_DEFAULT_TENANT + username, TenantHelper.getTenantId(), Duration.ofDays(30));
recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
recordLoginInfo(user.getUserId(), username); LoginVo loginVo = new LoginVo();
loginVo.setTenantId(TenantHelper.getTenantId());
// RedisUtils.setCacheObject(GlobalConstants.PHONE_DEFAULT_TENANT + username, TenantHelper.getTenantId(), Duration.ofDays(30)); loginVo.setAccessToken(StpUtil.getTokenValue());
loginVo.setExpireIn(StpUtil.getTokenTimeout());
LoginVo loginVo = new LoginVo(); return loginVo;
loginVo.setTenantId(TenantHelper.getTenantId()); // }));
loginVo.setAccessToken(StpUtil.getTokenValue()); // return StpUtil.getTokenValue();
loginVo.setExpireIn(StpUtil.getTokenTimeout()); }
return loginVo;
// })); /**
// return StpUtil.getTokenValue(); * 三方平台跳转登录方法
} *
* @param tpLoginBody 登录信息
* @return 结果
/** */
* 登录验证 public LoginVo thirdPlatformLogin(ThirdPlatformLoginBody tpLoginBody, String ipAddr) {
* return TenantHelper.ignore(() -> {
* @param username 用户名 SysUser sysUser = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
* @param password 密码 .eq(SysUser::getThirdPlatformKey, tpLoginBody.getThirdPlatformKey()));
* @param code 验证码
* @param uuid 唯一标识 String tenantId = sysUser.getTenantId();
* @return 结果 String username = sysUser.getUserName();
*/ String password = sysUser.getPassword();
public String login(String username, String password, String code, String uuid) {
boolean captchaEnabled = configService.selectCaptchaEnabled(); if (ReUtil.isMatch(RegexPool.MOBILE, username)) {
// 验证码开关 String defaultTenantId = RedisUtils.getCacheObject(GlobalConstants.PHONE_DEFAULT_TENANT + username);
if (captchaEnabled) { log.info("登录用户:{} 获取缓存默认租户:" + tenantId, username);
validateCaptcha(username, code, uuid); if (StrUtil.isEmpty(tenantId) && StrUtil.isNotBlank(defaultTenantId)) {
} defaultTenantId = checkDefaultTenant(defaultTenantId, username);
// 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可 tenantId = defaultTenantId;
SysUser user = loadUserByUsername(username); }
checkLogin(LoginType.PASSWORD, username, () -> !BCrypt.checkpw(password, user.getPassword())); }
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
LoginUser loginUser = buildLoginUser(user); //查询手机号绑定的所有用户
// 生成token if (StrUtil.isEmpty(tenantId)) {
LoginHelper.loginByDevice(loginUser, DeviceType.PC); List<SysUser> sysUsers = queryListByPhone(username);
if (CollectionUtil.isEmpty(sysUsers)) {
recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); log.info("登录用户:{} 不存在.", username);
recordLoginInfo(user.getUserId(), username); throw new UserException("user.not.exists", username);
return StpUtil.getTokenValue(); } else if (sysUsers.size() > 1) {
} //处理存在多个用户的情况,取一个最新租户
SysUser sysUser1 = sysUsers.get(0);
public LoginVo smsLogin(String username, String smsCode) { if (ObjectUtil.isEmpty(sysUser)) {
String tenantId = null; log.info("登录用户:{} 不存在.", username);
if (ReUtil.isMatch(RegexPool.MOBILE, username)) { throw new UserException("user.not.exists", username);
String defaultTenantId = RedisUtils.getCacheObject(GlobalConstants.PHONE_DEFAULT_TENANT + username); }
log.info("登录用户:{} 获取缓存默认租户:" + tenantId, username); tenantId = sysUser1.getTenantId();
if (StrUtil.isNotBlank(defaultTenantId)) { } else {
defaultTenantId = checkDefaultTenant(defaultTenantId, username); SysUser sysUser2 = sysUsers.get(0);
tenantId = defaultTenantId; tenantId = sysUser2.getTenantId();
} }
} }
//查询手机号绑定的所有用户 // 校验租户
if (StrUtil.isEmpty(tenantId)) { if (tenantId != null) {
List<SysUser> sysUsers = queryListByPhone(username); checkTenant(tenantId);
if (CollectionUtil.isEmpty(sysUsers)) { }
log.info("登录用户:{} 不存在.", username); if (tenantId == null || "".equals(tenantId)) {
throw new UserException("user.not.exists", username); tenantId = TenantConstants.DEFAULT_TENANT_ID;
} else if (sysUsers.size() > 1) { }
//处理存在多个用户的情况,取一个最新租户 TenantHelper.setTenantId(tenantId);
SysUser sysUser = sysUsers.get(0);
if (ObjectUtil.isEmpty(sysUser)) { // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
log.info("登录用户:{} 不存在.", username); SysUser user = loadUserByUsername(username);
throw new UserException("user.not.exists", username); //checkLogin(LoginType.PASSWORD, username, () -> !BCrypt.checkpw(password, user.getPassword()));
} // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
tenantId = sysUser.getTenantId(); LoginUser loginUser = buildLoginUser(user);
} else { // 生成token
SysUser sysUser = sysUsers.get(0); loginUser.setIpaddr(ipAddr);
tenantId = sysUser.getTenantId(); LoginHelper.loginByDevice(loginUser, DeviceType.PC);
}
} recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
recordLoginInfo(user.getUserId(), username);
// 校验租户
if (tenantId != null) { LoginVo loginVo = new LoginVo();
checkTenant(tenantId); loginVo.setTenantId(TenantHelper.getTenantId());
} loginVo.setAccessToken(StpUtil.getTokenValue());
if (tenantId == null || "".equals(tenantId)) { loginVo.setExpireIn(StpUtil.getTokenTimeout());
tenantId = TenantConstants.DEFAULT_TENANT_ID; return loginVo;
} });
TenantHelper.setTenantId(tenantId); }
// 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
// SysUser user = loadUserByUsername(username); /**
// return TenantBroker.applyAs(tenantId, (id -> { * 登录验证
*
// 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可 * @param username 用户名
SysUser user = loadUserByUsername(username); * @param password 密码
checkLogin(LoginType.SMS, username, () -> !validateSmsCode(username, smsCode)); * @param code 验证码
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 * @param uuid 唯一标识
LoginUser loginUser = buildLoginUser(user); * @return 结果
// 生成token */
LoginHelper.loginByDevice(loginUser, DeviceType.PC); public String login(String username, String password, String code, String uuid) {
boolean captchaEnabled = configService.selectCaptchaEnabled();
recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); // 验证码开关
recordLoginInfo(user.getUserId(), username); if (captchaEnabled) {
validateCaptcha(username, code, uuid);
LoginVo loginVo = new LoginVo(); }
loginVo.setTenantId(TenantHelper.getTenantId()); // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
loginVo.setAccessToken(StpUtil.getTokenValue()); SysUser user = loadUserByUsername(username);
loginVo.setExpireIn(StpUtil.getTokenTimeout()); checkLogin(LoginType.PASSWORD, username, () -> !BCrypt.checkpw(password, user.getPassword()));
return loginVo; // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
} LoginUser loginUser = buildLoginUser(user);
// 生成token
public String emailLogin(String email, String emailCode) { LoginHelper.loginByDevice(loginUser, DeviceType.PC);
// 通过手邮箱查找用户
SysUser user = loadUserByEmail(email); recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
recordLoginInfo(user.getUserId(), username);
checkLogin(LoginType.EMAIL, user.getUserName(), () -> !validateEmailCode(email, emailCode)); return StpUtil.getTokenValue();
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 }
LoginUser loginUser = buildLoginUser(user);
// 生成token public LoginVo smsLogin(String username, String smsCode) {
LoginHelper.loginByDevice(loginUser, DeviceType.APP); String tenantId = null;
if (ReUtil.isMatch(RegexPool.MOBILE, username)) {
recordLogininfor(user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); String defaultTenantId = RedisUtils.getCacheObject(GlobalConstants.PHONE_DEFAULT_TENANT + username);
recordLoginInfo(user.getUserId(), user.getUserName()); log.info("登录用户:{} 获取缓存默认租户:" + tenantId, username);
return StpUtil.getTokenValue(); if (StrUtil.isNotBlank(defaultTenantId)) {
} defaultTenantId = checkDefaultTenant(defaultTenantId, username);
tenantId = defaultTenantId;
public String xcxLogin(String xcxCode) { }
// xcxCode 为 小程序调用 wx.login 授权后获取 }
// todo 以下自行实现
// 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key 与 openid //查询手机号绑定的所有用户
String openid = ""; if (StrUtil.isEmpty(tenantId)) {
List<SysUser> sysUsers = queryListByPhone(username);
// 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可 if (CollectionUtil.isEmpty(sysUsers)) {
SysUser user = loadUserByOpenid(openid); log.info("登录用户:{} 不存在.", username);
throw new UserException("user.not.exists", username);
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 } else if (sysUsers.size() > 1) {
XcxLoginUser loginUser = new XcxLoginUser(); //处理存在多个用户的情况,取一个最新租户
loginUser.setUserId(user.getUserId()); SysUser sysUser = sysUsers.get(0);
loginUser.setUsername(user.getUserName()); if (ObjectUtil.isEmpty(sysUser)) {
loginUser.setUserType(user.getUserType()); log.info("登录用户:{} 不存在.", username);
loginUser.setOpenid(openid); throw new UserException("user.not.exists", username);
// 生成token }
LoginHelper.loginByDevice(loginUser, DeviceType.XCX); tenantId = sysUser.getTenantId();
} else {
recordLogininfor(user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); SysUser sysUser = sysUsers.get(0);
recordLoginInfo(user.getUserId(), user.getUserName()); tenantId = sysUser.getTenantId();
return StpUtil.getTokenValue(); }
} }
/** // 校验租户
* 退出登录 if (tenantId != null) {
*/ checkTenant(tenantId);
public void logout() { }
try { if (tenantId == null || "".equals(tenantId)) {
LoginUser loginUser = LoginHelper.getLoginUser(); tenantId = TenantConstants.DEFAULT_TENANT_ID;
if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) { }
// 超级管理员 登出清除动态租户 TenantHelper.setTenantId(tenantId);
TenantHelper.clearDynamic(); // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
} // SysUser user = loadUserByUsername(username);
recordLogininfor(loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success")); // return TenantBroker.applyAs(tenantId, (id -> {
} catch (NotLoginException ignored) {
} finally { // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
try { SysUser user = loadUserByUsername(username);
StpUtil.logout(); checkLogin(LoginType.SMS, username, () -> !validateSmsCode(username, smsCode));
} catch (NotLoginException ignored) { // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
} LoginUser loginUser = buildLoginUser(user);
} // 生成token
} LoginHelper.loginByDevice(loginUser, DeviceType.PC);
/** recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
* 记录登录信息 recordLoginInfo(user.getUserId(), username);
*
* @param username 用户名 LoginVo loginVo = new LoginVo();
* @param status 状态 loginVo.setTenantId(TenantHelper.getTenantId());
* @param message 消息内容 loginVo.setAccessToken(StpUtil.getTokenValue());
*/ loginVo.setExpireIn(StpUtil.getTokenTimeout());
private void recordLogininfor(String username, String status, String message) { return loginVo;
LogininforEvent logininforEvent = new LogininforEvent(); }
logininforEvent.setUsername(username);
logininforEvent.setStatus(status); public String emailLogin(String email, String emailCode) {
logininforEvent.setMessage(message); // 通过手邮箱查找用户
logininforEvent.setRequest(ServletUtils.getRequest()); SysUser user = loadUserByEmail(email);
SpringUtils.context().publishEvent(logininforEvent);
} checkLogin(LoginType.EMAIL, user.getUserName(), () -> !validateEmailCode(email, emailCode));
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
/** LoginUser loginUser = buildLoginUser(user);
* 校验短信验证码 // 生成token
*/ LoginHelper.loginByDevice(loginUser, DeviceType.APP);
private boolean validateSmsCode(String phonenumber, String smsCode) {
String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber); recordLogininfor(user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
if (StringUtils.isBlank(code)) { recordLoginInfo(user.getUserId(), user.getUserName());
recordLogininfor(phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); return StpUtil.getTokenValue();
throw new CaptchaExpireException(); }
}
return code.equals(smsCode); public String xcxLogin(String xcxCode) {
} // xcxCode 为 小程序调用 wx.login 授权后获取
// todo 以下自行实现
/** // 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key 与 openid
* 校验邮箱验证码 String openid = "";
*/
private boolean validateEmailCode(String email, String emailCode) { // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + email); SysUser user = loadUserByOpenid(openid);
if (StringUtils.isBlank(code)) {
recordLogininfor(email, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
throw new CaptchaExpireException(); XcxLoginUser loginUser = new XcxLoginUser();
} loginUser.setUserId(user.getUserId());
return code.equals(emailCode); loginUser.setUsername(user.getUserName());
} loginUser.setUserType(user.getUserType());
loginUser.setOpenid(openid);
/** // 生成token
* 校验验证码 LoginHelper.loginByDevice(loginUser, DeviceType.XCX);
*
* @param username 用户名 recordLogininfor(user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
* @param code 验证码 recordLoginInfo(user.getUserId(), user.getUserName());
* @param uuid 唯一标识 return StpUtil.getTokenValue();
*/ }
public void validateCaptcha(String username, String code, String uuid) {
String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, ""); /**
String captcha = RedisUtils.getCacheObject(verifyKey); * 退出登录
RedisUtils.deleteObject(verifyKey); */
if (captcha == null) { public void logout() {
recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); try {
throw new CaptchaExpireException(); LoginUser loginUser = LoginHelper.getLoginUser();
} if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) {
if (!code.equalsIgnoreCase(captcha)) { // 超级管理员 登出清除动态租户
recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")); TenantHelper.clearDynamic();
throw new CaptchaException(); }
} recordLogininfor(loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success"));
} } catch (NotLoginException ignored) {
} finally {
private SysUser loadUserByUsername(String username) { try {
SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>() StpUtil.logout();
.select(SysUser::getUserName, SysUser::getStatus) } catch (NotLoginException ignored) {
.eq(SysUser::getUserName, username) }
.or().eq(SysUser::getPhonenumber, username)); }
if (ObjectUtil.isNull(user)) { }
log.info("登录用户:{} 不存在.", username);
throw new UserException("user.not.exists", username); /**
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { * 记录登录信息
log.info("登录用户:{} 已被停用.", username); *
throw new UserException("user.blocked", username); * @param username 用户名
} * @param status 状态
return userMapper.selectUserByUserName(user.getUserName()); * @param message 消息内容
} */
private void recordLogininfor(String username, String status, String message) {
private SysUser loadUserByPhonenumber(String phonenumber) { LogininforEvent logininforEvent = new LogininforEvent();
SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>() logininforEvent.setUsername(username);
.select(SysUser::getPhonenumber, SysUser::getStatus) logininforEvent.setStatus(status);
.eq(SysUser::getPhonenumber, phonenumber)); logininforEvent.setMessage(message);
if (ObjectUtil.isNull(user)) { logininforEvent.setRequest(ServletUtils.getRequest());
log.info("登录用户:{} 不存在.", phonenumber); SpringUtils.context().publishEvent(logininforEvent);
throw new UserException("user.not.exists", phonenumber); }
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", phonenumber); /**
throw new UserException("user.blocked", phonenumber); * 校验短信验证码
} */
return userMapper.selectUserByPhonenumber(phonenumber); private boolean validateSmsCode(String phonenumber, String smsCode) {
} String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber);
if (StringUtils.isBlank(code)) {
private SysUser loadUserByEmail(String email) { recordLogininfor(phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>() throw new CaptchaExpireException();
.select(SysUser::getPhonenumber, SysUser::getStatus) }
.eq(SysUser::getEmail, email)); return code.equals(smsCode);
if (ObjectUtil.isNull(user)) { }
log.info("登录用户:{} 不存在.", email);
throw new UserException("user.not.exists", email); /**
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { * 校验邮箱验证码
log.info("登录用户:{} 已被停用.", email); */
throw new UserException("user.blocked", email); private boolean validateEmailCode(String email, String emailCode) {
} String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + email);
return userMapper.selectUserByEmail(email); if (StringUtils.isBlank(code)) {
} recordLogininfor(email, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
throw new CaptchaExpireException();
private SysUser loadUserByOpenid(String openid) { }
// 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户 return code.equals(emailCode);
// todo 自行实现 userService.selectUserByOpenid(openid); }
SysUser user = new SysUser();
if (ObjectUtil.isNull(user)) { /**
log.info("登录用户:{} 不存在.", openid); * 校验验证码
// todo 用户不存在 业务逻辑自行实现 *
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { * @param username 用户名
log.info("登录用户:{} 已被停用.", openid); * @param code 验证码
// todo 用户已被停用 业务逻辑自行实现 * @param uuid 唯一标识
} */
return user; public void validateCaptcha(String username, String code, String uuid) {
} String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, "");
String captcha = RedisUtils.getCacheObject(verifyKey);
/** RedisUtils.deleteObject(verifyKey);
* 构建登录用户 if (captcha == null) {
*/ recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
public LoginUser buildLoginUser(SysUser user) { throw new CaptchaExpireException();
LoginUser loginUser = new LoginUser(); }
loginUser.setTenantId(user.getTenantId()); if (!code.equalsIgnoreCase(captcha)) {
loginUser.setUserId(user.getUserId()); recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"));
loginUser.setDeptId(user.getDeptId()); throw new CaptchaException();
loginUser.setUsername(user.getUserName()); }
loginUser.setNickname(user.getNickName()); }
loginUser.setUserType(user.getUserType());
loginUser.setUserPhone(user.getPhonenumber()); private SysUser loadUserByUsername(String username) {
loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId())); SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId())); .select(SysUser::getUserName, SysUser::getStatus)
loginUser.setDeptName(ObjectUtil.isNull(user.getDept()) ? "" : user.getDept().getDeptName()); .eq(SysUser::getUserName, username)
List<RoleDTO> roles = BeanUtil.copyToList(user.getRoles(), RoleDTO.class); .or().eq(SysUser::getPhonenumber, username));
loginUser.setRoles(roles); if (ObjectUtil.isNull(user)) {
return loginUser; log.info("登录用户:{} 不存在.", username);
} throw new UserException("user.not.exists", username);
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", username);
/** throw new UserException("user.blocked", username);
* 记录登录信息 }
* return userMapper.selectUserByUserName(user.getUserName());
* @param userId 用户ID }
*/
public void recordLoginInfo(Long userId, String username) { private SysUser loadUserByPhonenumber(String phonenumber) {
SysUser sysUser = new SysUser(); SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
sysUser.setUserId(userId); .select(SysUser::getPhonenumber, SysUser::getStatus)
sysUser.setLoginIp(ServletUtils.getClientIP()); .eq(SysUser::getPhonenumber, phonenumber));
sysUser.setLoginDate(DateUtils.getNowDate()); if (ObjectUtil.isNull(user)) {
sysUser.setUpdateBy(username); log.info("登录用户:{} 不存在.", phonenumber);
userMapper.updateById(sysUser); throw new UserException("user.not.exists", phonenumber);
} } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", phonenumber);
/** throw new UserException("user.blocked", phonenumber);
* 登录校验 }
*/ return userMapper.selectUserByPhonenumber(phonenumber);
private void checkLogin(LoginType loginType, String username, Supplier<Boolean> supplier) { }
String errorKey = GlobalConstants.PWD_ERR_CNT_KEY + username;
String loginFail = Constants.LOGIN_FAIL; private SysUser loadUserByEmail(String email) {
SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
// 获取用户登录错误次数,默认为0 (可自定义限制策略 例如: key + username + ip) .select(SysUser::getPhonenumber, SysUser::getStatus)
int errorNumber = ObjectUtil.defaultIfNull(RedisUtils.getCacheObject(errorKey), 0); .eq(SysUser::getEmail, email));
// 锁定时间内登录 则踢出 if (ObjectUtil.isNull(user)) {
if (errorNumber >= maxRetryCount) { log.info("登录用户:{} 不存在.", email);
recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); throw new UserException("user.not.exists", email);
throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
} log.info("登录用户:{} 已被停用.", email);
throw new UserException("user.blocked", email);
if (supplier.get()) { }
// 错误次数递增 return userMapper.selectUserByEmail(email);
errorNumber++; }
RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime));
// 达到规定错误次数 则锁定登录 private SysUser loadUserByOpenid(String openid) {
if (errorNumber >= maxRetryCount) { // 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户
recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); // todo 自行实现 userService.selectUserByOpenid(openid);
throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); SysUser user = new SysUser();
} else { if (ObjectUtil.isNull(user)) {
// 未达到规定错误次数 log.info("登录用户:{} 不存在.", openid);
recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber)); // todo 用户不存在 业务逻辑自行实现
throw new UserException(loginType.getRetryLimitCount(), errorNumber); } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
} log.info("登录用户:{} 已被停用.", openid);
} // todo 用户已被停用 业务逻辑自行实现
}
// 登录成功 清空错误次数 return user;
RedisUtils.deleteObject(errorKey); }
}
/**
public void checkTenant(String tenantId) { * 构建登录用户
if (!TenantHelper.isEnable()) { */
return; public LoginUser buildLoginUser(SysUser user) {
} LoginUser loginUser = new LoginUser();
if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) { loginUser.setTenantId(user.getTenantId());
return; loginUser.setUserId(user.getUserId());
} loginUser.setDeptId(user.getDeptId());
SysTenantVo tenant = sysTenantService.queryByTenantId(tenantId); loginUser.setUsername(user.getUserName());
if (ObjectUtil.isNull(tenant)) { loginUser.setNickname(user.getNickName());
log.info("登录企业:{} 不存在.", tenantId); loginUser.setUserType(user.getUserType());
throw new TenantException("company.not.exists"); loginUser.setUserPhone(user.getPhonenumber());
} else if (TenantStatus.DISABLE.getCode().equals(tenant.getStatus())) { loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId()));
log.info("登录企业:{} 已被停用.", tenant.getCompanyName()); loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId()));
throw new TenantException("company.blocked"); loginUser.setDeptName(ObjectUtil.isNull(user.getDept()) ? "" : user.getDept().getDeptName());
} else if (ObjectUtil.isNotNull(tenant.getExpireTime()) List<RoleDTO> roles = BeanUtil.copyToList(user.getRoles(), RoleDTO.class);
&& new Date().after(tenant.getExpireTime())) { loginUser.setRoles(roles);
log.info("登录企业:{} 已超过有效期.", tenant.getCompanyName()); return loginUser;
throw new TenantException("company.expired"); }
}
}
/**
* 记录登录信息
public String checkDefaultTenant(String tenantId, String phoneNumber) { *
if (!TenantHelper.isEnable()) { * @param userId 用户ID
return null; */
} public void recordLoginInfo(Long userId, String username) {
if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) { SysUser sysUser = new SysUser();
return null; sysUser.setUserId(userId);
} sysUser.setLoginIp(ServletUtils.getClientIP());
SysTenantVo tenant = sysTenantService.queryByTenantId(tenantId); sysUser.setLoginDate(DateUtils.getNowDate());
if (ObjectUtil.isNull(tenant)) { sysUser.setUpdateBy(username);
log.info("登录企业:{} 不存在.", tenantId); userMapper.updateById(sysUser);
RedisUtils.deleteObject(GlobalConstants.PHONE_DEFAULT_TENANT + phoneNumber); }
return null;
} else if (TenantStatus.DISABLE.getCode().equals(tenant.getStatus())) { /**
log.info("登录企业:{} 已被停用.", tenant.getCompanyName()); * 登录校验
RedisUtils.deleteObject(GlobalConstants.PHONE_DEFAULT_TENANT + phoneNumber); */
return null; private void checkLogin(LoginType loginType, String username, Supplier<Boolean> supplier) {
} else if (ObjectUtil.isNotNull(tenant.getExpireTime()) String errorKey = GlobalConstants.PWD_ERR_CNT_KEY + username;
&& new Date().after(tenant.getExpireTime())) { String loginFail = Constants.LOGIN_FAIL;
log.info("登录企业:{} 已超过有效期.", tenant.getCompanyName());
RedisUtils.deleteObject(GlobalConstants.PHONE_DEFAULT_TENANT + phoneNumber); // 获取用户登录错误次数,默认为0 (可自定义限制策略 例如: key + username + ip)
return null; int errorNumber = ObjectUtil.defaultIfNull(RedisUtils.getCacheObject(errorKey), 0);
} // 锁定时间内登录 则踢出
return tenantId; if (errorNumber >= maxRetryCount) {
} recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime));
throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime);
}
public List<SysTenantVo> tenantListByAccount(String username) {
return TenantHelper.ignore(() -> sysTenantService.selectTenantList(username)); if (supplier.get()) {
} // 错误次数递增
errorNumber++;
// public List<SysTenantVo> selectTenantList(String username){ RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime));
// // 达到规定错误次数 则锁定登录
// } if (errorNumber >= maxRetryCount) {
recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime));
throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime);
public List<SysUser> queryListByPhone(String username) { } else {
return TenantHelper.ignore(() -> { // 未达到规定错误次数
List<SysUser> sysUsers = null; recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber));
if (ReUtil.isMatch(RegexPool.MOBILE, username)) { throw new UserException(loginType.getRetryLimitCount(), errorNumber);
}
LambdaQueryWrapper<SysUser> lqw = new LambdaQueryWrapper<SysUser>() }
.select(SysUser::getUserName, SysUser::getStatus, SysUser::getTenantId, SysUser::getDelFlag)
.eq(SysUser::getPhonenumber, username) // 登录成功 清空错误次数
.orderByDesc(SysUser::getUserId); RedisUtils.deleteObject(errorKey);
// sysUsers = userMapper.selectUserByTenantPhone(username); }
sysUsers = userMapper.selectList(lqw);
} else { public void checkTenant(String tenantId) {
LambdaQueryWrapper<SysUser> lqw = new LambdaQueryWrapper<SysUser>() if (!TenantHelper.isEnable()) {
.select(SysUser::getUserName, SysUser::getStatus, SysUser::getTenantId) return;
.eq(SysUser::getUserName, username) }
.orderByDesc(SysUser::getUserId); if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) {
// sysUsers = userMapper.selectUserByTenantUsername(username); return;
sysUsers = userMapper.selectList(lqw); }
} SysTenantVo tenant = sysTenantService.queryByTenantId(tenantId);
return sysUsers; if (ObjectUtil.isNull(tenant)) {
}); log.info("登录企业:{} 不存在.", tenantId);
} throw new TenantException("company.not.exists");
} else if (TenantStatus.DISABLE.getCode().equals(tenant.getStatus())) {
log.info("登录企业:{} 已被停用.", tenant.getCompanyName());
public LoginVo switchTenant(String tenantId) { throw new TenantException("company.blocked");
} else if (ObjectUtil.isNotNull(tenant.getExpireTime())
//获取当前登录信息 && new Date().after(tenant.getExpireTime())) {
Long userId = LoginHelper.getUserId(); log.info("登录企业:{} 已超过有效期.", tenant.getCompanyName());
Assert.notNull(userId, "企业切换失败!"); throw new TenantException("company.expired");
// 如果 切换租户和当前登录租户一致,仅保存默认租户 }
LoginUser loginUserVo = LoginHelper.getLoginUser(); }
if (tenantId.equals(loginUserVo.getTenantId())) {
//保存当前账号的默认租户
String defaultTenantKey = GlobalConstants.PHONE_DEFAULT_TENANT + loginUserVo.getUserPhone(); public String checkDefaultTenant(String tenantId, String phoneNumber) {
RedisUtils.setCacheObject(defaultTenantKey, tenantId, Duration.ofDays(90)); if (!TenantHelper.isEnable()) {
LoginVo loginVo = new LoginVo(); return null;
loginVo.setTenantId(TenantHelper.getTenantId()); }
loginVo.setAccessToken(StpUtil.getTokenValue()); if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) {
loginVo.setExpireIn(StpUtil.getTokenTimeout()); return null;
return loginVo; }
} SysTenantVo tenant = sysTenantService.queryByTenantId(tenantId);
if (ObjectUtil.isNull(tenant)) {
SysUser sysUser = TenantHelper.ignore(() -> { log.info("登录企业:{} 不存在.", tenantId);
return userMapper.selectUserById(userId); RedisUtils.deleteObject(GlobalConstants.PHONE_DEFAULT_TENANT + phoneNumber);
}); return null;
Assert.notNull(sysUser, "用户信息为空,企业切换失败!"); } else if (TenantStatus.DISABLE.getCode().equals(tenant.getStatus())) {
if (StrUtil.isEmpty(sysUser.getPhonenumber())) { log.info("登录企业:{} 已被停用.", tenant.getCompanyName());
Assert.notNull(sysUser, "用户手机号为空,企业切换失败!"); RedisUtils.deleteObject(GlobalConstants.PHONE_DEFAULT_TENANT + phoneNumber);
} return null;
//退出登录 } else if (ObjectUtil.isNotNull(tenant.getExpireTime())
StpUtil.logout(); && new Date().after(tenant.getExpireTime())) {
String tokenValue = StpUtil.getTokenValueByLoginId(userId); log.info("登录企业:{} 已超过有效期.", tenant.getCompanyName());
StpUtil.logoutByTokenValue(tokenValue); RedisUtils.deleteObject(GlobalConstants.PHONE_DEFAULT_TENANT + phoneNumber);
StpUtil.kickoutByTokenValue(tokenValue); return null;
// RedisUtils.deleteKeys("*"+tokenValue+"*"); }
return tenantId;
}
//重新登录
TenantHelper.setTenantId(tenantId);
String username = sysUser.getPhonenumber(); public List<SysTenantVo> tenantListByAccount(String username) {
SysUser user = loadUserByUsername(sysUser.getPhonenumber()); return TenantHelper.ignore(() -> sysTenantService.selectTenantList(username));
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 }
LoginUser loginUser = buildLoginUser(user);
// 生成token // public List<SysTenantVo> selectTenantList(String username){
LoginHelper.loginByDevice(loginUser, DeviceType.PC); //
// }
log.info("当前租户由" + sysUser.getTenantId() + "切换为" + tenantId);
//保存当前账号的默认租户 public List<SysUser> queryListByPhone(String username) {
String defaultTenantKey = GlobalConstants.PHONE_DEFAULT_TENANT + loginUser.getUserPhone(); return TenantHelper.ignore(() -> {
RedisUtils.setCacheObject(defaultTenantKey, tenantId, Duration.ofDays(90)); List<SysUser> sysUsers = null;
recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); if (ReUtil.isMatch(RegexPool.MOBILE, username)) {
recordLoginInfo(user.getUserId(), username);
LambdaQueryWrapper<SysUser> lqw = new LambdaQueryWrapper<SysUser>()
LoginVo loginVo = new LoginVo(); .select(SysUser::getUserName, SysUser::getStatus, SysUser::getTenantId, SysUser::getDelFlag)
loginVo.setTenantId(TenantHelper.getTenantId()); .eq(SysUser::getPhonenumber, username)
loginVo.setAccessToken(StpUtil.getTokenValue()); .orderByDesc(SysUser::getUserId);
loginVo.setExpireIn(StpUtil.getTokenTimeout()); // sysUsers = userMapper.selectUserByTenantPhone(username);
return loginVo; sysUsers = userMapper.selectList(lqw);
} } else {
} LambdaQueryWrapper<SysUser> lqw = new LambdaQueryWrapper<SysUser>()
.select(SysUser::getUserName, SysUser::getStatus, SysUser::getTenantId)
.eq(SysUser::getUserName, username)
.orderByDesc(SysUser::getUserId);
// sysUsers = userMapper.selectUserByTenantUsername(username);
sysUsers = userMapper.selectList(lqw);
}
return sysUsers;
});
}
public LoginVo switchTenant(String tenantId) {
//获取当前登录信息
Long userId = LoginHelper.getUserId();
Assert.notNull(userId, "企业切换失败!");
// 如果 切换租户和当前登录租户一致,仅保存默认租户
LoginUser loginUserVo = LoginHelper.getLoginUser();
if (tenantId.equals(loginUserVo.getTenantId())) {
//保存当前账号的默认租户
String defaultTenantKey = GlobalConstants.PHONE_DEFAULT_TENANT + loginUserVo.getUserPhone();
RedisUtils.setCacheObject(defaultTenantKey, tenantId, Duration.ofDays(90));
LoginVo loginVo = new LoginVo();
loginVo.setTenantId(TenantHelper.getTenantId());
loginVo.setAccessToken(StpUtil.getTokenValue());
loginVo.setExpireIn(StpUtil.getTokenTimeout());
return loginVo;
}
SysUser sysUser = TenantHelper.ignore(() -> {
return userMapper.selectUserById(userId);
});
Assert.notNull(sysUser, "用户信息为空,企业切换失败!");
if (StrUtil.isEmpty(sysUser.getPhonenumber())) {
Assert.notNull(sysUser, "用户手机号为空,企业切换失败!");
}
//退出登录
StpUtil.logout();
String tokenValue = StpUtil.getTokenValueByLoginId(userId);
StpUtil.logoutByTokenValue(tokenValue);
StpUtil.kickoutByTokenValue(tokenValue);
// RedisUtils.deleteKeys("*"+tokenValue+"*");
//重新登录
TenantHelper.setTenantId(tenantId);
String username = sysUser.getPhonenumber();
SysUser user = loadUserByUsername(sysUser.getPhonenumber());
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
LoginUser loginUser = buildLoginUser(user);
// 生成token
LoginHelper.loginByDevice(loginUser, DeviceType.PC);
log.info("当前租户由" + sysUser.getTenantId() + "切换为" + tenantId);
//保存当前账号的默认租户
String defaultTenantKey = GlobalConstants.PHONE_DEFAULT_TENANT + loginUser.getUserPhone();
RedisUtils.setCacheObject(defaultTenantKey, tenantId, Duration.ofDays(90));
recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
recordLoginInfo(user.getUserId(), username);
LoginVo loginVo = new LoginVo();
loginVo.setTenantId(TenantHelper.getTenantId());
loginVo.setAccessToken(StpUtil.getTokenValue());
loginVo.setExpireIn(StpUtil.getTokenTimeout());
return loginVo;
}
}
package com.dsk.system.service.impl; package com.dsk.system.service.impl;
import cn.dev33.satoken.secure.BCrypt; import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.session.SaSession; import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.session.TokenSign; import cn.dev33.satoken.session.TokenSign;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dsk.common.constant.CacheNames; import com.dsk.common.constant.CacheNames;
import com.dsk.common.constant.Constants; import com.dsk.common.constant.Constants;
import com.dsk.common.constant.TenantConstants; import com.dsk.common.constant.TenantConstants;
import com.dsk.common.constant.UserConstants; import com.dsk.common.constant.UserConstants;
import com.dsk.common.core.domain.PageQuery; import com.dsk.common.core.domain.PageQuery;
import com.dsk.common.core.domain.entity.SysDictData; import com.dsk.common.core.domain.entity.SysDictData;
import com.dsk.common.core.domain.entity.SysDictType; import com.dsk.common.core.domain.entity.SysDictType;
import com.dsk.common.core.page.TableDataInfo; import com.dsk.common.core.page.TableDataInfo;
import com.dsk.common.enums.UserStatus; import com.dsk.common.enums.UserStatus;
import com.dsk.common.exception.ServiceException; import com.dsk.common.exception.ServiceException;
import com.dsk.common.utils.PasswordUtils; import com.dsk.common.utils.DingTalkUtil;
import com.dsk.common.utils.StringUtils; import com.dsk.common.utils.PasswordUtils;
import com.dsk.common.utils.redis.RedisUtils; import com.dsk.common.utils.StringUtils;
import com.dsk.system.domain.*; import com.dsk.common.utils.redis.RedisUtils;
import com.dsk.system.domain.bo.SysTenantAdminBo; import com.dsk.system.domain.*;
import com.dsk.system.domain.bo.SysTenantBo; import com.dsk.system.domain.bo.SysTenantAdminBo;
import com.dsk.system.domain.vo.SysTenantVo; import com.dsk.system.domain.bo.SysTenantBo;
import com.dsk.system.mapper.*; import com.dsk.system.domain.vo.SysTenantVo;
import com.dsk.system.service.ISysTenantService; import com.dsk.system.mapper.*;
import lombok.RequiredArgsConstructor; import com.dsk.system.service.ISysTenantService;
import lombok.extern.slf4j.Slf4j; import lombok.RequiredArgsConstructor;
import org.dromara.sms4j.api.SmsBlend; import lombok.extern.slf4j.Slf4j;
import org.dromara.sms4j.api.entity.SmsResponse; import org.dromara.sms4j.api.SmsBlend;
import org.dromara.sms4j.core.factory.SmsFactory; import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.provider.enumerate.SupplierType; import org.dromara.sms4j.core.factory.SmsFactory;
import org.springframework.cache.annotation.CacheEvict; import org.dromara.sms4j.provider.enumerate.SupplierType;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service; import org.springframework.cache.annotation.Cacheable;
import org.springframework.transaction.annotation.Transactional; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.*;
/**
* 企业Service业务层处理 /**
* * 企业Service业务层处理
* @author sxk *
* @date 2023.08.22 * @author sxk
*/ * @date 2023.08.22
@RequiredArgsConstructor */
@Service @RequiredArgsConstructor
@Slf4j @Service
public class ISysTenantServiceImpl implements ISysTenantService { @Slf4j
public class ISysTenantServiceImpl implements ISysTenantService {
private final SysTenantMapper baseMapper;
private final SysTenantPackageMapper tenantPackageMapper; private final SysTenantMapper baseMapper;
private final SysRoleMapper roleMapper; private final SysTenantPackageMapper tenantPackageMapper;
private final SysRoleMenuMapper roleMenuMapper; private final SysRoleMapper roleMapper;
private final SysDeptMapper deptMapper; private final SysRoleMenuMapper roleMenuMapper;
private final SysRoleDeptMapper roleDeptMapper; private final SysDeptMapper deptMapper;
private final SysUserMapper userMapper; private final SysRoleDeptMapper roleDeptMapper;
private final SysUserRoleMapper userRoleMapper; private final SysUserMapper userMapper;
private final SysDictTypeMapper dictTypeMapper; private final SysUserRoleMapper userRoleMapper;
private final SysDictDataMapper dictDataMapper; private final SysDictTypeMapper dictTypeMapper;
private final SysConfigMapper configMapper; private final SysDictDataMapper dictDataMapper;
private final SysConfigMapper configMapper;
/**
* 查询租户列表 /**
*/ * 查询租户列表
@Override */
public TableDataInfo<SysTenantVo> queryPageList(SysTenantBo bo, PageQuery pageQuery) { @Override
LambdaQueryWrapper<SysTenant> lqw = buildQueryWrapper(bo); public TableDataInfo<SysTenantVo> queryPageList(SysTenantBo bo, PageQuery pageQuery) {
pageQuery.setIsAsc("desc"); LambdaQueryWrapper<SysTenant> lqw = buildQueryWrapper(bo);
pageQuery.setOrderByColumn("createTime"); pageQuery.setIsAsc("desc");
Page<SysTenantVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw); pageQuery.setOrderByColumn("createTime");
for (SysTenantVo sysTenantVo : result.getRecords()) { Page<SysTenantVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
SysTenantPackage sysTenantPackage = tenantPackageMapper.selectById(sysTenantVo.getPackageId()); for (SysTenantVo sysTenantVo : result.getRecords()) {
sysTenantVo.setPackageName(sysTenantPackage.getPackageName()); SysTenantPackage sysTenantPackage = tenantPackageMapper.selectById(sysTenantVo.getPackageId());
} sysTenantVo.setPackageName(sysTenantPackage.getPackageName());
return TableDataInfo.build(result); }
} return TableDataInfo.build(result);
}
/**
* 禁用所有已过期租户 /**
*/ * 禁用所有已过期租户
@Override */
public void handleExpiredTenant() { @Override
Date now = new Date(); public void handleExpiredTenant() {
//查询所有已过期租户 Date now = new Date();
List<SysTenant> tenantList = baseMapper.selectList(new LambdaQueryWrapper<SysTenant>() //查询所有已过期租户
.eq(SysTenant::getStatus, TenantConstants.NORMAL) List<SysTenant> tenantList = baseMapper.selectList(new LambdaQueryWrapper<SysTenant>()
.gt(SysTenant::getStartTime, now) .eq(SysTenant::getStatus, TenantConstants.NORMAL)
.or() .gt(SysTenant::getStartTime, now)
.lt(SysTenant::getExpireTime, now)); .or()
//批量禁用已过期租户 .lt(SysTenant::getExpireTime, now));
if (!tenantList.isEmpty()) { //批量禁用已过期租户
tenantList.forEach(sysTenant -> sysTenant.setStatus(TenantConstants.DISABLE)); if (!tenantList.isEmpty()) {
baseMapper.updateBatchById(tenantList); tenantList.forEach(sysTenant -> sysTenant.setStatus(TenantConstants.DISABLE));
} baseMapper.updateBatchById(tenantList);
} }
}
// /**
// * 查询租户列表 // /**
// */ // * 查询租户列表
// @Override // */
// public List<SysTenantVo> queryList(SysTenantBo bo) { // @Override
// LambdaQueryWrapper<SysTenant> lqw = buildQueryWrapper(bo); // public List<SysTenantVo> queryList(SysTenantBo bo) {
// return baseMapper.selectVoList(lqw); // LambdaQueryWrapper<SysTenant> lqw = buildQueryWrapper(bo);
// } // return baseMapper.selectVoList(lqw);
// }
/**
* 基于租户ID查询租户 /**
*/ * 基于租户ID查询租户
@Cacheable(cacheNames = CacheNames.SYS_TENANT, key = "#tenantId") */
@Override @Cacheable(cacheNames = CacheNames.SYS_TENANT, key = "#tenantId")
public SysTenantVo queryByTenantId(String tenantId) { @Override
return baseMapper.selectVoOne(new LambdaQueryWrapper<SysTenant>().eq(SysTenant::getTenantId, tenantId)); public SysTenantVo queryByTenantId(String tenantId) {
} return baseMapper.selectVoOne(new LambdaQueryWrapper<SysTenant>().eq(SysTenant::getTenantId, tenantId));
}
@Override
public List<SysTenantVo> selectTenantList(String username) { @Override
return baseMapper.selectTenantList(username); public List<SysTenantVo> selectTenantList(String username) {
} return baseMapper.selectTenantList(username);
}
private LambdaQueryWrapper<SysTenant> buildQueryWrapper(SysTenantBo bo) {
LambdaQueryWrapper<SysTenant> lqw = Wrappers.lambdaQuery(); private LambdaQueryWrapper<SysTenant> buildQueryWrapper(SysTenantBo bo) {
lqw.eq(StringUtils.isNotBlank(bo.getTenantId()), SysTenant::getTenantId, bo.getTenantId()); LambdaQueryWrapper<SysTenant> lqw = Wrappers.lambdaQuery();
lqw.like(StringUtils.isNotBlank(bo.getContactUserName()), SysTenant::getContactUserName, bo.getContactUserName()); lqw.eq(StringUtils.isNotBlank(bo.getTenantId()), SysTenant::getTenantId, bo.getTenantId());
lqw.eq(StringUtils.isNotBlank(bo.getContactPhone()), SysTenant::getContactPhone, bo.getContactPhone()); lqw.like(StringUtils.isNotBlank(bo.getContactUserName()), SysTenant::getContactUserName, bo.getContactUserName());
lqw.like(StringUtils.isNotBlank(bo.getCompanyName()), SysTenant::getCompanyName, bo.getCompanyName()); lqw.eq(StringUtils.isNotBlank(bo.getContactPhone()), SysTenant::getContactPhone, bo.getContactPhone());
lqw.eq(StringUtils.isNotBlank(bo.getLicenseNumber()), SysTenant::getLicenseNumber, bo.getLicenseNumber()); lqw.like(StringUtils.isNotBlank(bo.getCompanyName()), SysTenant::getCompanyName, bo.getCompanyName());
lqw.eq(StringUtils.isNotBlank(bo.getAddress()), SysTenant::getAddress, bo.getAddress()); lqw.eq(StringUtils.isNotBlank(bo.getLicenseNumber()), SysTenant::getLicenseNumber, bo.getLicenseNumber());
lqw.eq(StringUtils.isNotBlank(bo.getIntro()), SysTenant::getIntro, bo.getIntro()); lqw.eq(StringUtils.isNotBlank(bo.getAddress()), SysTenant::getAddress, bo.getAddress());
lqw.like(StringUtils.isNotBlank(bo.getDomain()), SysTenant::getDomain, bo.getDomain()); lqw.eq(StringUtils.isNotBlank(bo.getIntro()), SysTenant::getIntro, bo.getIntro());
lqw.eq(bo.getPackageId() != null, SysTenant::getPackageId, bo.getPackageId()); lqw.like(StringUtils.isNotBlank(bo.getDomain()), SysTenant::getDomain, bo.getDomain());
lqw.eq(bo.getExpireTime() != null, SysTenant::getExpireTime, bo.getExpireTime()); lqw.eq(bo.getPackageId() != null, SysTenant::getPackageId, bo.getPackageId());
lqw.eq(bo.getAccountCount() != null, SysTenant::getAccountCount, bo.getAccountCount()); lqw.eq(bo.getExpireTime() != null, SysTenant::getExpireTime, bo.getExpireTime());
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysTenant::getStatus, bo.getStatus()); lqw.eq(bo.getAccountCount() != null, SysTenant::getAccountCount, bo.getAccountCount());
return lqw; lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysTenant::getStatus, bo.getStatus());
} return lqw;
}
/**
* 查询租户 /**
*/ * 查询租户
@Override */
public SysTenantVo queryById(Long id) { @Override
return baseMapper.selectVoById(id); public SysTenantVo queryById(Long id) {
} return baseMapper.selectVoById(id);
}
/**
* 校验企业名称是否唯一 /**
*/ * 校验企业名称是否唯一
@Override */
public boolean checkCompanyNameUnique(SysTenantBo bo) { @Override
boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysTenant>() public boolean checkCompanyNameUnique(SysTenantBo bo) {
.eq(SysTenant::getCompanyName, bo.getCompanyName()) boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysTenant>()
.ne(ObjectUtil.isNotNull(bo.getTenantId()), SysTenant::getTenantId, bo.getTenantId())); .eq(SysTenant::getCompanyName, bo.getCompanyName())
return !exist; .ne(ObjectUtil.isNotNull(bo.getTenantId()), SysTenant::getTenantId, bo.getTenantId()));
} return !exist;
}
/**
* 新增租户 /**
*/ * 新增租户
@Override */
@Transactional(rollbackFor = Exception.class) @Override
public Boolean insertByBo(SysTenantBo bo) { @Transactional(rollbackFor = Exception.class)
SysTenant add = BeanUtil.toBean(bo, SysTenant.class); public Boolean insertByBo(SysTenantBo bo) {
SysTenant add = BeanUtil.toBean(bo, SysTenant.class);
// 获取所有租户编号
List<String> tenantIds = baseMapper.selectObjs( // 获取所有租户编号
new LambdaQueryWrapper<SysTenant>().select(SysTenant::getTenantId), Convert::toStr); List<String> tenantIds = baseMapper.selectObjs(
String tenantId = generateTenantId(tenantIds); new LambdaQueryWrapper<SysTenant>().select(SysTenant::getTenantId), Convert::toStr);
add.setTenantId(tenantId); String tenantId = generateTenantId(tenantIds);
boolean flag = baseMapper.insert(add) > 0; add.setTenantId(tenantId);
if (!flag) {
throw new ServiceException("创建租户失败"); boolean flag = baseMapper.insert(add) > 0;
} if (!flag) {
bo.setId(add.getId()); throw new ServiceException("创建租户失败");
}
// 根据套餐创建角色 bo.setId(add.getId());
Long roleId = createTenantRole(tenantId, bo.getPackageId(),
TenantConstants.TENANT_SUPER_ADMIN_ROLE_NAME, // 根据套餐创建角色
TenantConstants.TENANT_SUPER_ADMIN_ROLE_KEY); Long roleId = createTenantRole(tenantId, bo.getPackageId(),
TenantConstants.TENANT_SUPER_ADMIN_ROLE_NAME,
// 创建部门: 公司名是部门名称 TenantConstants.TENANT_SUPER_ADMIN_ROLE_KEY);
SysDept dept = new SysDept();
dept.setTenantId(tenantId); // 创建部门: 公司名是部门名称
dept.setDeptName(bo.getCompanyName()); SysDept dept = new SysDept();
dept.setParentId(Constants.TOP_PARENT_ID); dept.setTenantId(tenantId);
dept.setAncestors(Constants.TOP_PARENT_ID.toString()); dept.setDeptName(bo.getCompanyName());
deptMapper.insert(dept); dept.setParentId(Constants.TOP_PARENT_ID);
Long deptId = dept.getDeptId(); dept.setAncestors(Constants.TOP_PARENT_ID.toString());
deptMapper.insert(dept);
// 角色和部门关联表 Long deptId = dept.getDeptId();
SysRoleDept roleDept = new SysRoleDept();
roleDept.setRoleId(roleId); // 角色和部门关联表
roleDept.setDeptId(deptId); SysRoleDept roleDept = new SysRoleDept();
roleDeptMapper.insert(roleDept); roleDept.setRoleId(roleId);
roleDept.setDeptId(deptId);
// 创建系统用户 roleDeptMapper.insert(roleDept);
SysUser user = new SysUser();
user.setTenantId(tenantId); // 创建系统用户
user.setPhonenumber(bo.getContactPhone()); SysUser user = new SysUser();
//默认新增用户名为手机号 user.setTenantId(tenantId);
user.setUserName(bo.getContactPhone()); String thirdPlatformKey = UUID.randomUUID().toString();
user.setNickName(bo.getContactUserName()); user.setThirdPlatformKey(thirdPlatformKey);
//生成8位随机密码 user.setPhonenumber(bo.getContactPhone());
String password = PasswordUtils.generatePwd(8); //默认新增用户名为手机号
user.setPassword(BCrypt.hashpw(password)); user.setUserName(bo.getContactPhone());
user.setDeptId(deptId); user.setNickName(bo.getContactUserName());
user.setCreateTime(new DateTime()); //生成8位随机密码
userMapper.insert(user); String password = PasswordUtils.generatePwd(8);
//新增系统用户后,默认当前用户为部门的负责人 user.setPassword(BCrypt.hashpw(password));
SysDept sd = new SysDept(); user.setDeptId(deptId);
sd.setLeader(String.valueOf(user.getUserId())); user.setCreateTime(new DateTime());
sd.setDeptId(deptId); userMapper.insert(user);
deptMapper.updateById(sd); //新增系统用户后,默认当前用户为部门的负责人
SysDept sd = new SysDept();
// 用户和角色关联表 sd.setLeader(String.valueOf(user.getUserId()));
SysUserRole userRole = new SysUserRole(); sd.setDeptId(deptId);
userRole.setUserId(user.getUserId()); deptMapper.updateById(sd);
userRole.setRoleId(roleId);
userRoleMapper.insert(userRole); // 用户和角色关联表
SysUserRole userRole = new SysUserRole();
String defaultTenantId = TenantConstants.DEFAULT_TENANT_ID; userRole.setUserId(user.getUserId());
List<SysDictType> dictTypeList = dictTypeMapper.selectList( userRole.setRoleId(roleId);
new LambdaQueryWrapper<SysDictType>().eq(SysDictType::getTenantId, defaultTenantId)); userRoleMapper.insert(userRole);
List<SysDictData> dictDataList = dictDataMapper.selectList(
new LambdaQueryWrapper<SysDictData>().eq(SysDictData::getTenantId, defaultTenantId)); String defaultTenantId = TenantConstants.DEFAULT_TENANT_ID;
for (SysDictType dictType : dictTypeList) { List<SysDictType> dictTypeList = dictTypeMapper.selectList(
dictType.setDictId(null); new LambdaQueryWrapper<SysDictType>().eq(SysDictType::getTenantId, defaultTenantId));
dictType.setTenantId(tenantId); List<SysDictData> dictDataList = dictDataMapper.selectList(
} new LambdaQueryWrapper<SysDictData>().eq(SysDictData::getTenantId, defaultTenantId));
for (SysDictData dictData : dictDataList) { for (SysDictType dictType : dictTypeList) {
dictData.setDictCode(null); dictType.setDictId(null);
dictData.setTenantId(tenantId); dictType.setTenantId(tenantId);
} }
dictTypeMapper.insertBatch(dictTypeList); for (SysDictData dictData : dictDataList) {
dictDataMapper.insertBatch(dictDataList); dictData.setDictCode(null);
dictData.setTenantId(tenantId);
List<SysConfig> sysConfigList = configMapper.selectList( }
new LambdaQueryWrapper<SysConfig>() dictTypeMapper.insertBatch(dictTypeList);
.eq(SysConfig::getTenantId, defaultTenantId) dictDataMapper.insertBatch(dictDataList);
.eq(SysConfig::getConfigType, "Y"));
for (SysConfig config : sysConfigList) { List<SysConfig> sysConfigList = configMapper.selectList(
config.setConfigId(null); new LambdaQueryWrapper<SysConfig>()
config.setTenantId(tenantId); .eq(SysConfig::getTenantId, defaultTenantId)
} .eq(SysConfig::getConfigType, "Y"));
configMapper.insertBatch(sysConfigList); for (SysConfig config : sysConfigList) {
config.setConfigId(null);
////此处暂用钉钉机器人模拟发送短信 config.setTenantId(tenantId);
//String content = "【短信通知】:" }
// + bo.getContactUserName() configMapper.insertBatch(sysConfigList);
// + ",您好,您已经成功开通数字化经营管理系统,请使用手机号码登录,初始密码为"
// + password //此处暂用钉钉机器人模拟发送短信
// + "。友情提示:为了您的账号安全,请勿泄露密码。"; String content = "【短信通知】:"
//DingTalkUtil.sendDingTalkMsg(content); + bo.getContactUserName()
+ ",您好,您已经成功开通数字化经营管理系统,请使用手机号码登录,初始密码为"
//租户新增成功,发送短信通知租户 + password
LinkedHashMap<String, String> map = new LinkedHashMap<>(1); + ",三方平台登录秘钥为"
map.put("company", bo.getContactUserName()); + thirdPlatformKey
map.put("pwd", password); + "。友情提示:为了您的账号安全,请勿泄露密码。";
SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.ALIBABA); DingTalkUtil.sendDingTalkMsg(content);
SmsResponse smsResponse = smsBlend.sendMessage(bo.getContactPhone(), "SMS_463175230", map);
if (!"OK".equals(smsResponse.getCode())) { //租户新增成功,发送短信通知租户
log.error("新增租户通知短信发送异常 => {}", smsResponse); LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
} map.put("company", bo.getContactUserName());
return true; map.put("pwd", password);
} SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.ALIBABA);
SmsResponse smsResponse = smsBlend.sendMessage(bo.getContactPhone(), "SMS_463175230", map);
/** if (!"OK".equals(smsResponse.getCode())) {
* 新增企业普通管理员账号 log.error("新增租户通知短信发送异常 => {}", smsResponse);
* }
* @param tenantAdminBo 用户信息 return true;
* @return 结果 }
*/
@Override /**
@Transactional(rollbackFor = Exception.class) * 新增企业普通管理员账号
public Boolean addTenantAdmin(SysTenantAdminBo tenantAdminBo) { *
String tenantId = tenantAdminBo.getTenantId(); * @param tenantAdminBo 用户信息
* @return 结果
//获取部门ID */
Long deptId = deptMapper.selectOne(new LambdaQueryWrapper<SysDept>() @Override
.eq(SysDept::getTenantId, tenantId)).getDeptId(); @Transactional(rollbackFor = Exception.class)
public Boolean addTenantAdmin(SysTenantAdminBo tenantAdminBo) {
SysRole sysRole = roleMapper.selectOne(new LambdaQueryWrapper<SysRole>() String tenantId = tenantAdminBo.getTenantId();
.eq(SysRole::getStatus, UserConstants.ROLE_NORMAL)
.eq(SysRole::getDelFlag, UserConstants.ROLE_NORMAL) //获取部门ID
.eq(SysRole::getTenantId, tenantId) Long deptId = deptMapper.selectOne(new LambdaQueryWrapper<SysDept>()
.eq(SysRole::getRoleKey, TenantConstants.TENANT_ADMIN_ROLE_KEY)); .eq(SysDept::getTenantId, tenantId)).getDeptId();
Long roleId = null; SysRole sysRole = roleMapper.selectOne(new LambdaQueryWrapper<SysRole>()
//校验当前企业是否已存在普通管理员角色 .eq(SysRole::getStatus, UserConstants.ROLE_NORMAL)
if (ObjectUtil.isNull(sysRole)) { .eq(SysRole::getDelFlag, UserConstants.ROLE_NORMAL)
//不存在,则根据套餐创建角色 .eq(SysRole::getTenantId, tenantId)
roleId = createTenantRole(tenantId, tenantAdminBo.getPackageId(), .eq(SysRole::getRoleKey, TenantConstants.TENANT_ADMIN_ROLE_KEY));
TenantConstants.TENANT_ADMIN_ROLE_NAME,
TenantConstants.TENANT_ADMIN_ROLE_KEY); Long roleId = null;
//校验当前企业是否已存在普通管理员角色
// 角色和部门关联表 if (ObjectUtil.isNull(sysRole)) {
SysRoleDept roleDept = new SysRoleDept(); //不存在,则根据套餐创建角色
roleDept.setRoleId(roleId); roleId = createTenantRole(tenantId, tenantAdminBo.getPackageId(),
roleDept.setDeptId(deptId); TenantConstants.TENANT_ADMIN_ROLE_NAME,
roleDeptMapper.insert(roleDept); TenantConstants.TENANT_ADMIN_ROLE_KEY);
} else {
roleId = sysRole.getRoleId(); // 角色和部门关联表
} SysRoleDept roleDept = new SysRoleDept();
roleDept.setRoleId(roleId);
// 创建系统用户 roleDept.setDeptId(deptId);
SysUser user = new SysUser(); roleDeptMapper.insert(roleDept);
user.setTenantId(tenantId); } else {
user.setPhonenumber(tenantAdminBo.getPhonenumber()); roleId = sysRole.getRoleId();
//默认新增用户名为手机号 }
user.setUserName(tenantAdminBo.getPhonenumber());
user.setNickName(tenantAdminBo.getNickName()); // 创建系统用户
//生成8位随机密码 SysUser user = new SysUser();
String password = PasswordUtils.generatePwd(8); user.setTenantId(tenantId);
user.setPassword(BCrypt.hashpw(password)); user.setPhonenumber(tenantAdminBo.getPhonenumber());
user.setDeptId(deptId); //默认新增用户名为手机号
user.setCreateTime(new DateTime()); user.setUserName(tenantAdminBo.getPhonenumber());
userMapper.insert(user); user.setNickName(tenantAdminBo.getNickName());
//生成8位随机密码
// 用户和角色关联表 String password = PasswordUtils.generatePwd(8);
SysUserRole userRole = new SysUserRole(); user.setPassword(BCrypt.hashpw(password));
userRole.setUserId(user.getUserId()); user.setDeptId(deptId);
userRole.setRoleId(roleId); user.setCreateTime(new DateTime());
userRoleMapper.insert(userRole); userMapper.insert(user);
List<SysConfig> sysConfigList = configMapper.selectList( // 用户和角色关联表
new LambdaQueryWrapper<SysConfig>() SysUserRole userRole = new SysUserRole();
.eq(SysConfig::getTenantId, TenantConstants.DEFAULT_TENANT_ID) userRole.setUserId(user.getUserId());
.eq(SysConfig::getConfigType, "Y")); userRole.setRoleId(roleId);
for (SysConfig config : sysConfigList) { userRoleMapper.insert(userRole);
config.setConfigId(null);
config.setTenantId(tenantId); List<SysConfig> sysConfigList = configMapper.selectList(
} new LambdaQueryWrapper<SysConfig>()
configMapper.insertBatch(sysConfigList); .eq(SysConfig::getTenantId, TenantConstants.DEFAULT_TENANT_ID)
.eq(SysConfig::getConfigType, "Y"));
//管理员新增成功,发送短信通知用户 for (SysConfig config : sysConfigList) {
LinkedHashMap<String, String> map = new LinkedHashMap<>(1); config.setConfigId(null);
map.put("company", tenantAdminBo.getNickName()); config.setTenantId(tenantId);
map.put("pwd", password); }
SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.ALIBABA); configMapper.insertBatch(sysConfigList);
SmsResponse smsResponse = smsBlend.sendMessage(tenantAdminBo.getPhonenumber(), "SMS_463175230", map);
if (!"OK".equals(smsResponse.getCode())) { //管理员新增成功,发送短信通知用户
log.error("新增租户通知短信发送异常 => {}", smsResponse); LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
} map.put("company", tenantAdminBo.getNickName());
return true; map.put("pwd", password);
} SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.ALIBABA);
SmsResponse smsResponse = smsBlend.sendMessage(tenantAdminBo.getPhonenumber(), "SMS_463175230", map);
/** if (!"OK".equals(smsResponse.getCode())) {
* 生成租户id log.error("新增租户通知短信发送异常 => {}", smsResponse);
* }
* @param tenantIds 已有租户id列表 return true;
* @return 租户id }
*/
private String generateTenantId(List<String> tenantIds) { /**
// 随机生成6位 * 生成租户id
String numbers = RandomUtil.randomNumbers(6); *
// 判断是否存在,如果存在则重新生成 * @param tenantIds 已有租户id列表
if (tenantIds.contains(numbers)) { * @return 租户id
generateTenantId(tenantIds); */
} private String generateTenantId(List<String> tenantIds) {
return numbers; // 随机生成6位
} String numbers = RandomUtil.randomNumbers(6);
// 判断是否存在,如果存在则重新生成
/** if (tenantIds.contains(numbers)) {
* 根据租户菜单创建租户角色 generateTenantId(tenantIds);
* }
* @param tenantId 租户编号 return numbers;
* @param packageId 租户套餐id }
* @return 角色id
*/ /**
private Long createTenantRole(String tenantId, Long packageId, String roleName, String roleKey) { * 根据租户菜单创建租户角色
// 获取租户套餐 *
SysTenantPackage tenantPackage = tenantPackageMapper.selectById(packageId); * @param tenantId 租户编号
if (ObjectUtil.isNull(tenantPackage)) { * @param packageId 租户套餐id
throw new ServiceException("套餐不存在"); * @return 角色id
} */
// 获取套餐菜单id private Long createTenantRole(String tenantId, Long packageId, String roleName, String roleKey) {
List<Long> menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong); // 获取租户套餐
SysTenantPackage tenantPackage = tenantPackageMapper.selectById(packageId);
// 创建角色 if (ObjectUtil.isNull(tenantPackage)) {
SysRole role = new SysRole(); throw new ServiceException("套餐不存在");
role.setTenantId(tenantId); }
role.setRoleName(roleName); // 获取套餐菜单id
role.setRoleKey(roleKey); List<Long> menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong);
role.setRoleSort(1);
role.setStatus(TenantConstants.NORMAL); // 创建角色
roleMapper.insert(role); SysRole role = new SysRole();
Long roleId = role.getRoleId(); role.setTenantId(tenantId);
role.setRoleName(roleName);
// 创建角色菜单 role.setRoleKey(roleKey);
List<SysRoleMenu> roleMenus = new ArrayList<>(menuIds.size()); role.setRoleSort(1);
menuIds.forEach(menuId -> { role.setStatus(TenantConstants.NORMAL);
SysRoleMenu roleMenu = new SysRoleMenu(); roleMapper.insert(role);
roleMenu.setRoleId(roleId); Long roleId = role.getRoleId();
roleMenu.setMenuId(menuId);
roleMenus.add(roleMenu); // 创建角色菜单
}); List<SysRoleMenu> roleMenus = new ArrayList<>(menuIds.size());
roleMenuMapper.insertBatch(roleMenus); menuIds.forEach(menuId -> {
SysRoleMenu roleMenu = new SysRoleMenu();
return roleId; roleMenu.setRoleId(roleId);
} roleMenu.setMenuId(menuId);
roleMenus.add(roleMenu);
/** });
* 校验租户是否允许操作 roleMenuMapper.insertBatch(roleMenus);
*
* @param tenantId 租户ID return roleId;
*/ }
@Override
public void checkTenantAllowed(String tenantId) { /**
if (ObjectUtil.isNotNull(tenantId) && TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) { * 校验租户是否允许操作
throw new ServiceException("不允许操作管理租户"); *
} * @param tenantId 租户ID
} */
@Override
/** public void checkTenantAllowed(String tenantId) {
* 修改租户 if (ObjectUtil.isNotNull(tenantId) && TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) {
*/ throw new ServiceException("不允许操作管理租户");
@Override }
@CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#bo.tenantId") }
public Boolean updateByBo(SysTenantBo bo) {
SysTenant tenant = BeanUtil.toBean(bo, SysTenant.class); /**
if (TenantConstants.DISABLE.equals(bo.getStatus())) { * 修改租户
tenant.setExpireTime(new DateTime()); */
} @Override
tenant.setTenantId(null); @CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#bo.tenantId")
return baseMapper.updateById(tenant) > 0; public Boolean updateByBo(SysTenantBo bo) {
} SysTenant tenant = BeanUtil.toBean(bo, SysTenant.class);
if (TenantConstants.DISABLE.equals(bo.getStatus())) {
// /** tenant.setExpireTime(new DateTime());
// * 修改租户状态 }
// * tenant.setTenantId(null);
// * @param bo 租户信息 return baseMapper.updateById(tenant) > 0;
// * @return 结果 }
// */
// @Override // /**
// @CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#bo.tenantId") // * 修改租户状态
// public int updateTenantStatus(SysTenantBo bo) { // *
// SysTenant tenant = MapStructUtils.convert(bo, SysTenant.class); // * @param bo 租户信息
// return baseMapper.updateById(tenant); // * @return 结果
// } // */
// @Override
/** // @CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#bo.tenantId")
* 校验并批量删除租户信息 // public int updateTenantStatus(SysTenantBo bo) {
*/ // SysTenant tenant = MapStructUtils.convert(bo, SysTenant.class);
@Override // return baseMapper.updateById(tenant);
@CacheEvict(cacheNames = CacheNames.SYS_TENANT, allEntries = true) // }
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) { /**
// 做一些业务上的校验,判断是否需要校验 * 校验并批量删除租户信息
if (ids.contains(TenantConstants.SUPER_ADMIN_ID)) { */
throw new ServiceException("超管租户不能删除"); @Override
} @CacheEvict(cacheNames = CacheNames.SYS_TENANT, allEntries = true)
} public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
return baseMapper.deleteBatchIds(ids) > 0; if (isValid) {
} // 做一些业务上的校验,判断是否需要校验
if (ids.contains(TenantConstants.SUPER_ADMIN_ID)) {
@Override throw new ServiceException("超管租户不能删除");
@Transactional(rollbackFor = Exception.class) }
public Boolean syncTenantPackage(String tenantId, Long packageId) { }
SysTenantPackage tenantPackage = tenantPackageMapper.selectById(packageId); return baseMapper.deleteBatchIds(ids) > 0;
List<SysRole> roles = roleMapper.selectList( }
new LambdaQueryWrapper<SysRole>().eq(SysRole::getTenantId, tenantId));
List<Long> roleIds = new ArrayList<>(roles.size() - 1); @Override
List<Long> menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong); @Transactional(rollbackFor = Exception.class)
roles.forEach(item -> { public Boolean syncTenantPackage(String tenantId, Long packageId) {
if (TenantConstants.TENANT_SUPER_ADMIN_ROLE_KEY.equals(item.getRoleKey())) { SysTenantPackage tenantPackage = tenantPackageMapper.selectById(packageId);
List<SysRoleMenu> roleMenus = new ArrayList<>(menuIds.size()); List<SysRole> roles = roleMapper.selectList(
menuIds.forEach(menuId -> { new LambdaQueryWrapper<SysRole>().eq(SysRole::getTenantId, tenantId));
SysRoleMenu roleMenu = new SysRoleMenu(); List<Long> roleIds = new ArrayList<>(roles.size() - 1);
roleMenu.setRoleId(item.getRoleId()); List<Long> menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong);
roleMenu.setMenuId(menuId); roles.forEach(item -> {
roleMenus.add(roleMenu); if (TenantConstants.TENANT_SUPER_ADMIN_ROLE_KEY.equals(item.getRoleKey())) {
}); List<SysRoleMenu> roleMenus = new ArrayList<>(menuIds.size());
roleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, item.getRoleId())); menuIds.forEach(menuId -> {
roleMenuMapper.insertBatch(roleMenus); SysRoleMenu roleMenu = new SysRoleMenu();
} else { roleMenu.setRoleId(item.getRoleId());
roleIds.add(item.getRoleId()); roleMenu.setMenuId(menuId);
} roleMenus.add(roleMenu);
}); });
if (!roleIds.isEmpty()) { roleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, item.getRoleId()));
roleMenuMapper.delete( roleMenuMapper.insertBatch(roleMenus);
new LambdaQueryWrapper<SysRoleMenu>().in(SysRoleMenu::getRoleId, roleIds).notIn(!menuIds.isEmpty(), SysRoleMenu::getMenuId, menuIds)); } else {
} roleIds.add(item.getRoleId());
try { }
//清除企业用户登录信息 });
List<SysUser> tenantUsers = userMapper.selectList(Wrappers.<SysUser>lambdaQuery() if (!roleIds.isEmpty()) {
.eq(SysUser::getTenantId, tenantId).eq(SysUser::getStatus, UserStatus.OK.getCode())); roleMenuMapper.delete(
if (!CollectionUtils.isEmpty(tenantUsers)) { new LambdaQueryWrapper<SysRoleMenu>().in(SysRoleMenu::getRoleId, roleIds).notIn(!menuIds.isEmpty(), SysRoleMenu::getMenuId, menuIds));
for (SysUser tenantUser : tenantUsers) { }
String key = "global:Authorization:login:session:00:" + tenantUser.getUserId(); try {
if (RedisUtils.hasKey(key)) { //清除企业用户登录信息
SaSession session = RedisUtils.getCacheObject(key); List<SysUser> tenantUsers = userMapper.selectList(Wrappers.<SysUser>lambdaQuery()
List<TokenSign> tokenSignList = session.getTokenSignList(); .eq(SysUser::getTenantId, tenantId).eq(SysUser::getStatus, UserStatus.OK.getCode()));
tokenSignList.forEach(sign -> StpUtil.kickoutByTokenValue(sign.getValue())); if (!CollectionUtils.isEmpty(tenantUsers)) {
} for (SysUser tenantUser : tenantUsers) {
} String key = "global:Authorization:login:session:00:" + tenantUser.getUserId();
} if (RedisUtils.hasKey(key)) {
} catch (Exception e) { SaSession session = RedisUtils.getCacheObject(key);
log.error("清除企业用户登录信息操作失败!error={}", e.getMessage()); List<TokenSign> tokenSignList = session.getTokenSignList();
} tokenSignList.forEach(sign -> StpUtil.kickoutByTokenValue(sign.getValue()));
}
return true; }
} }
} catch (Exception e) {
log.error("清除企业用户登录信息操作失败!error={}", e.getMessage());
} }
return true;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment