From 32976708e984d62df593e5025fc9049febe9cbe2 Mon Sep 17 00:00:00 2001
From: xieb <vip_xiaobin810@163.com>
Date: Tue, 12 Dec 2023 15:15:22 +0800
Subject: [PATCH] 手机验证码登录
---
src/main/java/org/springblade/modules/auth/endpoint/BladeTokenEndPoint.java | 12 +++
src/main/java/org/springblade/modules/system/service/impl/UserServiceImpl.java | 11 +++
src/main/java/org/springblade/modules/auth/granter/SmsCodeTokenGranter.java | 111 +++++++++++++++++++++++++++++++++++++
src/main/java/org/springblade/modules/auth/provider/TokenGranterBuilder.java | 6 -
src/main/java/org/springblade/modules/system/service/IUserService.java | 4 +
5 files changed, 138 insertions(+), 6 deletions(-)
diff --git a/src/main/java/org/springblade/modules/auth/endpoint/BladeTokenEndPoint.java b/src/main/java/org/springblade/modules/auth/endpoint/BladeTokenEndPoint.java
index 99eea8f..21075c4 100644
--- a/src/main/java/org/springblade/modules/auth/endpoint/BladeTokenEndPoint.java
+++ b/src/main/java/org/springblade/modules/auth/endpoint/BladeTokenEndPoint.java
@@ -38,6 +38,7 @@
import org.springblade.core.tool.utils.RandomType;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.core.tool.utils.WebUtil;
+import org.springblade.modules.auth.granter.SmsCodeTokenGranter;
import org.springblade.modules.auth.provider.ITokenGranter;
import org.springblade.modules.auth.provider.TokenGranterBuilder;
import org.springblade.modules.auth.provider.TokenParameter;
@@ -75,6 +76,8 @@
public Kv token(@ApiParam(value = "租户ID", required = true) @RequestParam String tenantId,
@ApiParam(value = "账号", required = true) @RequestParam(required = false) String username,
@ApiParam(value = "密码", required = true) @RequestParam(required = false) String password,
+ @ApiParam(value = "手机号", required = true) @RequestParam(required = false) String phone,
+ @ApiParam(value = "手机验证码", required = true) @RequestParam(required = false) String code,
@ApiIgnore @RequestHeader(name = TokenUtil.DEPT_HEADER_KEY, required = false) String deptId,
@ApiIgnore @RequestHeader(name = TokenUtil.ROLE_HEADER_KEY, required = false) String roleId) {
@@ -92,13 +95,18 @@
.set("grantType", grantType)
.set("refreshToken", refreshToken)
.set("userType", userType)
- .set("deptId", deptId).set("roleId", roleId);
+ .set("deptId", deptId).set("roleId", roleId)
+ .set("phone", phone)
+ .set("code", code);
ITokenGranter granter = TokenGranterBuilder.getGranter(grantType);
UserInfo userInfo = granter.grant(tokenParameter);
if (userInfo == null || userInfo.getUser() == null) {
- return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_description", "用户名或密码不正确");
+ if (grantType.equals(SmsCodeTokenGranter.GRANT_TYPE))
+ return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_description", "手机号码未绑定账号");
+ else
+ return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_description", "用户名或密码不正确");
}
if (Func.isEmpty(userInfo.getRoles())) {
diff --git a/src/main/java/org/springblade/modules/auth/granter/SmsCodeTokenGranter.java b/src/main/java/org/springblade/modules/auth/granter/SmsCodeTokenGranter.java
new file mode 100644
index 0000000..83a2b41
--- /dev/null
+++ b/src/main/java/org/springblade/modules/auth/granter/SmsCodeTokenGranter.java
@@ -0,0 +1,111 @@
+package org.springblade.modules.auth.granter;
+
+import lombok.AllArgsConstructor;
+import org.springblade.common.cache.CacheNames;
+import org.springblade.common.cache.ParamCache;
+import org.springblade.core.log.exception.ServiceException;
+import org.springblade.core.redis.cache.BladeRedis;
+import org.springblade.core.tool.utils.DigestUtil;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.WebUtil;
+import org.springblade.modules.auth.enums.UserEnum;
+import org.springblade.modules.auth.provider.ITokenGranter;
+import org.springblade.modules.auth.provider.TokenParameter;
+import org.springblade.modules.auth.sms.MobTechSmsVerify;
+import org.springblade.modules.auth.utils.TokenUtil;
+import org.springblade.modules.system.entity.Tenant;
+import org.springblade.modules.system.entity.UserInfo;
+import org.springblade.modules.system.service.IRoleService;
+import org.springblade.modules.system.service.ITenantService;
+import org.springblade.modules.system.service.IUserService;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import java.time.Duration;
+import java.util.List;
+
+/**
+ * @PROJECT_NAME: zttj-java-boot
+ * @DESCRIPTION: 短信验证码鉴权
+ * @USER: aix
+ * @DATE: 2023/12/12 14:25
+ */
+@Component
+@AllArgsConstructor
+public class SmsCodeTokenGranter implements ITokenGranter {
+
+ public static final String GRANT_TYPE = "smsCode";
+ public static final Integer FAIL_COUNT = 5;
+ public static final String FAIL_COUNT_VALUE = "account.failCount";
+ private final IUserService userService;
+ private final IRoleService roleService;
+ private final ITenantService tenantService;
+ private final BladeRedis bladeRedis;
+
+
+ @Override
+ public UserInfo grant(TokenParameter tokenParameter) {
+ HttpServletRequest request = WebUtil.getRequest();
+ // 获取用户绑定ID
+ String headerDept = request.getHeader(TokenUtil.DEPT_HEADER_KEY);
+ String headerRole = request.getHeader(TokenUtil.ROLE_HEADER_KEY);
+
+ // 获取用户信息
+ String tenantId = tokenParameter.getArgs().getStr("tenantId");
+ String phone = tokenParameter.getArgs().getStr("phone");
+ String code = tokenParameter.getArgs().getStr("code");
+
+ //短信验证api
+ String verifyStr = MobTechSmsVerify.requestData(phone, code);
+ if (verifyStr.indexOf("200") < 0) {
+ throw new ServiceException(TokenUtil.CAPTCHA_NOT_CORRECT);
+ }
+
+ // 判断登录是否锁定
+ int cnt = Func.toInt(bladeRedis.get(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, phone)), 0);
+ int failCount = Func.toInt(ParamCache.getValue(FAIL_COUNT_VALUE), FAIL_COUNT);
+ if (cnt >= failCount) {
+ throw new ServiceException(TokenUtil.USER_HAS_TOO_MANY_FAILS);
+ }
+
+ UserInfo userInfo = null;
+ if (Func.isNoneBlank(phone, code)) {
+ // 获取租户信息
+ Tenant tenant = tenantService.getByTenantId(tenantId);
+ if (TokenUtil.judgeTenant(tenant)) {
+ throw new ServiceException(TokenUtil.USER_HAS_NO_TENANT_PERMISSION);
+ }
+ // 获取用户类型
+ String userType = tokenParameter.getArgs().getStr("userType");
+ // 根据不同用户类型调用对应的接口返回数据,用户可自行拓展
+ if (userType.equals(UserEnum.WEB.getName())) {
+ userInfo = userService.userInfo(tenantId, phone);
+ } else if (userType.equals(UserEnum.APP.getName())) {
+ userInfo = userService.userInfo(tenantId, phone);
+ } else {
+ userInfo = userService.userInfo(tenantId, phone);
+ }
+ }
+
+ if (userInfo == null || userInfo.getUser() == null) {
+ // 增加错误锁定次数
+ bladeRedis.setEx(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, phone), cnt + 1, Duration.ofMinutes(30));
+ } else {
+ // 成功则清除登录缓存
+ bladeRedis.del(CacheNames.tenantKey(tenantId, CacheNames.USER_FAIL_KEY, phone));
+ }
+ // 多部门情况下指定单部门
+ if (Func.isNotEmpty(headerDept) && userInfo != null && userInfo.getUser().getDeptId().contains(headerDept)) {
+ userInfo.getUser().setDeptId(headerDept);
+ }
+ // 多角色情况下指定单角色
+ if (Func.isNotEmpty(headerRole) && userInfo != null && userInfo.getUser().getRoleId().contains(headerRole)) {
+ List<String> roleResult = roleService.getRoleAliases(headerRole);
+ userInfo.setRoles(roleResult);
+ userInfo.getUser().setRoleId(headerRole);
+ }
+
+ return userInfo;
+
+ }
+}
diff --git a/src/main/java/org/springblade/modules/auth/provider/TokenGranterBuilder.java b/src/main/java/org/springblade/modules/auth/provider/TokenGranterBuilder.java
index 7e6177c..ac35501 100644
--- a/src/main/java/org/springblade/modules/auth/provider/TokenGranterBuilder.java
+++ b/src/main/java/org/springblade/modules/auth/provider/TokenGranterBuilder.java
@@ -20,10 +20,7 @@
import org.springblade.core.secure.exception.SecureException;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.SpringUtil;
-import org.springblade.modules.auth.granter.CaptchaTokenGranter;
-import org.springblade.modules.auth.granter.PasswordTokenGranter;
-import org.springblade.modules.auth.granter.RefreshTokenGranter;
-import org.springblade.modules.auth.granter.SocialTokenGranter;
+import org.springblade.modules.auth.granter.*;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -46,6 +43,7 @@
GRANTER_POOL.put(CaptchaTokenGranter.GRANT_TYPE, SpringUtil.getBean(CaptchaTokenGranter.class));
GRANTER_POOL.put(RefreshTokenGranter.GRANT_TYPE, SpringUtil.getBean(RefreshTokenGranter.class));
GRANTER_POOL.put(SocialTokenGranter.GRANT_TYPE, SpringUtil.getBean(SocialTokenGranter.class));
+ GRANTER_POOL.put(SmsCodeTokenGranter.GRANT_TYPE, SpringUtil.getBean(SmsCodeTokenGranter.class));
}
/**
diff --git a/src/main/java/org/springblade/modules/system/service/IUserService.java b/src/main/java/org/springblade/modules/system/service/IUserService.java
index 932d0a5..3718a2b 100644
--- a/src/main/java/org/springblade/modules/system/service/IUserService.java
+++ b/src/main/java/org/springblade/modules/system/service/IUserService.java
@@ -90,6 +90,8 @@
*/
User userByAccount(String tenantId, String account);
+ User userByPhone(String tenantId, String phone);
+
/**
* 用户信息
*
@@ -98,6 +100,8 @@
*/
UserInfo userInfo(Long userId);
+ UserInfo userInfo(String tenantId, String phone);
+
/**
* 用户信息
*
diff --git a/src/main/java/org/springblade/modules/system/service/impl/UserServiceImpl.java b/src/main/java/org/springblade/modules/system/service/impl/UserServiceImpl.java
index 6dc569d..4c07c77 100644
--- a/src/main/java/org/springblade/modules/system/service/impl/UserServiceImpl.java
+++ b/src/main/java/org/springblade/modules/system/service/impl/UserServiceImpl.java
@@ -183,12 +183,23 @@
}
@Override
+ public User userByPhone(String tenantId, String phone) {
+ return baseMapper.selectOne(Wrappers.<User>query().lambda().eq(User::getTenantId, tenantId).eq(User::getPhone, phone).eq(User::getIsDeleted, BladeConstant.DB_NOT_DELETED));
+ }
+
+ @Override
public UserInfo userInfo(Long userId) {
User user = baseMapper.selectById(userId);
return buildUserInfo(user);
}
@Override
+ public UserInfo userInfo(String tenantId, String phone) {
+ User user = userByPhone(tenantId, phone);
+ return buildUserInfo(user);
+ }
+
+ @Override
public UserInfo userInfo(String tenantId, String account, String password) {
User user = baseMapper.getUser(tenantId, account, password);
return buildUserInfo(user);
--
Gitblit v1.9.3