xieb
2023-12-12 32976708e984d62df593e5025fc9049febe9cbe2
手机验证码登录
4 files modified
1 files added
144 ■■■■■ changed files
src/main/java/org/springblade/modules/auth/endpoint/BladeTokenEndPoint.java 12 ●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/auth/granter/SmsCodeTokenGranter.java 111 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/auth/provider/TokenGranterBuilder.java 6 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/service/IUserService.java 4 ●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/service/impl/UserServiceImpl.java 11 ●●●●● patch | view | raw | blame | history
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())) {
src/main/java/org/springblade/modules/auth/granter/SmsCodeTokenGranter.java
New file
@@ -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;
    }
}
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));
    }
    /**
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);
    /**
     * 用户信息
     *
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);