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