udp 使用工厂模式优化登录接口

This commit is contained in:
山寒 2026-03-12 17:23:09 +08:00
parent 2d7195c61d
commit f09f2d8095
11 changed files with 203 additions and 153 deletions

View File

@ -18,6 +18,7 @@ import org.dromara.common.core.domain.R;
import org.dromara.common.core.domain.model.LoginBody;
import org.dromara.common.core.domain.model.RegisterBody;
import org.dromara.common.core.domain.model.SocialLoginBody;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.*;
import org.dromara.common.encrypt.annotation.ApiEncrypt;
import org.dromara.common.json.utils.JsonUtils;
@ -40,9 +41,10 @@ import org.dromara.system.service.ISysTenantService;
import org.dromara.web.domain.vo.LoginTenantVo;
import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.domain.vo.TenantListVo;
import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.strategy.IAuthStrategy;
import org.dromara.web.service.SysLoginService;
import org.dromara.web.service.SysRegisterService;
import org.dromara.web.strategy.AuthFactory;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@ -75,7 +77,7 @@ public class AuthController {
private final ISysSocialService socialUserService;
private final ISysClientService clientService;
private final ScheduledExecutorService scheduledExecutorService;
private final AuthFactory authFactory;
/**
* 登录方法
@ -101,8 +103,13 @@ public class AuthController {
}
// 校验租户
loginService.checkTenant(loginBody.getTenantId());
IAuthStrategy authStrategy = authFactory.getLoginStrategy(grantType);
if (authStrategy == null) {
throw new ServiceException("授权类型不正确!");
}
// 登录
LoginVo loginVo = IAuthStrategy.login(body, client, grantType);
LoginVo loginVo = authStrategy.login(body, client);
Long userId = LoginHelper.getUserId();
scheduledExecutorService.schedule(() -> {

View File

@ -1,46 +0,0 @@
package org.dromara.web.service;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.system.domain.SysClient;
import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.web.domain.vo.LoginVo;
/**
* 授权策略
*
* @author Michelle.Chung
*/
public interface IAuthStrategy {
String BASE_NAME = "AuthStrategy";
/**
* 登录
*
* @param body 登录对象
* @param client 授权管理视图对象
* @param grantType 授权类型
* @return 登录验证信息
*/
static LoginVo login(String body, SysClientVo client, String grantType) {
// 授权类型和客户端id
String beanName = grantType + BASE_NAME;
if (!SpringUtils.containsBean(beanName)) {
throw new ServiceException("授权类型不正确!");
}
IAuthStrategy instance = SpringUtils.getBean(beanName);
return instance.login(body, client);
}
/**
* 登录
*
* @param body 登录对象
* @param client 授权管理视图对象
* @return 登录验证信息
*/
LoginVo login(String body, SysClientVo client);
}

View File

@ -0,0 +1,37 @@
package org.dromara.web.strategy;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.web.domain.vo.LoginVo;
/**
* 登录策略抽象类
*
* @author shanhan
*/
public abstract class AbstractAuthStrategy implements IAuthStrategy {
public LoginVo loginClient(SysClientVo client, LoginUser loginUser) {
loginUser.setClientKey(client.getClientKey());
loginUser.setDeviceType(client.getDeviceType());
SaLoginParameter model = new SaLoginParameter();
model.setDeviceType(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;
}
}

View File

@ -0,0 +1,44 @@
package org.dromara.web.strategy;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @description: 登录策略工厂类(工厂模式)
* @author shanhan
*/
@Component
public class AuthFactory {
@Resource
private List<IAuthStrategy> authStrategyList = new ArrayList<>();
private final Map<String, IAuthStrategy> authStrategyMap = new HashMap<>();
@PostConstruct
public void init() {
for (IAuthStrategy authStrategy : authStrategyList) {
String loginType = authStrategy.loginType().getCode();
authStrategyMap.put(loginType, authStrategy);
}
}
/**
* 根据登录类型获取实例
*
* @author shuai.zhou
* @date: 2023/11/17 10:53
* @param: loginType
* @return: org.dromara.auth.strategy.IAuthStrategy
*/
public IAuthStrategy getLoginStrategy(String loginType) {
return authStrategyMap.get(loginType);
}
}

View File

@ -0,0 +1,35 @@
package org.dromara.web.strategy;
import org.dromara.common.core.enums.LoginType;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.web.domain.vo.LoginVo;
/**
* 授权策略
*
* @author Michelle.Chung
*/
public interface IAuthStrategy {
String BASE_NAME = "AuthStrategy";
/**
* 登录
*
* @param body 登录对象
* @param client 授权管理视图对象
* @return 登录验证信息
*/
LoginVo login(String body, SysClientVo client);
/**
* 登录类型
*
* @return 登录类型
*/
LoginType loginType();
}

View File

@ -1,7 +1,5 @@
package org.dromara.web.service.impl;
package org.dromara.web.strategy.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
@ -19,26 +17,27 @@ 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.common.tenant.helper.TenantHelper;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService;
import org.dromara.web.strategy.AbstractAuthStrategy;
import org.springframework.stereotype.Service;
import static org.dromara.common.core.enums.LoginType.EMAIL;
/**
* 邮件认证策略
*
* @author Michelle.Chung
*/
@Slf4j
@Service("email" + IAuthStrategy.BASE_NAME)
@Service("emailAuthStrategy")
@RequiredArgsConstructor
public class EmailAuthStrategy implements IAuthStrategy {
public class EmailAuthStrategy extends AbstractAuthStrategy {
private final SysLoginService loginService;
private final SysUserMapper userMapper;
@ -56,23 +55,12 @@ public class EmailAuthStrategy implements IAuthStrategy {
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
return loginService.buildLoginUser(user);
});
loginUser.setClientKey(client.getClientKey());
loginUser.setDeviceType(client.getDeviceType());
SaLoginParameter model = new SaLoginParameter();
model.setDeviceType(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);
return loginClient(client, loginUser);
}
LoginVo loginVo = new LoginVo();
loginVo.setAccessToken(StpUtil.getTokenValue());
loginVo.setExpireIn(StpUtil.getTokenTimeout());
loginVo.setClientId(client.getClientId());
return loginVo;
@Override
public LoginType loginType() {
return EMAIL;
}
/**

View File

@ -1,7 +1,5 @@
package org.dromara.web.service.impl;
package org.dromara.web.strategy.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@ -21,7 +19,6 @@ 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.common.tenant.helper.TenantHelper;
import org.dromara.common.web.config.properties.CaptchaProperties;
import org.dromara.system.domain.SysUser;
@ -29,19 +26,21 @@ import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService;
import org.dromara.web.strategy.AbstractAuthStrategy;
import org.springframework.stereotype.Service;
import static org.dromara.common.core.enums.LoginType.PASSWORD;
/**
* 密码认证策略
*
* @author Michelle.Chung
*/
@Slf4j
@Service("password" + IAuthStrategy.BASE_NAME)
@Service("passwordAuthStrategy")
@RequiredArgsConstructor
public class PasswordAuthStrategy implements IAuthStrategy {
public class PasswordAuthStrategy extends AbstractAuthStrategy {
private final CaptchaProperties captchaProperties;
private final SysLoginService loginService;
@ -68,23 +67,12 @@ public class PasswordAuthStrategy implements IAuthStrategy {
// 此处可根据登录用户的数据不同 自行创建 loginUser
return loginService.buildLoginUser(user);
});
loginUser.setClientKey(client.getClientKey());
loginUser.setDeviceType(client.getDeviceType());
SaLoginParameter model = new SaLoginParameter();
model.setDeviceType(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);
return loginClient(client, loginUser);
}
LoginVo loginVo = new LoginVo();
loginVo.setAccessToken(StpUtil.getTokenValue());
loginVo.setExpireIn(StpUtil.getTokenTimeout());
loginVo.setClientId(client.getClientId());
return loginVo;
@Override
public LoginType loginType() {
return PASSWORD;
}
/**

View File

@ -1,7 +1,5 @@
package org.dromara.web.service.impl;
package org.dromara.web.strategy.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
@ -19,30 +17,32 @@ 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.common.tenant.helper.TenantHelper;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService;
import org.dromara.web.strategy.AbstractAuthStrategy;
import org.springframework.stereotype.Service;
import static org.dromara.common.core.enums.LoginType.SMS;
/**
* 短信认证策略
*
* @author Michelle.Chung
*/
@Slf4j
@Service("sms" + IAuthStrategy.BASE_NAME)
@Service("smsAuthStrategy")
@RequiredArgsConstructor
public class SmsAuthStrategy implements IAuthStrategy {
public class SmsAuthStrategy extends AbstractAuthStrategy {
private final SysLoginService loginService;
private final SysUserMapper userMapper;
@Override
public LoginVo login(String body, SysClientVo client) {
SmsLoginBody loginBody = JsonUtils.parseObject(body, SmsLoginBody.class);
@ -56,23 +56,12 @@ public class SmsAuthStrategy implements IAuthStrategy {
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
return loginService.buildLoginUser(user);
});
loginUser.setClientKey(client.getClientKey());
loginUser.setDeviceType(client.getDeviceType());
SaLoginParameter model = new SaLoginParameter();
model.setDeviceType(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);
return loginClient(client, loginUser);
}
LoginVo loginVo = new LoginVo();
loginVo.setAccessToken(StpUtil.getTokenValue());
loginVo.setExpireIn(StpUtil.getTokenTimeout());
loginVo.setClientId(client.getClientId());
return loginVo;
@Override
public LoginType loginType() {
return SMS;
}
/**

View File

@ -1,7 +1,5 @@
package org.dromara.web.service.impl;
package org.dromara.web.strategy.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
@ -11,12 +9,12 @@ import me.zhyd.oauth.model.AuthUser;
import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.domain.model.SocialLoginBody;
import org.dromara.common.core.enums.LoginType;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.exception.user.UserException;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.social.config.properties.SocialProperties;
import org.dromara.common.social.utils.SocialUtils;
import org.dromara.common.tenant.helper.TenantHelper;
@ -26,22 +24,25 @@ import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.system.service.ISysSocialService;
import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService;
import org.dromara.web.strategy.AbstractAuthStrategy;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
import static org.dromara.common.core.enums.LoginType.SOCIAL;
/**
* 第三方授权策略
*
* @author thiszhc is 三三
*/
@Slf4j
@Service("social" + IAuthStrategy.BASE_NAME)
@Service("socialAuthStrategy")
@RequiredArgsConstructor
public class SocialAuthStrategy implements IAuthStrategy {
public class SocialAuthStrategy extends AbstractAuthStrategy {
private final SocialProperties socialProperties;
private final ISysSocialService sysSocialService;
@ -51,16 +52,16 @@ public class SocialAuthStrategy implements IAuthStrategy {
/**
* 登录-第三方授权登录
*
* @param body 登录信息
* @param client 客户端信息
* @param body 登录信息
* @param client 客户端信息
*/
@Override
public LoginVo login(String body, SysClientVo client) {
SocialLoginBody loginBody = JsonUtils.parseObject(body, SocialLoginBody.class);
ValidatorUtils.validate(loginBody);
AuthResponse<AuthUser> response = SocialUtils.loginAuth(
loginBody.getSource(), loginBody.getSocialCode(),
loginBody.getSocialState(), socialProperties);
loginBody.getSource(), loginBody.getSocialCode(),
loginBody.getSocialState(), socialProperties);
if (!response.ok()) {
throw new ServiceException(response.getMsg());
}
@ -85,23 +86,12 @@ public class SocialAuthStrategy implements IAuthStrategy {
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
return loginService.buildLoginUser(user);
});
loginUser.setClientKey(client.getClientKey());
loginUser.setDeviceType(client.getDeviceType());
SaLoginParameter model = new SaLoginParameter();
model.setDeviceType(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);
return loginClient(client, loginUser);
}
LoginVo loginVo = new LoginVo();
loginVo.setAccessToken(StpUtil.getTokenValue());
loginVo.setExpireIn(StpUtil.getTokenTimeout());
loginVo.setClientId(client.getClientId());
return loginVo;
@Override
public LoginType loginType() {
return SOCIAL;
}
private SysUserVo loadUser(Long userId) {

View File

@ -1,4 +1,4 @@
package org.dromara.web.service.impl;
package org.dromara.web.strategy.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
@ -15,6 +15,7 @@ import me.zhyd.oauth.request.AuthWechatMiniProgramRequest;
import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.domain.model.XcxLoginBody;
import org.dromara.common.core.domain.model.XcxLoginUser;
import org.dromara.common.core.enums.LoginType;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils;
@ -22,19 +23,21 @@ import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService;
import org.dromara.web.strategy.AbstractAuthStrategy;
import org.springframework.stereotype.Service;
import static org.dromara.common.core.enums.LoginType.XCX;
/**
* 小程序认证策略
*
* @author Michelle.Chung
*/
@Slf4j
@Service("xcx" + IAuthStrategy.BASE_NAME)
@Service("xcxAuthStrategy")
@RequiredArgsConstructor
public class XcxAuthStrategy implements IAuthStrategy {
public class XcxAuthStrategy extends AbstractAuthStrategy {
private final SysLoginService loginService;
@ -94,6 +97,11 @@ public class XcxAuthStrategy implements IAuthStrategy {
return loginVo;
}
@Override
public LoginType loginType() {
return XCX;
}
private SysUserVo loadUserByOpenid(String openid) {
// 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户
// todo 自行实现 userService.selectUserByOpenid(openid);

View File

@ -15,22 +15,32 @@ public enum LoginType {
/**
* 密码登录
*/
PASSWORD("user.password.retry.limit.exceed", "user.password.retry.limit.count"),
PASSWORD("password", "user.password.retry.limit.exceed", "user.password.retry.limit.count"),
/**
* 短信登录
*/
SMS("sms.code.retry.limit.exceed", "sms.code.retry.limit.count"),
SMS("sms", "sms.code.retry.limit.exceed", "sms.code.retry.limit.count"),
/**
* 邮箱登录
*/
EMAIL("email.code.retry.limit.exceed", "email.code.retry.limit.count"),
EMAIL("email", "email.code.retry.limit.exceed", "email.code.retry.limit.count"),
/**
* 第三方登录
*/
SOCIAL("social", "", ""),
/**
* 小程序登录
*/
XCX("", "");
XCX("xcx", "", "");
/**
* 登录策略编码
*/
final String code;
/**
* 登录重试超出限制提示