package org.dromara.auth.service.impl; import cn.dev33.satoken.secure.BCrypt; import cn.dev33.satoken.stp.SaLoginModel; import cn.dev33.satoken.stp.StpUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.dubbo.config.annotation.DubboReference; import org.dromara.auth.domain.vo.LoginVo; import org.dromara.auth.form.PasswordLoginBody; import org.dromara.auth.properties.CaptchaProperties; import org.dromara.auth.service.IAuthStrategy; import org.dromara.auth.service.SysLoginService; import org.dromara.common.core.constant.Constants; import org.dromara.common.core.constant.GlobalConstants; import org.dromara.common.core.enums.LoginType; import org.dromara.common.core.exception.user.CaptchaException; import org.dromara.common.core.exception.user.CaptchaExpireException; import org.dromara.common.core.utils.MessageUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.ValidatorUtils; import org.dromara.common.json.utils.JsonUtils; import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.system.api.RemoteUserService; import org.dromara.system.api.domain.vo.RemoteClientVo; import org.dromara.system.api.model.LoginUser; import org.springframework.stereotype.Service; /** * 密码认证策略 * * @author Michelle.Chung */ @Slf4j @Service("password" + IAuthStrategy.BASE_NAME) @RequiredArgsConstructor public class PasswordAuthStrategy implements IAuthStrategy { private final CaptchaProperties captchaProperties; private final SysLoginService loginService; @DubboReference private RemoteUserService remoteUserService; @Override public LoginVo login(String body, RemoteClientVo client) { PasswordLoginBody loginBody = JsonUtils.parseObject(body, PasswordLoginBody.class); ValidatorUtils.validate(loginBody); String tenantId = loginBody.getTenantId(); String username = loginBody.getUsername(); String password = loginBody.getPassword(); String code = loginBody.getCode(); String uuid = loginBody.getUuid(); // 验证码开关 if (captchaProperties.getEnabled()) { validateCaptcha(tenantId, username, code, uuid); } LoginUser loginUser = remoteUserService.getUserInfo(username, tenantId); loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, loginUser.getPassword())); loginUser.setClientKey(client.getClientKey()); loginUser.setDeviceType(client.getDeviceType()); SaLoginModel model = new SaLoginModel(); model.setDevice(client.getDeviceType()); // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 // 例如: 后台用户30分钟过期 app用户1天过期 model.setTimeout(client.getTimeout()); model.setActiveTimeout(client.getActiveTimeout()); model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); // 生成token LoginHelper.login(loginUser, model); LoginVo loginVo = new LoginVo(); loginVo.setAccessToken(StpUtil.getTokenValue()); loginVo.setExpireIn(StpUtil.getTokenTimeout()); loginVo.setClientId(client.getClientId()); return loginVo; } /** * 校验验证码 * * @param username 用户名 * @param code 验证码 * @param uuid 唯一标识 */ private void validateCaptcha(String tenantId, 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) { loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); throw new CaptchaExpireException(); } if (!code.equalsIgnoreCase(captcha)) { loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")); throw new CaptchaException(); } } }