diff --git a/pom.xml b/pom.xml index 6b4ce3d..d2d6c9f 100644 --- a/pom.xml +++ b/pom.xml @@ -56,6 +56,8 @@ 3.1.1 3.0.2 + + 1.16.6 3.2.2 @@ -343,6 +345,13 @@ jsr305 ${jsr305.version} + + + + me.zhyd.oauth + JustAuth + ${justauth.version} + diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml index 36079d1..50dd58b 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -31,6 +31,12 @@ mysql-connector-j + + + com.ruoyi + ruoyi-common-social + + org.postgresql diff --git a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java b/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java index 6c3b286..5bb5581 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java @@ -15,7 +15,7 @@ public class RuoYiApplication public static void main(String[] args) { SpringApplication.run(RuoYiApplication.class, args); - System.out.println("(♥◠‿◠)ノ゙ RuoYi-Flex启动成功 ლ(´ڡ`ლ)゙ \n" + + System.out.println("(♥◠‿◠)ノ゙ RuoYi-Flex-Boot启动成功 ლ(´ڡ`ლ)゙ \n" + " ███████ ██ ██ ██ ████████ ██ \n" + "░██░░░░██ ░░██ ██ ░░ ░██░░░░░ ░██ \n" + "░██ ░██ ██ ██ ██████ ░░████ ██ ░██ ░██ █████ ██ ██\n" + diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/AuthController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/AuthController.java index 4ca7575..6872415 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/AuthController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/AuthController.java @@ -7,18 +7,25 @@ import com.mybatisflex.core.query.QueryWrapper; import com.ruoyi.common.core.constant.UserConstants; import com.ruoyi.common.core.core.domain.AjaxResult; import com.ruoyi.common.core.core.domain.model.LoginUser; +import com.ruoyi.common.core.core.domain.model.SocialLoginBody; import com.ruoyi.common.core.utils.*; import com.ruoyi.common.encrypt.annotation.ApiEncrypt; import com.ruoyi.common.json.utils.JsonUtils; import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.common.social.config.properties.SocialLoginConfigProperties; +import com.ruoyi.common.social.config.properties.SocialProperties; +import com.ruoyi.common.social.utils.SocialUtils; import com.ruoyi.common.tenant.helper.TenantHelper; +import com.ruoyi.common.websocket.utils.WebSocketUtils; import com.ruoyi.system.domain.bo.SysTenantBo; +import com.ruoyi.system.domain.vo.SysClientVo; import com.ruoyi.system.domain.vo.SysTenantVo; import com.ruoyi.system.domain.vo.SysUserVo; import com.ruoyi.system.service.*; import com.ruoyi.web.domain.vo.LoginTenantVo; import com.ruoyi.web.domain.vo.LoginVo; import com.ruoyi.web.domain.vo.TenantListVo; +import com.ruoyi.web.service.SysRegisterService; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; @@ -29,12 +36,17 @@ import com.ruoyi.common.core.core.domain.model.RegisterBody; import com.ruoyi.system.domain.SysClient; import com.ruoyi.web.service.IAuthStrategy; import com.ruoyi.web.service.SysLoginService; +import me.zhyd.oauth.model.AuthResponse; +import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.request.AuthRequest; +import me.zhyd.oauth.utils.AuthStateUtils; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.net.URL; import java.util.List; -import java.util.Set; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import static com.ruoyi.system.domain.table.SysClientTableDef.SYS_CLIENT; @@ -46,7 +58,6 @@ import static com.ruoyi.system.domain.table.SysClientTableDef.SYS_CLIENT; */ @Slf4j @SaIgnore -@Validated @RequiredArgsConstructor @RestController @RequestMapping("/auth") @@ -57,7 +68,16 @@ public class AuthController { @Resource private ISysClientService clientService; @Resource + private SysRegisterService registerService; + @Resource + private ISysConfigService configService; + @Resource private ISysTenantService tenantService; + @Resource + private ISysSocialService socialService; + + private final ScheduledExecutorService scheduledExecutorService; + private final SocialProperties socialProperties; /** * 登录方法 @@ -74,7 +94,7 @@ public class AuthController { String clientId = loginBody.getClientId(); String grantType = loginBody.getGrantType(); QueryWrapper query=QueryWrapper.create().from(SYS_CLIENT).where(SYS_CLIENT.CLIENT_ID.eq(clientId)); - SysClient client = clientService.getOne(query); + SysClientVo client = clientService.getOneAs(query,SysClientVo.class); // 查询不到 client 或 client 内不包含 grantType if (ObjectUtil.isNull(client) || !StringUtils.contains(client.getGrantType(), grantType)) { log.info("客户端id: {} 认证类型:{} 异常!.", clientId, grantType); @@ -86,7 +106,64 @@ public class AuthController { loginService.checkTenant(loginBody.getTenantId()); // 登录 - return R.ok(IAuthStrategy.login(body, client, grantType)); + LoginVo loginVo =IAuthStrategy.login(body, client, grantType); + + Long userId = LoginHelper.getUserId(); + scheduledExecutorService.schedule(() -> { + WebSocketUtils.sendMessage(userId, "欢迎登录RuoYi-Flex多租户管理系统"); + }, 3, TimeUnit.SECONDS); + + return R.ok(loginVo); + } + + /** + * 第三方登录请求 + * + * @param source 登录来源 + * @return 结果 + */ + @GetMapping("/binding/{source}") + public R authBinding(@PathVariable("source") String source) { + SocialLoginConfigProperties obj = socialProperties.getType().get(source); + if (ObjectUtil.isNull(obj)) { + return R.fail(source + "平台账号暂不支持"); + } + AuthRequest authRequest = SocialUtils.getAuthRequest(source, socialProperties); + String authorizeUrl = authRequest.authorize(AuthStateUtils.createState()); + return R.ok("操作成功", authorizeUrl); + } + + /** + * 第三方登录回调业务处理 绑定授权 + * + * @param loginBody 请求体 + * @return 结果 + */ + @PostMapping("/social/callback") + public R socialCallback(@RequestBody SocialLoginBody loginBody) { + // 获取第三方登录信息 + AuthResponse response = SocialUtils.loginAuth( + loginBody.getSource(), loginBody.getSocialCode(), + loginBody.getSocialState(), socialProperties); + AuthUser authUserData = response.getData(); + // 判断授权响应是否成功 + if (!response.ok()) { + return R.fail(response.getMsg()); + } + loginService.socialRegister(authUserData); + return R.ok(); + } + + + /** + * 取消授权 + * + * @param socialId socialId + */ + @DeleteMapping(value = "/unlock/{socialId}") + public R unlockSocial(@PathVariable Long socialId) { + Boolean rows = socialService.deleteWithValidById(socialId); + return rows ? R.ok() : R.fail("取消授权失败"); } /** @@ -103,12 +180,12 @@ public class AuthController { */ @PostMapping("/register") public R register(@Validated @RequestBody RegisterBody user) { - //if (!configService.selectRegisterEnabled(user.getTenantId())) // TODO:注册代码 + if (!configService.selectRegisterEnabled(user.getTenantId())) { return R.fail("当前系统没有开启注册功能!"); } -// registerService.register(user); -// return R.ok(); + registerService.register(user); + return R.ok(); } /** diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/service/IAuthStrategy.java b/ruoyi-admin/src/main/java/com/ruoyi/web/service/IAuthStrategy.java index ed11904..5b88d85 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/service/IAuthStrategy.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/service/IAuthStrategy.java @@ -6,6 +6,7 @@ import com.ruoyi.common.core.core.domain.model.LoginBody; import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.common.core.utils.SpringUtils; import com.ruoyi.system.domain.SysClient; +import com.ruoyi.system.domain.vo.SysClientVo; import com.ruoyi.web.domain.vo.LoginVo; /** @@ -19,8 +20,13 @@ public interface IAuthStrategy { /** * 登录 + * + * @param body 登录对象 + * @param client 授权管理视图对象 + * @param grantType 授权类型 + * @return 登录验证信息 */ - static LoginVo login(String body, SysClient client, String grantType) { + static LoginVo login(String body, SysClientVo client, String grantType) { // 授权类型和客户端id String beanName = grantType + BASE_NAME; if (!SpringUtils.containsBean(beanName)) { @@ -32,7 +38,11 @@ public interface IAuthStrategy { /** * 登录 + * + * @param body 登录对象 + * @param client 授权管理视图对象 + * @return 登录验证信息 */ - LoginVo login(String body, SysClient client); + LoginVo login(String body, SysClientVo client); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java b/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java index 7f28f15..e76230e 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java @@ -3,6 +3,7 @@ package com.ruoyi.web.service; import cn.dev33.satoken.exception.NotLoginException; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import com.mybatisflex.core.tenant.TenantManager; import com.ruoyi.common.core.constant.*; @@ -18,14 +19,18 @@ import com.ruoyi.common.security.utils.LoginHelper; import com.ruoyi.common.tenant.exception.TenantException; import com.ruoyi.common.tenant.helper.TenantHelper; import com.ruoyi.system.domain.SysUser; +import com.ruoyi.system.domain.bo.SysSocialBo; import com.ruoyi.system.domain.bo.SysUserBo; +import com.ruoyi.system.domain.vo.SysSocialVo; import com.ruoyi.system.domain.vo.SysTenantVo; import com.ruoyi.system.domain.vo.SysUserVo; import com.ruoyi.system.service.ISysPermissionService; +import com.ruoyi.system.service.ISysSocialService; import com.ruoyi.system.service.ISysTenantService; import jakarta.annotation.Resource; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import me.zhyd.oauth.model.AuthUser; import org.springframework.beans.factory.annotation.Autowired; import com.ruoyi.common.core.core.domain.model.LoginUser; import com.ruoyi.common.core.utils.DateUtils; @@ -59,12 +64,66 @@ public class SysLoginService { @Resource private ISysPermissionService permissionService; + @Resource + private ISysSocialService sysSocialService; + @Resource private ISysUserService userService; @Resource private ISysTenantService tenantService; + /** + * 绑定第三方用户 + * + * @param authUserData 授权响应实体 + * @return 统一响应实体 + */ + public void socialRegister(AuthUser authUserData) { + String authId = authUserData.getSource() + authUserData.getUuid(); + // 第三方用户信息 + SysSocialBo bo = BeanUtil.toBean(authUserData, SysSocialBo.class); + BeanUtil.copyProperties(authUserData.getToken(), bo); + bo.setUserId(LoginHelper.getUserId()); + bo.setAuthId(authId); + bo.setOpenId(authUserData.getUuid()); + bo.setUserName(authUserData.getUsername()); + bo.setNickName(authUserData.getNickname()); + // 查询是否已经绑定用户 + List list = sysSocialService.selectListByAuthId(authId); + if (CollUtil.isEmpty(list)) { + // 没有绑定用户, 新增用户信息 + sysSocialService.insertByBo(bo); + } else { + // 更新用户信息 + bo.setSocialId(list.get(0).getSocialId()); + sysSocialService.updateByBo(bo); + } + } + + /** + * 退出登录 + */ + public void logout() { + try { + LoginUser loginUser = LoginHelper.getLoginUser(); + if (ObjectUtil.isNull(loginUser)) { + return; + } + if (LoginHelper.isSuperAdmin()) { + // 超级管理员 登出清除动态租户 + TenantHelper.clearDynamic(); + } + recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success")); + } catch (NotLoginException ignored) { + } finally { + try { + StpUtil.logout(); + } catch (NotLoginException ignored) { + } + } + } + /** * 登录校验 */ @@ -180,25 +239,18 @@ public class SysLoginService { } /** - * 退出登录 + * 记录登录信息 + * + * @param userId 用户ID */ - public void logout() { - try { - LoginUser loginUser = LoginHelper.getLoginUser(); - if (ObjectUtil.isNull(loginUser)) { - return; - } - if (LoginHelper.isSuperAdmin()) { - // 超级管理员 登出清除动态租户 - TenantHelper.clearDynamic(); - } - recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success")); - } catch (NotLoginException ignored) { - } finally { - try { - StpUtil.logout(); - } catch (NotLoginException ignored) { - } - } + public void recordLoginInfo(Long userId, String ip) { + SysUser sysUser = new SysUser(); + sysUser.setUserId(userId); + sysUser.setLoginIp(ip); + sysUser.setLoginDate(DateUtils.getNowDate()); + sysUser.setUpdateBy(userId); + userService.updateById(sysUser); } + + } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysRegisterService.java b/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysRegisterService.java index 44a0352..b1ede30 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysRegisterService.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysRegisterService.java @@ -8,6 +8,7 @@ import com.ruoyi.common.core.utils.ServletUtils; import com.ruoyi.common.core.utils.SpringUtils; import com.ruoyi.common.log.event.LogininforEvent; import com.ruoyi.common.redis.utils.RedisUtils; +import com.ruoyi.common.tenant.helper.TenantHelper; import com.ruoyi.common.web.config.properties.CaptchaProperties; import com.ruoyi.system.domain.SysUser; import com.ruoyi.system.domain.bo.SysUserBo; @@ -30,8 +31,7 @@ import org.springframework.stereotype.Service; */ @RequiredArgsConstructor @Service -public class SysRegisterService -{ +public class SysRegisterService { @Resource private ISysUserService userService; @@ -43,33 +43,36 @@ public class SysRegisterService /** * 注册 */ - public void register(RegisterBody registerBody) - { + public void register(RegisterBody registerBody) { Long tenantId = registerBody.getTenantId(); - String username = registerBody.getUsername(); - String password = registerBody.getPassword(); - // 校验用户类型是否存在 - String userType = UserType.getUserType(registerBody.getUserType()).getUserType(); + TenantHelper.dynamic(tenantId, () -> { + String username = registerBody.getUsername(); + String password = registerBody.getPassword(); + // 校验用户类型是否存在 + String userType = UserType.getUserType(registerBody.getUserType()).getUserType(); - boolean captchaEnabled = captchaProperties.getEnable(); - // 验证码开关 - if (captchaEnabled) { - validateCaptcha(tenantId, username, registerBody.getCode(), registerBody.getUuid()); - } - SysUserBo sysUser = new SysUserBo(); - sysUser.setUserName(username); - sysUser.setNickName(username); - sysUser.setPassword(BCrypt.hashpw(password)); - sysUser.setUserType(userType); + boolean captchaEnabled = captchaProperties.getEnable(); + // 验证码开关 + if (captchaEnabled) { + validateCaptcha(tenantId, username, registerBody.getCode(), registerBody.getUuid()); + } + SysUserBo sysUser = new SysUserBo(); + sysUser.setUserName(username); + sysUser.setNickName(username); + sysUser.setPassword(BCrypt.hashpw(password)); + sysUser.setUserType(userType); - if (!userService.checkUserNameUnique(sysUser)) { - throw new UserException("user.register.save.error", username); - } - boolean regFlag = userService.registerUser(sysUser, tenantId); - if (!regFlag) { - throw new UserException("user.register.error"); - } - recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.register.success")); + boolean unique = userService.checkUserNameUnique(sysUser); + + if (!unique) { + throw new UserException("user.register.save.error", username); + } + boolean regFlag = userService.registerUser(sysUser, tenantId); + if (!regFlag) { + throw new UserException("user.register.error"); + } + recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.register.success")); + }); } /** diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/EmailAuthStrategy.java b/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/EmailAuthStrategy.java index 79201ef..41ec96c 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/EmailAuthStrategy.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/EmailAuthStrategy.java @@ -3,10 +3,10 @@ package com.ruoyi.web.service.impl; import cn.dev33.satoken.stp.SaLoginModel; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.util.ObjectUtil; -import com.ruoyi.common.core.core.domain.AjaxResult; import com.ruoyi.common.core.core.domain.model.EmailLoginBody; import com.ruoyi.common.json.utils.JsonUtils; import com.ruoyi.common.tenant.helper.TenantHelper; +import com.ruoyi.system.domain.vo.SysClientVo; import com.ruoyi.system.domain.vo.SysUserVo; import com.ruoyi.system.service.ISysUserService; import com.ruoyi.web.domain.vo.LoginVo; @@ -15,7 +15,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import com.ruoyi.common.core.constant.Constants; import com.ruoyi.common.core.constant.GlobalConstants; -import com.ruoyi.common.core.core.domain.model.LoginBody; import com.ruoyi.common.core.core.domain.model.LoginUser; import com.ruoyi.common.core.enums.LoginType; import com.ruoyi.common.core.enums.UserStatus; @@ -24,12 +23,8 @@ import com.ruoyi.common.core.exception.user.UserException; import com.ruoyi.common.core.utils.MessageUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.ValidatorUtils; -import com.ruoyi.common.core.validate.auth.EmailGroup; import com.ruoyi.common.redis.utils.RedisUtils; import com.ruoyi.common.security.utils.LoginHelper; -import com.ruoyi.system.domain.SysClient; -import com.ruoyi.system.domain.SysUser; -import com.ruoyi.system.mapper.SysUserMapper; import com.ruoyi.web.service.IAuthStrategy; import com.ruoyi.web.service.SysLoginService; import org.springframework.stereotype.Service; @@ -48,8 +43,9 @@ public class EmailAuthStrategy implements IAuthStrategy { private final SysLoginService loginService; @Resource private ISysUserService userService; + @Override - public LoginVo login(String body, SysClient client) { + public LoginVo login(String body, SysClientVo client) { EmailLoginBody loginBody = JsonUtils.parseObject(body, EmailLoginBody.class); ValidatorUtils.validate(loginBody); Long tenantId = loginBody.getTenantId(); @@ -97,17 +93,15 @@ public class EmailAuthStrategy implements IAuthStrategy { } private SysUserVo loadUserByEmail(Long tenantId, String email) { - return TenantHelper.dynamic(tenantId, () -> { - SysUserVo user =userService.selectUserByEmail(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 user; - }); + SysUserVo user = userService.selectTenantUserByEmail(tenantId, 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 user; } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/PasswordAuthStrategy.java b/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/PasswordAuthStrategy.java index 7037a64..e44f0e0 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/PasswordAuthStrategy.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/PasswordAuthStrategy.java @@ -7,6 +7,7 @@ import cn.hutool.core.util.ObjectUtil; import com.ruoyi.common.core.core.domain.model.PasswordLoginBody; import com.ruoyi.common.json.utils.JsonUtils; import com.ruoyi.common.tenant.helper.TenantHelper; +import com.ruoyi.system.domain.vo.SysClientVo; import com.ruoyi.system.service.ISysUserService; import jakarta.annotation.Resource; import lombok.RequiredArgsConstructor; @@ -49,7 +50,7 @@ public class PasswordAuthStrategy implements IAuthStrategy { private ISysUserService userService; @Override - public LoginVo login(String body, SysClient client) { + public LoginVo login(String body, SysClientVo client) { PasswordLoginBody loginBody = JsonUtils.parseObject(body, PasswordLoginBody.class); ValidatorUtils.validate(loginBody); Long tenantId = loginBody.getTenantId(); @@ -80,8 +81,8 @@ public class PasswordAuthStrategy implements IAuthStrategy { // 生成token LoginHelper.login(loginUser, model); - loginService.recordLogininfor(loginUser.getTenantId(), username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); - loginService.recordLoginInfo(user.getUserId(),user.getVersion()); +// loginService.recordLogininfor(loginUser.getTenantId(), username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); +// loginService.recordLoginInfo(user.getUserId(),user.getVersion()); LoginVo loginVo = new LoginVo(); loginVo.setAccessToken(StpUtil.getTokenValue()); @@ -113,8 +114,7 @@ public class PasswordAuthStrategy implements IAuthStrategy { } private SysUserVo loadUserByUsername(Long tenantId, String username) { - - SysUserVo user = userService.selectTenantUserByUserName(username,tenantId); + SysUserVo user = userService.selectTenantUserByUserName(tenantId,username); if (ObjectUtil.isNull(user)) { log.info("登录用户:{} 不存在.", username); throw new UserException("user.not.exists", username); diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/SmsAuthStrategy.java b/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/SmsAuthStrategy.java new file mode 100644 index 0000000..62a7933 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/SmsAuthStrategy.java @@ -0,0 +1,103 @@ +package com.ruoyi.web.service.impl; + +import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.util.ObjectUtil; +import com.ruoyi.common.core.core.domain.model.LoginUser; +import com.ruoyi.common.core.core.domain.model.SmsLoginBody; +import com.ruoyi.system.service.ISysUserService; +import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import com.ruoyi.common.core.constant.Constants; +import com.ruoyi.common.core.constant.GlobalConstants; +import com.ruoyi.common.core.enums.LoginType; +import com.ruoyi.common.core.enums.UserStatus; +import com.ruoyi.common.core.exception.user.CaptchaExpireException; +import com.ruoyi.common.core.exception.user.UserException; +import com.ruoyi.common.core.utils.MessageUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.utils.ValidatorUtils; +import com.ruoyi.common.json.utils.JsonUtils; +import com.ruoyi.common.redis.utils.RedisUtils; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.system.domain.vo.SysClientVo; +import com.ruoyi.system.domain.vo.SysUserVo; +import com.ruoyi.web.domain.vo.LoginVo; +import com.ruoyi.web.service.IAuthStrategy; +import com.ruoyi.web.service.SysLoginService; +import org.springframework.stereotype.Service; + +/** + * 短信认证策略 + * + * @author Michelle.Chung + */ +@Slf4j +@Service("sms" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class SmsAuthStrategy implements IAuthStrategy { + + @Resource + private SysLoginService loginService; + @Resource + private ISysUserService userService; + + @Override + public LoginVo login(String body, SysClientVo client) { + SmsLoginBody loginBody = JsonUtils.parseObject(body, SmsLoginBody.class); + ValidatorUtils.validate(loginBody); + Long tenantId = loginBody.getTenantId(); + String phonenumber = loginBody.getPhonenumber(); + String smsCode = loginBody.getSmsCode(); + + // 通过手机号查找用户 + SysUserVo user = loadUserByPhonenumber(tenantId, phonenumber); + + loginService.checkLogin(LoginType.SMS, tenantId, user.getUserName(), () -> !validateSmsCode(tenantId, phonenumber, smsCode)); + // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 + LoginUser loginUser = loginService.buildLoginUser(user); + 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; + } + + /** + * 校验短信验证码 + */ + private boolean validateSmsCode(Long tenantId, String phonenumber, String smsCode) { + String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber); + if (StringUtils.isBlank(code)) { + loginService.recordLogininfor(tenantId, phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); + throw new CaptchaExpireException(); + } + return code.equals(smsCode); + } + + private SysUserVo loadUserByPhonenumber(Long tenantId, String phonenumber) { + SysUserVo user = userService.selectTenantUserByPhonenumber(tenantId, 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 user; + } + +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/SocialAuthStrategy.java b/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/SocialAuthStrategy.java new file mode 100644 index 0000000..d1c0075 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/SocialAuthStrategy.java @@ -0,0 +1,122 @@ +package com.ruoyi.web.service.impl; + +import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.http.HttpUtil; +import cn.hutool.http.Method; +import com.ruoyi.system.service.ISysUserService; +import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.zhyd.oauth.model.AuthResponse; +import me.zhyd.oauth.model.AuthUser; +import com.ruoyi.common.core.core.domain.model.LoginUser; +import com.ruoyi.common.core.core.domain.model.SocialLoginBody; +import com.ruoyi.common.core.enums.UserStatus; +import com.ruoyi.common.core.exception.ServiceException; +import com.ruoyi.common.core.exception.user.UserException; +import com.ruoyi.common.core.utils.ValidatorUtils; +import com.ruoyi.common.json.utils.JsonUtils; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.common.social.config.properties.SocialProperties; +import com.ruoyi.common.social.utils.SocialUtils; +import com.ruoyi.common.tenant.helper.TenantHelper; +import com.ruoyi.system.domain.vo.SysClientVo; +import com.ruoyi.system.domain.vo.SysSocialVo; +import com.ruoyi.system.domain.vo.SysUserVo; +import com.ruoyi.system.mapper.SysUserMapper; +import com.ruoyi.system.service.ISysSocialService; +import com.ruoyi.web.domain.vo.LoginVo; +import com.ruoyi.web.service.IAuthStrategy; +import com.ruoyi.web.service.SysLoginService; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +/** + * 第三方授权策略 + * + * @author thiszhc is 三三 + */ +@Slf4j +@Service("social" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class SocialAuthStrategy implements IAuthStrategy { + + private final SocialProperties socialProperties; + @Resource + private ISysSocialService sysSocialService; + @Resource + private ISysUserService userService; + @Resource + private SysLoginService loginService; + + /** + * 登录-第三方授权登录 + * + * @param body 登录信息 + * @param client 客户端信息 + */ + @Override + public LoginVo login(String body, SysClientVo client) { + SocialLoginBody loginBody = JsonUtils.parseObject(body, SocialLoginBody.class); + ValidatorUtils.validate(loginBody); + AuthResponse response = SocialUtils.loginAuth( + loginBody.getSource(), loginBody.getSocialCode(), + loginBody.getSocialState(), socialProperties); + if (!response.ok()) { + throw new ServiceException(response.getMsg()); + } + AuthUser authUserData = response.getData(); + + List list = sysSocialService.selectListByAuthId(authUserData.getSource() + authUserData.getUuid()); + if (CollUtil.isEmpty(list)) { + throw new ServiceException("你还没有绑定第三方账号,绑定后才可以登录!"); + } + Optional opt = list.stream().filter(x -> x.getTenantId().equals(loginBody.getTenantId())).findAny(); + if (opt.isEmpty()) { + throw new ServiceException("对不起,你没有权限登录当前租户!"); + } + SysSocialVo social = opt.get(); + + // 查找用户 + SysUserVo user = loadUser(social.getTenantId(), social.getUserId()); + + // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 + LoginUser loginUser = loginService.buildLoginUser(user); + 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; + } + + private SysUserVo loadUser(Long tenantId, Long userId) { + SysUserVo user = userService.selectTenantUserById(tenantId, userId); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", ""); + throw new UserException("user.not.exists", ""); + } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", ""); + throw new UserException("user.blocked", ""); + } + return user; + } + +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/XcxAuthStrategy.java b/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/XcxAuthStrategy.java new file mode 100644 index 0000000..cd702bb --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/service/impl/XcxAuthStrategy.java @@ -0,0 +1,94 @@ +package com.ruoyi.web.service.impl; + +import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.util.ObjectUtil; +import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import com.ruoyi.common.core.core.domain.model.XcxLoginBody; +import com.ruoyi.common.core.core.domain.model.XcxLoginUser; +import com.ruoyi.common.core.enums.UserStatus; +import com.ruoyi.common.core.utils.ValidatorUtils; +import com.ruoyi.common.json.utils.JsonUtils; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.system.domain.SysClient; +import com.ruoyi.system.domain.vo.SysClientVo; +import com.ruoyi.system.domain.vo.SysUserVo; +import com.ruoyi.web.domain.vo.LoginVo; +import com.ruoyi.web.service.IAuthStrategy; +import com.ruoyi.web.service.SysLoginService; +import org.springframework.stereotype.Service; + +/** + * 小程序认证策略 + * + * @author Michelle.Chung + */ +@Slf4j +@Service("xcx" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class XcxAuthStrategy implements IAuthStrategy { + + @Resource + private SysLoginService loginService; + + @Override + public LoginVo login(String body, SysClientVo client) { + XcxLoginBody loginBody = JsonUtils.parseObject(body, XcxLoginBody.class); + ValidatorUtils.validate(loginBody); + // xcxCode 为 小程序调用 wx.login 授权后获取 + String xcxCode = loginBody.getXcxCode(); + // 多个小程序识别使用 + String appid = loginBody.getAppid(); + + // todo 以下自行实现 + // 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key 与 openid + String openid = ""; + // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可 + SysUserVo user = loadUserByOpenid(openid); + + // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 + XcxLoginUser loginUser = new XcxLoginUser(); + loginUser.setTenantId(user.getTenantId()); + loginUser.setUserId(user.getUserId()); + loginUser.setUsername(user.getUserName()); + loginUser.setNickname(user.getNickName()); + loginUser.setUserType(user.getUserType()); + loginUser.setClientKey(client.getClientKey()); + loginUser.setDeviceType(client.getDeviceType()); + loginUser.setOpenid(openid); + + 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()); + loginVo.setOpenid(openid); + return loginVo; + } + + private SysUserVo loadUserByOpenid(String openid) { + // 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户 + // todo 自行实现 userService.selectUserByOpenid(openid); + SysUserVo user = new SysUserVo(); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", openid); + // todo 用户不存在 业务逻辑自行实现 + } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", openid); + // todo 用户已被停用 业务逻辑自行实现 + } + return user; + } + +} diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml index 99f9e7b..50274c6 100644 --- a/ruoyi-admin/src/main/resources/application-dev.yml +++ b/ruoyi-admin/src/main/resources/application-dev.yml @@ -157,3 +157,79 @@ sms: access-key-secret: 您的accessKeySecret signature: 您的短信签名 sdk-app-id: 您的sdkAppId + +--- # 三方授权 +justauth: + # 前端外网访问地址 + address: http://localhost:80 + type: + maxkey: + # maxkey 服务器地址 + # 注意 如下均配置均不需要修改 maxkey 已经内置好了数据 + server-url: http://sso.maxkey.top + client-id: 876892492581044224 + client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8 + redirect-uri: ${justauth.address}/social-callback?source=maxkey + topiam: + # topiam 服务器地址 + server-url: http://127.0.0.1:1989/api/v1/authorize/y0q************spq***********8ol + client-id: 449c4*********937************759 + client-secret: ac7***********1e0************28d + redirect-uri: ${justauth.address}/social-callback?source=topiam + scopes: [openid, email, phone, profile] + qq: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=qq + union-id: false + weibo: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=weibo + gitee: + client-id: 91436b7940090**********d67eea73acbf61b6b590751a98 + client-secret: 02c6fcfd70342980cd8**********c754d7a264c4e125f9ba915ac + redirect-uri: ${justauth.address}/social-callback?source=gitee + dingtalk: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=dingtalk + baidu: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=baidu + csdn: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=csdn + coding: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=coding + coding-group-name: xx + oschina: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=oschina + alipay_wallet: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet + alipay-public-key: MIIB**************DAQAB + wechat_open: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_open + wechat_mp: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_mp + wechat_enterprise: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise + agent-id: 1000002 + gitlab: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=gitlab diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml index fc107f6..52edd47 100644 --- a/ruoyi-admin/src/main/resources/application-prod.yml +++ b/ruoyi-admin/src/main/resources/application-prod.yml @@ -171,3 +171,80 @@ sms: access-key-secret: 您的accessKeySecret signature: 您的短信签名 sdk-app-id: 您的sdkAppId + + +--- # 三方授权 +justauth: + # 前端外网访问地址 + address: http://localhost:80 + type: + maxkey: + # maxkey 服务器地址 + # 注意 如下均配置均不需要修改 maxkey 已经内置好了数据 + server-url: http://sso.maxkey.top + client-id: 876892492581044224 + client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8 + redirect-uri: ${justauth.address}/social-callback?source=maxkey + topiam: + # topiam 服务器地址 + server-url: http://127.0.0.1:1989/api/v1/authorize/y0q************spq***********8ol + client-id: 449c4*********937************759 + client-secret: ac7***********1e0************28d + redirect-uri: ${justauth.address}/social-callback?source=topiam + scopes: [openid, email, phone, profile] + qq: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=qq + union-id: false + weibo: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=weibo + gitee: + client-id: 91436b7940090**********d67eea73acbf61b6b590751a98 + client-secret: 02c6fcfd70342980cd8**********c754d7a264c4e125f9ba915ac + redirect-uri: ${justauth.address}/social-callback?source=gitee + dingtalk: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=dingtalk + baidu: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=baidu + csdn: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=csdn + coding: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=coding + coding-group-name: xx + oschina: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=oschina + alipay_wallet: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet + alipay-public-key: MIIB**************DAQAB + wechat_open: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_open + wechat_mp: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_mp + wechat_enterprise: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise + agent-id: 1000002 + gitlab: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=gitlab diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index f629313..ed263d7 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -25,6 +25,7 @@ ruoyi-common-redis ruoyi-common-security ruoyi-common-sms + ruoyi-common-social ruoyi-common-springdoc ruoyi-common-tenant ruoyi-common-web diff --git a/ruoyi-common/ruoyi-common-bom/pom.xml b/ruoyi-common/ruoyi-common-bom/pom.xml index d128a24..411cbf3 100644 --- a/ruoyi-common/ruoyi-common-bom/pom.xml +++ b/ruoyi-common/ruoyi-common-bom/pom.xml @@ -108,8 +108,15 @@ com.ruoyi ruoyi-common-sms ${revision} - + + + + com.ruoyi + ruoyi-common-social + ${revision} + + com.ruoyi diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/SmsLoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/SmsLoginBody.java new file mode 100644 index 0000000..6cb854d --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/SmsLoginBody.java @@ -0,0 +1,29 @@ +package com.ruoyi.common.core.core.domain.model; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 短信登录对象 + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +public class SmsLoginBody extends LoginBody { + + /** + * 手机号 + */ + @NotBlank(message = "{user.phonenumber.not.blank}") + private String phonenumber; + + /** + * 短信code + */ + @NotBlank(message = "{sms.code.not.blank}") + private String smsCode; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/SocialLoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/SocialLoginBody.java new file mode 100644 index 0000000..5e85981 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/SocialLoginBody.java @@ -0,0 +1,35 @@ +package com.ruoyi.common.core.core.domain.model; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 三方登录对象 + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +public class SocialLoginBody extends LoginBody { + + /** + * 第三方登录平台 + */ + @NotBlank(message = "{social.source.not.blank}") + private String source; + + /** + * 第三方登录code + */ + @NotBlank(message = "{social.code.not.blank}") + private String socialCode; + + /** + * 第三方登录socialState + */ + @NotBlank(message = "{social.state.not.blank}") + private String socialState; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/XcxLoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/XcxLoginBody.java new file mode 100644 index 0000000..793fac9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/XcxLoginBody.java @@ -0,0 +1,28 @@ +package com.ruoyi.common.core.core.domain.model; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 三方登录对象 + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +public class XcxLoginBody extends LoginBody { + + /** + * 小程序id(多个小程序时使用) + */ + private String appid; + + /** + * 小程序code + */ + @NotBlank(message = "{xcx.code.not.blank}") + private String xcxCode; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/XcxLoginUser.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/XcxLoginUser.java new file mode 100644 index 0000000..a180115 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/XcxLoginUser.java @@ -0,0 +1,27 @@ +package com.ruoyi.common.core.core.domain.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.io.Serial; + +/** + * 小程序登录用户身份权限 + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +public class XcxLoginUser extends LoginUser { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * openid + */ + private String openid; + +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/SecurityConfig.java b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/SecurityConfig.java index 09b7b5f..73193c2 100644 --- a/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/SecurityConfig.java +++ b/ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/SecurityConfig.java @@ -49,7 +49,16 @@ public class SecurityConfig implements WebMvcConfigurer { // 检查是否登录 是否有token StpUtil.checkLogin(); - //TODO :以后完善多平台登录校验clientID功能 + // 检查 header 与 param 里的 clientid 与 token 里的是否一致 + String headerCid = ServletUtils.getRequest().getHeader(LoginHelper.CLIENT_KEY); + String paramCid = ServletUtils.getParameter(LoginHelper.CLIENT_KEY); + String clientId = StpUtil.getExtra(LoginHelper.CLIENT_KEY).toString(); + if (!StringUtils.equalsAny(clientId, headerCid, paramCid)) { + // token 无效 + throw NotLoginException.newInstance(StpUtil.getLoginType(), + "-100", "客户端ID与Token不匹配", + StpUtil.getTokenValue()); + } }); })).addPathPatterns("/**") diff --git a/ruoyi-common/ruoyi-common-social/pom.xml b/ruoyi-common/ruoyi-common-social/pom.xml new file mode 100644 index 0000000..7dfe2e8 --- /dev/null +++ b/ruoyi-common/ruoyi-common-social/pom.xml @@ -0,0 +1,34 @@ + + + + com.ruoyi + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-social + + + ruoyi-common-social 三方授权认证 + + + + + me.zhyd.oauth + JustAuth + + + + com.ruoyi + ruoyi-common-json + + + + com.ruoyi + ruoyi-common-redis + + + diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/config/SocialAutoConfiguration.java b/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/config/SocialAutoConfiguration.java new file mode 100644 index 0000000..6a28866 --- /dev/null +++ b/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/config/SocialAutoConfiguration.java @@ -0,0 +1,23 @@ +package com.ruoyi.common.social.config; + +import me.zhyd.oauth.cache.AuthStateCache; +import com.ruoyi.common.social.config.properties.SocialProperties; +import com.ruoyi.common.social.utils.AuthRedisStateCache; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; + +/** + * Social 配置属性 + * @author thiszhc + */ +@AutoConfiguration +@EnableConfigurationProperties(SocialProperties.class) +public class SocialAutoConfiguration { + + @Bean + public AuthStateCache authStateCache() { + return new AuthRedisStateCache(); + } + +} diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/config/properties/SocialLoginConfigProperties.java b/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/config/properties/SocialLoginConfigProperties.java new file mode 100644 index 0000000..2d83a73 --- /dev/null +++ b/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/config/properties/SocialLoginConfigProperties.java @@ -0,0 +1,75 @@ +package com.ruoyi.common.social.config.properties; + +import lombok.Data; + +import java.util.List; + +/** + * 社交登录配置 + * + * @author thiszhc + */ +@Data +public class SocialLoginConfigProperties { + + /** + * 应用 ID + */ + private String clientId; + + /** + * 应用密钥 + */ + private String clientSecret; + + /** + * 回调地址 + */ + private String redirectUri; + + /** + * 是否获取unionId + */ + private boolean unionId; + + /** + * Coding 企业名称 + */ + private String codingGroupName; + + /** + * 支付宝公钥 + */ + private String alipayPublicKey; + + /** + * 企业微信应用ID + */ + private String agentId; + + /** + * stackoverflow api key + */ + private String stackOverflowKey; + + /** + * 设备ID + */ + private String deviceId; + + /** + * 客户端系统类型 + */ + private String clientOsType; + + /** + * maxkey 服务器地址 + */ + private String serverUrl; + + /** + * 请求范围 + */ + private List scopes; + +} diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/config/properties/SocialProperties.java b/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/config/properties/SocialProperties.java new file mode 100644 index 0000000..9a488e9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/config/properties/SocialProperties.java @@ -0,0 +1,24 @@ +package com.ruoyi.common.social.config.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * Social 配置属性 + * + * @author thiszhc + */ +@Data +@Component +@ConfigurationProperties(prefix = "justauth") +public class SocialProperties { + + /** + * 授权类型 + */ + private Map type; + +} diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/maxkey/AuthMaxKeyRequest.java b/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/maxkey/AuthMaxKeyRequest.java new file mode 100644 index 0000000..42cf563 --- /dev/null +++ b/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/maxkey/AuthMaxKeyRequest.java @@ -0,0 +1,80 @@ +package com.ruoyi.common.social.maxkey; + +import cn.hutool.core.lang.Dict; +import me.zhyd.oauth.cache.AuthStateCache; +import me.zhyd.oauth.config.AuthConfig; +import me.zhyd.oauth.exception.AuthException; +import me.zhyd.oauth.model.AuthCallback; +import me.zhyd.oauth.model.AuthToken; +import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.request.AuthDefaultRequest; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.json.utils.JsonUtils; + +/** + * @author 长春叭哥 2023年03月26日 + */ +public class AuthMaxKeyRequest extends AuthDefaultRequest { + + public static final String SERVER_URL = SpringUtils.getProperty("justauth.type.maxkey.server-url"); + + /** + * 设定归属域 + */ + public AuthMaxKeyRequest(AuthConfig config) { + super(config, AuthMaxKeySource.MAXKEY); + } + + public AuthMaxKeyRequest(AuthConfig config, AuthStateCache authStateCache) { + super(config, AuthMaxKeySource.MAXKEY, authStateCache); + } + + @Override + protected AuthToken getAccessToken(AuthCallback authCallback) { + String body = doPostAuthorizationCode(authCallback.getCode()); + Dict object = JsonUtils.parseMap(body); + // oauth/token 验证异常 + if (object.containsKey("error")) { + throw new AuthException(object.getStr("error_description")); + } + // user 验证异常 + if (object.containsKey("message")) { + throw new AuthException(object.getStr("message")); + } + return AuthToken.builder() + .accessToken(object.getStr("access_token")) + .refreshToken(object.getStr("refresh_token")) + .idToken(object.getStr("id_token")) + .tokenType(object.getStr("token_type")) + .scope(object.getStr("scope")) + .build(); + } + + @Override + protected AuthUser getUserInfo(AuthToken authToken) { + String body = doGetUserInfo(authToken); + Dict object = JsonUtils.parseMap(body); + // oauth/token 验证异常 + if (object.containsKey("error")) { + throw new AuthException(object.getStr("error_description")); + } + // user 验证异常 + if (object.containsKey("message")) { + throw new AuthException(object.getStr("message")); + } + return AuthUser.builder() + .uuid(object.getStr("userId")) + .username(object.getStr("username")) + .nickname(object.getStr("displayName")) + .avatar(object.getStr("avatar_url")) + .blog(object.getStr("web_url")) + .company(object.getStr("organization")) + .location(object.getStr("location")) + .email(object.getStr("email")) + .remark(object.getStr("bio")) + .token(authToken) + .source(source.toString()) + .build(); + } + +} diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/maxkey/AuthMaxKeySource.java b/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/maxkey/AuthMaxKeySource.java new file mode 100644 index 0000000..3928332 --- /dev/null +++ b/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/maxkey/AuthMaxKeySource.java @@ -0,0 +1,52 @@ +package com.ruoyi.common.social.maxkey; + +import me.zhyd.oauth.config.AuthSource; +import me.zhyd.oauth.request.AuthDefaultRequest; + +/** + * Oauth2 默认接口说明 + * + * @author 长春叭哥 2023年03月26日 + * + */ +public enum AuthMaxKeySource implements AuthSource { + + /** + * 自己搭建的 maxkey 私服 + */ + MAXKEY { + + /** + * 授权的api + */ + @Override + public String authorize() { + return AuthMaxKeyRequest.SERVER_URL + "/sign/authz/oauth/v20/authorize"; + } + + /** + * 获取accessToken的api + */ + @Override + public String accessToken() { + return AuthMaxKeyRequest.SERVER_URL + "/sign/authz/oauth/v20/token"; + } + + /** + * 获取用户信息的api + */ + @Override + public String userInfo() { + return AuthMaxKeyRequest.SERVER_URL + "/sign/api/oauth/v20/me"; + } + + /** + * 平台对应的 AuthRequest 实现类,必须继承自 {@link AuthDefaultRequest} + */ + @Override + public Class getTargetClass() { + return AuthMaxKeyRequest.class; + } + + } +} diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/topiam/AuthTopIamRequest.java b/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/topiam/AuthTopIamRequest.java new file mode 100644 index 0000000..5d1d368 --- /dev/null +++ b/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/topiam/AuthTopIamRequest.java @@ -0,0 +1,100 @@ +package com.ruoyi.common.social.topiam; + +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.StrUtil; +import com.xkcoding.http.support.HttpHeader; +import lombok.extern.slf4j.Slf4j; +import me.zhyd.oauth.cache.AuthStateCache; +import me.zhyd.oauth.config.AuthConfig; +import me.zhyd.oauth.exception.AuthException; +import me.zhyd.oauth.model.AuthCallback; +import me.zhyd.oauth.model.AuthToken; +import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.request.AuthDefaultRequest; +import me.zhyd.oauth.utils.HttpUtils; +import me.zhyd.oauth.utils.UrlBuilder; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.json.utils.JsonUtils; + +import static com.ruoyi.common.social.topiam.AuthTopiamSource.TOPIAM; + +/** + * TopIAM 认证请求 + * + * @author xlsea + * @since 2024-01-06 + */ +@Slf4j +public class AuthTopIamRequest extends AuthDefaultRequest { + + public static final String SERVER_URL = SpringUtils.getProperty("justauth.type.topiam.server-url"); + + /** + * 设定归属域 + */ + public AuthTopIamRequest(AuthConfig config) { + super(config, TOPIAM); + } + + public AuthTopIamRequest(AuthConfig config, AuthStateCache authStateCache) { + super(config, TOPIAM, authStateCache); + } + + @Override + protected AuthToken getAccessToken(AuthCallback authCallback) { + String body = doPostAuthorizationCode(authCallback.getCode()); + Dict object = JsonUtils.parseMap(body); + checkResponse(object); + return AuthToken.builder() + .accessToken(object.getStr("access_token")) + .refreshToken(object.getStr("refresh_token")) + .idToken(object.getStr("id_token")) + .tokenType(object.getStr("token_type")) + .scope(object.getStr("scope")) + .build(); + } + + @Override + protected AuthUser getUserInfo(AuthToken authToken) { + String body = doGetUserInfo(authToken); + Dict object = JsonUtils.parseMap(body); + checkResponse(object); + return AuthUser.builder() + .uuid(object.getStr("sub")) + .username(object.getStr("preferred_username")) + .nickname(object.getStr("nickname")) + .avatar(object.getStr("picture")) + .email(object.getStr("email")) + .token(authToken) + .source(source.toString()) + .build(); + } + + + @Override + protected String doGetUserInfo(AuthToken authToken) { + return new HttpUtils(config.getHttpConfig()).get(source.userInfo(), null, new HttpHeader() + .add("Content-Type", "application/json") + .add("Authorization", "Bearer " + authToken.getAccessToken()), false).getBody(); + } + + + @Override + public String authorize(String state) { + return UrlBuilder.fromBaseUrl(super.authorize(state)) + .queryParam("scope", StrUtil.join("%20", config.getScopes())) + .build(); + } + + public static void checkResponse(Dict object) { + // oauth/token 验证异常 + if (object.containsKey("error")) { + throw new AuthException(object.getStr("error_description")); + } + // user 验证异常 + if (object.containsKey("message")) { + throw new AuthException(object.getStr("message")); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/topiam/AuthTopiamSource.java b/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/topiam/AuthTopiamSource.java new file mode 100644 index 0000000..5bf5a48 --- /dev/null +++ b/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/topiam/AuthTopiamSource.java @@ -0,0 +1,51 @@ +package com.ruoyi.common.social.topiam; + +import me.zhyd.oauth.config.AuthSource; +import me.zhyd.oauth.request.AuthDefaultRequest; + +/** + * Oauth2 默认接口说明 + * + * @author xlsea + * @since 2024-01-06 + */ +public enum AuthTopiamSource implements AuthSource { + + /** + * 测试 + */ + TOPIAM { + /** + * 授权的api + */ + @Override + public String authorize() { + return AuthTopIamRequest.SERVER_URL + "/oauth2/auth"; + } + + /** + * 获取accessToken的api + */ + @Override + public String accessToken() { + return AuthTopIamRequest.SERVER_URL + "/oauth2/token"; + } + + /** + * 获取用户信息的api + */ + @Override + public String userInfo() { + return AuthTopIamRequest.SERVER_URL + "/oauth2/userinfo"; + } + + /** + * 平台对应的 AuthRequest 实现类,必须继承自 {@link AuthDefaultRequest} + */ + @Override + public Class getTargetClass() { + return AuthTopIamRequest.class; + } + + } +} diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/utils/AuthRedisStateCache.java b/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/utils/AuthRedisStateCache.java new file mode 100644 index 0000000..e8c6aa5 --- /dev/null +++ b/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/utils/AuthRedisStateCache.java @@ -0,0 +1,61 @@ +package com.ruoyi.common.social.utils; + +import lombok.AllArgsConstructor; +import me.zhyd.oauth.cache.AuthStateCache; +import com.ruoyi.common.core.constant.GlobalConstants; +import com.ruoyi.common.redis.utils.RedisUtils; + +import java.time.Duration; + +/** + * 授权状态缓存 + */ +@AllArgsConstructor +public class AuthRedisStateCache implements AuthStateCache { + + /** + * 存入缓存 + * + * @param key 缓存key + * @param value 缓存内容 + */ + @Override + public void cache(String key, String value) { + // 授权超时时间 默认三分钟 + RedisUtils.setCacheObject(GlobalConstants.SOCIAL_AUTH_CODE_KEY + key, value, Duration.ofMinutes(3)); + } + + /** + * 存入缓存 + * + * @param key 缓存key + * @param value 缓存内容 + * @param timeout 指定缓存过期时间(毫秒) + */ + @Override + public void cache(String key, String value, long timeout) { + RedisUtils.setCacheObject(GlobalConstants.SOCIAL_AUTH_CODE_KEY + key, value, Duration.ofMillis(timeout)); + } + + /** + * 获取缓存内容 + * + * @param key 缓存key + * @return 缓存内容 + */ + @Override + public String get(String key) { + return RedisUtils.getCacheObject(GlobalConstants.SOCIAL_AUTH_CODE_KEY + key); + } + + /** + * 是否存在key,如果对应key的value值已过期,也返回false + * + * @param key 缓存key + * @return true:存在key,并且value没过期;false:key不存在或者已过期 + */ + @Override + public boolean containsKey(String key) { + return RedisUtils.hasKey(GlobalConstants.SOCIAL_AUTH_CODE_KEY + key); + } +} diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/utils/SocialUtils.java b/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/utils/SocialUtils.java new file mode 100644 index 0000000..2b9b395 --- /dev/null +++ b/ruoyi-common/ruoyi-common-social/src/main/java/com/ruoyi/common/social/utils/SocialUtils.java @@ -0,0 +1,73 @@ +package com.ruoyi.common.social.utils; + +import cn.hutool.core.util.ObjectUtil; +import me.zhyd.oauth.config.AuthConfig; +import me.zhyd.oauth.exception.AuthException; +import me.zhyd.oauth.model.AuthCallback; +import me.zhyd.oauth.model.AuthResponse; +import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.request.*; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.social.config.properties.SocialLoginConfigProperties; +import com.ruoyi.common.social.config.properties.SocialProperties; +import com.ruoyi.common.social.maxkey.AuthMaxKeyRequest; +import com.ruoyi.common.social.topiam.AuthTopIamRequest; + +/** + * 认证授权工具类 + * + * @author thiszhc + */ +public class SocialUtils { + + private static final AuthRedisStateCache STATE_CACHE = SpringUtils.getBean(AuthRedisStateCache.class); + + @SuppressWarnings("unchecked") + public static AuthResponse loginAuth(String source, String code, String state, SocialProperties socialProperties) throws AuthException { + AuthRequest authRequest = getAuthRequest(source, socialProperties); + AuthCallback callback = new AuthCallback(); + callback.setCode(code); + callback.setState(state); + return authRequest.login(callback); + } + + public static AuthRequest getAuthRequest(String source, SocialProperties socialProperties) throws AuthException { + SocialLoginConfigProperties obj = socialProperties.getType().get(source); + if (ObjectUtil.isNull(obj)) { + throw new AuthException("不支持的第三方登录类型"); + } + AuthConfig.AuthConfigBuilder builder = AuthConfig.builder() + .clientId(obj.getClientId()) + .clientSecret(obj.getClientSecret()) + .redirectUri(obj.getRedirectUri()) + .scopes(obj.getScopes()); + return switch (source.toLowerCase()) { + case "dingtalk" -> new AuthDingTalkRequest(builder.build(), STATE_CACHE); + case "baidu" -> new AuthBaiduRequest(builder.build(), STATE_CACHE); + case "github" -> new AuthGithubRequest(builder.build(), STATE_CACHE); + case "gitee" -> new AuthGiteeRequest(builder.build(), STATE_CACHE); + case "weibo" -> new AuthWeiboRequest(builder.build(), STATE_CACHE); + case "coding" -> new AuthCodingRequest(builder.build(), STATE_CACHE); + case "oschina" -> new AuthOschinaRequest(builder.build(), STATE_CACHE); + // 支付宝在创建回调地址时,不允许使用localhost或者127.0.0.1,所以这儿的回调地址使用的局域网内的ip + case "alipay_wallet" -> new AuthAlipayRequest(builder.build(), socialProperties.getType().get("alipay_wallet").getAlipayPublicKey(), STATE_CACHE); + case "qq" -> new AuthQqRequest(builder.build(), STATE_CACHE); + case "wechat_open" -> new AuthWeChatOpenRequest(builder.build(), STATE_CACHE); + case "taobao" -> new AuthTaobaoRequest(builder.build(), STATE_CACHE); + case "douyin" -> new AuthDouyinRequest(builder.build(), STATE_CACHE); + case "linkedin" -> new AuthLinkedinRequest(builder.build(), STATE_CACHE); + case "microsoft" -> new AuthMicrosoftRequest(builder.build(), STATE_CACHE); + case "renren" -> new AuthRenrenRequest(builder.build(), STATE_CACHE); + case "stack_overflow" -> new AuthStackOverflowRequest(builder.stackOverflowKey("").build(), STATE_CACHE); + case "huawei" -> new AuthHuaweiRequest(builder.build(), STATE_CACHE); + case "wechat_enterprise" -> new AuthWeChatEnterpriseQrcodeRequest(builder.agentId("").build(), STATE_CACHE); + case "gitlab" -> new AuthGitlabRequest(builder.build(), STATE_CACHE); + case "wechat_mp" -> new AuthWeChatMpRequest(builder.build(), STATE_CACHE); + case "aliyun" -> new AuthAliyunRequest(builder.build(), STATE_CACHE); + case "maxkey" -> new AuthMaxKeyRequest(builder.build(), STATE_CACHE); + case "topiam" -> new AuthTopIamRequest(builder.build(), STATE_CACHE); + default -> throw new AuthException("未获取到有效的Auth配置"); + }; + } +} + diff --git a/ruoyi-common/ruoyi-common-social/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-social/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..fb6d9fa --- /dev/null +++ b/ruoyi-common/ruoyi-common-social/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +com.ruoyi.common.social.config.SocialAutoConfiguration diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysSocialController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysSocialController.java new file mode 100644 index 0000000..8ba2e6f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/system/SysSocialController.java @@ -0,0 +1,40 @@ +package com.ruoyi.system.controller.system; + +import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; +import com.ruoyi.common.core.core.domain.R; +import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.common.web.core.BaseController; +import com.ruoyi.system.domain.vo.SysSocialVo; +import com.ruoyi.system.service.ISysSocialService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 社会化关系 + * + * @author thiszhc + * @date 2023-06-16 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/social") +public class SysSocialController extends BaseController { + + @Resource + private ISysSocialService sysSocialService; + + /** + * 查询社会化关系列表 + */ + @GetMapping("/list") + public R> list() { + return R.ok(sysSocialService.selectListByUserId(LoginHelper.getUserId())); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysSocial.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysSocial.java new file mode 100644 index 0000000..3291a28 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysSocial.java @@ -0,0 +1,139 @@ +package com.ruoyi.system.domain; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.Table; +import com.ruoyi.common.orm.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 社会化关系对象 sys_social + * + * @author thiszhc + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Table("sys_social") +public class SysSocial extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @Id + private Long socialId; + + /** + * 用户ID + */ + private Long userId; + + /** + * 的唯一ID + */ + private String authId; + + /** + * 用户来源 + */ + private String source; + + /** + * 用户的授权令牌 + */ + private String accessToken; + + /** + * 用户的授权令牌的有效期,部分平台可能没有 + */ + private int expireIn; + + /** + * 刷新令牌,部分平台可能没有 + */ + private String refreshToken; + + /** + * 用户的 open id + */ + private String openId; + + /** + * 授权的第三方账号 + */ + private String userName; + + /** + * 授权的第三方昵称 + */ + private String nickName; + + /** + * 授权的第三方邮箱 + */ + private String email; + + /** + * 授权的第三方头像地址 + */ + private String avatar; + + /** + * 平台的授权信息,部分平台可能没有 + */ + private String accessCode; + + /** + * 用户的 unionid + */ + private String unionId; + + /** + * 授予的权限,部分平台可能没有 + */ + private String scope; + + /** + * 个别平台的授权信息,部分平台可能没有 + */ + private String tokenType; + + /** + * id token,部分平台可能没有 + */ + private String idToken; + + /** + * 小米平台用户的附带属性,部分平台可能没有 + */ + private String macAlgorithm; + + /** + * 小米平台用户的附带属性,部分平台可能没有 + */ + private String macKey; + + /** + * 用户的授权code,部分平台可能没有 + */ + private String code; + + /** + * Twitter平台用户的附带属性,部分平台可能没有 + */ + private String oauthToken; + + /** + * Twitter平台用户的附带属性,部分平台可能没有 + */ + private String oauthTokenSecret; + + /** + * 删除标志(0就代表存在 1就代表删除) + */ + private Integer delFlag; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysSocialBo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysSocialBo.java new file mode 100644 index 0000000..cfb9cbc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/SysSocialBo.java @@ -0,0 +1,142 @@ +package com.ruoyi.system.domain.bo; + +import com.ruoyi.common.orm.core.domain.BaseEntity; +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import com.ruoyi.system.domain.SysSocial; + +/** + * 社会化关系业务对象 sys_social + * + * @author Lion Li + */ +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysSocial.class, reverseConvertGenerate = false) +public class SysSocialBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空") + private Long socialId; + + /** + * 的唯一ID + */ + @NotBlank(message = "的唯一ID不能为空") + private String authId; + + /** + * 用户来源 + */ + @NotBlank(message = "用户来源不能为空") + private String source; + + /** + * 用户的授权令牌 + */ + @NotBlank(message = "用户的授权令牌不能为空") + private String accessToken; + + /** + * 用户的授权令牌的有效期,部分平台可能没有 + */ + private int expireIn; + + /** + * 刷新令牌,部分平台可能没有 + */ + private String refreshToken; + + /** + * 平台唯一id + */ + private String openId; + + /** + * 用户的 ID + */ + @NotBlank(message = "用户的 ID不能为空") + private Long userId; + + /** + * 平台的授权信息,部分平台可能没有 + */ + private String accessCode; + + /** + * 用户的 unionid + */ + private String unionId; + + /** + * 授予的权限,部分平台可能没有 + */ + private String scope; + + /** + * 授权的第三方账号 + */ + private String userName; + + /** + * 授权的第三方昵称 + */ + private String nickName; + + /** + * 授权的第三方邮箱 + */ + private String email; + + /** + * 授权的第三方头像地址 + */ + private String avatar; + + /** + * 个别平台的授权信息,部分平台可能没有 + */ + private String tokenType; + + /** + * id token,部分平台可能没有 + */ + private String idToken; + + /** + * 小米平台用户的附带属性,部分平台可能没有 + */ + private String macAlgorithm; + + /** + * 小米平台用户的附带属性,部分平台可能没有 + */ + private String macKey; + + /** + * 用户的授权code,部分平台可能没有 + */ + private String code; + + /** + * Twitter平台用户的附带属性,部分平台可能没有 + */ + private String oauthToken; + + /** + * Twitter平台用户的附带属性,部分平台可能没有 + */ + private String oauthTokenSecret; + + /** + * 删除标志(0就代表存在 1就代表删除) + */ + private Integer delFlag; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysSocialVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysSocialVo.java new file mode 100644 index 0000000..6dacfbe --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysSocialVo.java @@ -0,0 +1,140 @@ +package com.ruoyi.system.domain.vo; + +import com.ruoyi.common.orm.core.domain.BaseEntity; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import com.ruoyi.system.domain.SysSocial; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 社会化关系视图对象 sys_social + * + * @author thiszhc + */ +@Data +@AutoMapper(target = SysSocial.class) +public class SysSocialVo extends BaseEntity implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + private Long socialId; + + /** + * 用户ID + */ + private Long userId; + + /** + * 的唯一ID + */ + private String authId; + + /** + * 用户来源 + */ + private String source; + + /** + * 用户的授权令牌 + */ + private String accessToken; + + /** + * 用户的授权令牌的有效期,部分平台可能没有 + */ + private int expireIn; + + /** + * 刷新令牌,部分平台可能没有 + */ + private String refreshToken; + + /** + * 用户的 open id + */ + private String openId; + + /** + * 授权的第三方账号 + */ + private String userName; + + /** + * 授权的第三方昵称 + */ + private String nickName; + + /** + * 授权的第三方邮箱 + */ + private String email; + + /** + * 授权的第三方头像地址 + */ + private String avatar; + + + /** + * 平台的授权信息,部分平台可能没有 + */ + private String accessCode; + + /** + * 用户的 unionid + */ + private String unionId; + + /** + * 授予的权限,部分平台可能没有 + */ + private String scope; + + /** + * 个别平台的授权信息,部分平台可能没有 + */ + private String tokenType; + + /** + * id token,部分平台可能没有 + */ + private String idToken; + + /** + * 小米平台用户的附带属性,部分平台可能没有 + */ + private String macAlgorithm; + + /** + * 小米平台用户的附带属性,部分平台可能没有 + */ + private String macKey; + + /** + * 用户的授权code,部分平台可能没有 + */ + private String code; + + /** + * Twitter平台用户的附带属性,部分平台可能没有 + */ + private String oauthToken; + + /** + * Twitter平台用户的附带属性,部分平台可能没有 + */ + private String oauthTokenSecret; + + /** + * 删除标志(0就代表存在 1就代表删除) + */ + private Integer delFlag; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysSocialMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysSocialMapper.java new file mode 100644 index 0000000..6289d36 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysSocialMapper.java @@ -0,0 +1,15 @@ +package com.ruoyi.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.ruoyi.system.domain.SysSocial; +import org.apache.ibatis.annotations.Mapper; + +/** + * 社会化关系Mapper接口 + * + * @author thiszhc + */ +@Mapper +public interface SysSocialMapper extends BaseMapper { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java index ebfc201..08e1511 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java @@ -39,6 +39,14 @@ public interface ISysConfigService extends IBaseService */ boolean selectCaptchaEnabled(); + /** + * 获取注册开关(不走Mybatis-Flex租户插件) + * + * @param tenantId 租户id + * @return true开启,false关闭 + */ + boolean selectRegisterEnabled(Long tenantId); + /** * 查询参数配置列表 * diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysSocialService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysSocialService.java new file mode 100644 index 0000000..3011268 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysSocialService.java @@ -0,0 +1,57 @@ +package com.ruoyi.system.service; + +import com.ruoyi.common.orm.core.service.IBaseService; +import com.ruoyi.system.domain.SysSocial; +import com.ruoyi.system.domain.bo.SysSocialBo; +import com.ruoyi.system.domain.vo.SysSocialVo; + +import java.util.List; + +/** + * 社会化关系Service接口 + * + * @author thiszhc + */ +public interface ISysSocialService extends IBaseService { + + + /** + * 查询社会化关系 + */ + SysSocialVo queryById(Long socialId); + + /** + * 查询社会化关系列表 + */ + List queryList(); + + /** + * 查询社会化关系列表 + */ + List selectListByUserId(Long userId); + + /** + * 新增授权关系 + */ + Boolean insertByBo(SysSocialBo bo); + + /** + * 更新社会化关系 + */ + Boolean updateByBo(SysSocialBo bo); + + /** + * 删除社会化关系信息 + */ + Boolean deleteWithValidById(Long id); + + + /** + * 根据 authId 查询 SysSocial 表和 SysUser 表,返回 SysSocialAuthResult 映射的对象 + * @param authId 认证ID + * @return SysSocial + */ + List selectListByAuthId(String authId); + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java index d17e049..44bdd1b 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java @@ -13,8 +13,7 @@ import java.util.List; * * @author ruoyi */ -public interface ISysUserService extends IBaseService -{ +public interface ISysUserService extends IBaseService { /** * 根据条件分页查询用户列表 * @@ -56,21 +55,39 @@ public interface ISysUserService extends IBaseService SysUserVo selectUserByUserName(String userName); /** - * 登录时通过用户名、租户编号查询用户(不走Mybatis-Flex租户插件) + * 登录时通过租户编号、用户名查询用户(不走Mybatis-Flex租户插件) * * @param userName 用户名 * @param tenantId 租户编号 * @return 用户对象信息 */ - SysUserVo selectTenantUserByUserName(String userName,Long tenantId); + SysUserVo selectTenantUserByUserName(Long tenantId, String userName); /** - * 通过邮箱查询用户 + * 登录时通过租户编号、用户名查询用户(不走Mybatis-Flex租户插件) + * + * @param phonenumber 手机号 + * @param tenantId 租户编号 + * @return 用户对象信息 + */ + SysUserVo selectTenantUserByPhonenumber(Long tenantId, String phonenumber); + + /** + * 登录时通过租户编号、邮箱查询用户(不走Mybatis-Flex租户插件) * * @param email 邮箱 * @return 用户对象信息 */ - SysUserVo selectUserByEmail(String email); + SysUserVo selectTenantUserByEmail(Long tenantId, String email); + + /** + * 登录时通过租户编号、用户id查询用户(不走Mybatis-Flex租户插件) + * + * @param tenantId 租户编号 + * @param userId 用户id + * @return 用户对象信息 + */ + SysUserVo selectTenantUserById(Long tenantId, Long userId); /** * 通过用户ID查询用户 @@ -178,7 +195,7 @@ public interface ISysUserService extends IBaseService /** * 用户授权角色 * - * @param userId 用户ID + * @param userId 用户ID * @param roleIds 角色组 */ void insertUserAuth(Long userId, Long[] roleIds); @@ -227,9 +244,9 @@ public interface ISysUserService extends IBaseService /** * 导入用户数据 * - * @param userList 用户数据列表 + * @param userList 用户数据列表 * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据 - * @param operID 操作用户ID + * @param operID 操作用户ID * @return 结果 */ String importUser(List userList, Boolean isUpdateSupport, Long operID); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java index 22bcb69..0ed7976 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java @@ -2,6 +2,7 @@ package com.ruoyi.system.service.impl; import java.util.List; +import cn.hutool.core.util.ObjectUtil; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryWrapper; import com.ruoyi.common.core.constant.CacheNames; @@ -12,6 +13,7 @@ import com.ruoyi.common.orm.core.page.PageQuery; import com.ruoyi.common.orm.core.page.TableDataInfo; import com.ruoyi.common.orm.core.service.impl.BaseServiceImpl; import com.ruoyi.common.redis.utils.CacheUtils; +import com.ruoyi.common.tenant.helper.TenantHelper; import com.ruoyi.system.domain.bo.SysConfigBo; import com.ruoyi.system.domain.vo.SysConfigVo; import jakarta.annotation.Resource; @@ -84,6 +86,26 @@ public class SysConfigServiceImpl extends BaseServiceImpl { + QueryWrapper queryWrapper = query() + .where(SYS_CONFIG.TENANT_ID.eq(tenantId)) + .and(SYS_CONFIG.CONFIG_KEY.eq("sys.account.registerUser")); + SysConfig config = this.getOne(queryWrapper); + if (ObjectUtil.isNull(config)) { + return false; + } + return Convert.toBool(config.getConfigValue()); + }); + } + /** * 构造查询条件 * diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java index db13524..58e22f1 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java @@ -20,6 +20,7 @@ import com.ruoyi.common.orm.core.page.PageQuery; import com.ruoyi.common.orm.core.page.TableDataInfo; import com.ruoyi.common.orm.core.service.impl.BaseServiceImpl; import com.ruoyi.common.security.utils.LoginHelper; +import com.ruoyi.common.tenant.helper.TenantHelper; import com.ruoyi.system.domain.SysClient; import com.ruoyi.system.domain.bo.SysLogininforBo; import com.ruoyi.system.domain.vo.SysLogininforVo; @@ -109,7 +110,7 @@ public class SysLogininforServiceImpl extends BaseServiceImpl insertLogininfor(logininfor));//支持注册时的动态多租户 } private String getBlock(Object msg) { diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysSocialServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysSocialServiceImpl.java new file mode 100644 index 0000000..61ec6c3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysSocialServiceImpl.java @@ -0,0 +1,103 @@ +package com.ruoyi.system.service.impl; + +import com.mybatisflex.core.query.QueryWrapper; +import com.ruoyi.common.orm.core.service.impl.BaseServiceImpl; +import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; +import com.ruoyi.common.core.utils.MapstructUtils; +import com.ruoyi.system.domain.SysSocial; +import com.ruoyi.system.domain.bo.SysSocialBo; +import com.ruoyi.system.domain.vo.SysSocialVo; +import com.ruoyi.system.mapper.SysSocialMapper; +import com.ruoyi.system.service.ISysSocialService; +import org.springframework.stereotype.Service; + +import java.util.List; + +import static com.ruoyi.system.domain.table.SysSocialTableDef.SYS_SOCIAL; + +/** + * 社会化关系Service业务层处理 + * + * @author thiszhc + * @date 2023-06-12 + */ +@RequiredArgsConstructor +@Service +public class SysSocialServiceImpl extends BaseServiceImpl implements ISysSocialService { + + @Resource + private SysSocialMapper sysSocialMapper; + + + /** + * 查询社会化关系 + */ + @Override + public SysSocialVo queryById(Long socialId) { + return sysSocialMapper.selectOneWithRelationsByIdAs(socialId, SysSocialVo.class); + } + + /** + * 授权列表 + */ + @Override + public List queryList() { + return sysSocialMapper.selectListByQueryAs(QueryWrapper.create().from(SYS_SOCIAL), SysSocialVo.class); + } + + @Override + public List selectListByUserId(Long userId) { + return sysSocialMapper.selectListByQueryAs(QueryWrapper.create().from(SYS_SOCIAL).where(SYS_SOCIAL.USER_ID.eq(userId)), SysSocialVo.class); + } + + + /** + * 新增社会化关系 + */ + @Override + public Boolean insertByBo(SysSocialBo bo) { + SysSocial add = MapstructUtils.convert(bo, SysSocial.class); + validEntityBeforeSave(add); + return sysSocialMapper.insert(add, true) > 0; + } + + /** + * 更新社会化关系 + */ + @Override + public Boolean updateByBo(SysSocialBo bo) { + SysSocial update = MapstructUtils.convert(bo, SysSocial.class); + validEntityBeforeSave(update); + return sysSocialMapper.update(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(SysSocial entity) { + //TODO 做一些数据校验,如唯一约束 + } + + + /** + * 删除社会化关系 + */ + @Override + public Boolean deleteWithValidById(Long socialId) { + return sysSocialMapper.deleteById(socialId) > 0; + } + + + /** + * 根据 authId 查询用户信息 + * + * @param authId 认证id + * @return 授权信息 + */ + @Override + public List selectListByAuthId(String authId) { + return sysSocialMapper.selectListByQueryAs(QueryWrapper.create().from(SYS_SOCIAL).where(SYS_SOCIAL.AUTH_ID.eq(authId)), SysSocialVo.class); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java index 893423a..d90acd8 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java @@ -140,8 +140,7 @@ public class SysUserServiceImpl extends BaseServiceImpl SYS_DEPT.DEPT_ID, SYS_DEPT.PARENT_ID, SYS_DEPT.ANCESTORS, SYS_DEPT.DEPT_NAME, SYS_DEPT.ORDER_NUM, SYS_DEPT.LEADER, SYS_DEPT.STATUS.as("dept_status") )) .from(SYS_USER.as("u")) - .leftJoin(SYS_DEPT).as("d").on(SYS_DEPT.DEPT_ID.eq(SYS_USER.DEPT_ID)) - .where(SYS_USER.DEL_FLAG.eq(0)); + .leftJoin(SYS_DEPT).as("d").on(SYS_DEPT.DEPT_ID.eq(SYS_USER.DEPT_ID)); //.leftJoin(SYS_USER_ROLE).as("ur").on(SYS_USER_ROLE.USER_ID.eq(SYS_USER.USER_ID)) //.leftJoin(SYS_ROLE).as("r").on(SYS_ROLE.ROLE_ID.eq(SYS_USER_ROLE.ROLE_ID)); } @@ -276,12 +275,12 @@ public class SysUserServiceImpl extends BaseServiceImpl /** * 登录时通过用户名、租户编号查询用户(不走Mybatis-Flex租户插件) * - * @param userName 用户名 * @param tenantId 租户编号 + * @param userName 用户名 * @return 用户对象信息 */ @Override - public SysUserVo selectTenantUserByUserName(String userName, Long tenantId) { + public SysUserVo selectTenantUserByUserName(Long tenantId, String userName) { return TenantHelper.ignore(() -> { QueryWrapper queryWrapper = buildOneQueryWrapper() .where(SYS_USER.TENANT_ID.eq(tenantId)) @@ -291,19 +290,54 @@ public class SysUserServiceImpl extends BaseServiceImpl } /** - * 通过邮箱查询用户 + * 登录时通过用户名、租户编号查询用户(不走Mybatis-Flex租户插件) * + * @param tenantId 租户编号 + * @param phonenumber 手机号 + * @return 用户对象信息 + */ + @Override + public SysUserVo selectTenantUserByPhonenumber(Long tenantId, String phonenumber) { + return TenantHelper.ignore(() -> { + QueryWrapper queryWrapper = buildOneQueryWrapper() + .where(SYS_USER.TENANT_ID.eq(tenantId)) + .and(SYS_USER.PHONENUMBER.eq(phonenumber)); + return this.getOneAs(queryWrapper, SysUserVo.class); + }); + } + + /** + * 登录时通过租户编号、邮箱查询用户(不走Mybatis-Flex租户插件) + * + * @param tenantId 租户编号 * @param email 邮箱 * @return 用户对象信息 */ @Override - public SysUserVo selectUserByEmail(String email) { - QueryWrapper queryWrapper = buildOneQueryWrapper(); - queryWrapper.where(SYS_USER.DEL_FLAG.eq(0)); - if (StringUtils.isNotEmpty(email)) { - queryWrapper.and(SYS_USER.EMAIL.eq(email)); - } - return this.getOneAs(queryWrapper, SysUserVo.class); + public SysUserVo selectTenantUserByEmail(Long tenantId, String email) { + return TenantHelper.ignore(() -> { + QueryWrapper queryWrapper = buildOneQueryWrapper() + .where(SYS_USER.TENANT_ID.eq(tenantId)) + .and(SYS_USER.EMAIL.eq(email)); + return this.getOneAs(queryWrapper, SysUserVo.class); + }); + } + + /** + * 登录时通过租户编号、邮箱查询用户(不走Mybatis-Flex租户插件) + * + * @param tenantId 租户编号 + * @param userId 用户id + * @return 用户对象信息 + */ + @Override + public SysUserVo selectTenantUserById(Long tenantId, Long userId) { + return TenantHelper.ignore(() -> { + QueryWrapper queryWrapper = buildOneQueryWrapper() + .where(SYS_USER.TENANT_ID.eq(tenantId)) + .and(SYS_USER.USER_ID.eq(userId)); + return this.getOneAs(queryWrapper, SysUserVo.class); + }); } /** diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysSocialMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysSocialMapper.xml new file mode 100644 index 0000000..b734b77 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysSocialMapper.xml @@ -0,0 +1,7 @@ + + + + +