集成JustAuth第三方登录组件
This commit is contained in:
parent
84be51d691
commit
3ae17b0657
9
pom.xml
9
pom.xml
@ -56,6 +56,8 @@
|
||||
<sms4j.version>3.1.1</sms4j.version>
|
||||
<!-- findbugs消除打包警告 -->
|
||||
<jsr305.version>3.0.2</jsr305.version>
|
||||
<!-- 三方授权认证 -->
|
||||
<justauth.version>1.16.6</justauth.version>
|
||||
|
||||
<!-- 插件版本 -->
|
||||
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
|
||||
@ -344,6 +346,13 @@
|
||||
<version>${jsr305.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JustAuth 的依赖配置-->
|
||||
<dependency>
|
||||
<groupId>me.zhyd.oauth</groupId>
|
||||
<artifactId>JustAuth</artifactId>
|
||||
<version>${justauth.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--Annotation Processor-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
@ -31,6 +31,12 @@
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 三方授权认证 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-social</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- PostgreSql -->
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
|
@ -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" +
|
||||
|
@ -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<String> 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<Void> socialCallback(@RequestBody SocialLoginBody loginBody) {
|
||||
// 获取第三方登录信息
|
||||
AuthResponse<AuthUser> 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<Void> 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<Void> 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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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<SysSocialVo> 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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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,9 +43,9 @@ public class SysRegisterService
|
||||
/**
|
||||
* 注册
|
||||
*/
|
||||
public void register(RegisterBody registerBody)
|
||||
{
|
||||
public void register(RegisterBody registerBody) {
|
||||
Long tenantId = registerBody.getTenantId();
|
||||
TenantHelper.dynamic(tenantId, () -> {
|
||||
String username = registerBody.getUsername();
|
||||
String password = registerBody.getPassword();
|
||||
// 校验用户类型是否存在
|
||||
@ -62,7 +62,9 @@ public class SysRegisterService
|
||||
sysUser.setPassword(BCrypt.hashpw(password));
|
||||
sysUser.setUserType(userType);
|
||||
|
||||
if (!userService.checkUserNameUnique(sysUser)) {
|
||||
boolean unique = userService.checkUserNameUnique(sysUser);
|
||||
|
||||
if (!unique) {
|
||||
throw new UserException("user.register.save.error", username);
|
||||
}
|
||||
boolean regFlag = userService.registerUser(sysUser, tenantId);
|
||||
@ -70,6 +72,7 @@ public class SysRegisterService
|
||||
throw new UserException("user.register.error");
|
||||
}
|
||||
recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.register.success"));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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,8 +93,7 @@ public class EmailAuthStrategy implements IAuthStrategy {
|
||||
}
|
||||
|
||||
private SysUserVo loadUserByEmail(Long tenantId, String email) {
|
||||
return TenantHelper.dynamic(tenantId, () -> {
|
||||
SysUserVo user =userService.selectUserByEmail(email);
|
||||
SysUserVo user = userService.selectTenantUserByEmail(tenantId, email);
|
||||
if (ObjectUtil.isNull(user)) {
|
||||
log.info("登录用户:{} 不存在.", email);
|
||||
throw new UserException("user.not.exists", email);
|
||||
@ -107,7 +102,6 @@ public class EmailAuthStrategy implements IAuthStrategy {
|
||||
throw new UserException("user.blocked", email);
|
||||
}
|
||||
return user;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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<AuthUser> response = SocialUtils.loginAuth(
|
||||
loginBody.getSource(), loginBody.getSocialCode(),
|
||||
loginBody.getSocialState(), socialProperties);
|
||||
if (!response.ok()) {
|
||||
throw new ServiceException(response.getMsg());
|
||||
}
|
||||
AuthUser authUserData = response.getData();
|
||||
|
||||
List<SysSocialVo> list = sysSocialService.selectListByAuthId(authUserData.getSource() + authUserData.getUuid());
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
throw new ServiceException("你还没有绑定第三方账号,绑定后才可以登录!");
|
||||
}
|
||||
Optional<SysSocialVo> 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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -25,6 +25,7 @@
|
||||
<module>ruoyi-common-redis</module>
|
||||
<module>ruoyi-common-security</module>
|
||||
<module>ruoyi-common-sms</module>
|
||||
<module>ruoyi-common-social</module>
|
||||
<module>ruoyi-common-springdoc</module>
|
||||
<module>ruoyi-common-tenant</module>
|
||||
<module>ruoyi-common-web</module>
|
||||
|
@ -110,6 +110,13 @@
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 三方授权认证模块 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-social</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 接口模块 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
|
@ -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;
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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("/**")
|
||||
|
34
ruoyi-common/ruoyi-common-social/pom.xml
Normal file
34
ruoyi-common/ruoyi-common-social/pom.xml
Normal file
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ruoyi-common-social</artifactId>
|
||||
|
||||
<description>
|
||||
ruoyi-common-social 三方授权认证
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>me.zhyd.oauth</groupId>
|
||||
<artifactId>JustAuth</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-json</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-redis</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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<String> scopes;
|
||||
|
||||
}
|
@ -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<String, SocialLoginConfigProperties> type;
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthMaxKeyRequest.class;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthTopIamRequest.class;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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<AuthUser> 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配置");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
com.ruoyi.common.social.config.SocialAutoConfiguration
|
@ -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<SysSocialVo>> list() {
|
||||
return R.ok(sysSocialService.selectListByUserId(LoginHelper.getUserId()));
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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<SysSocial> {
|
||||
|
||||
}
|
@ -39,6 +39,14 @@ public interface ISysConfigService extends IBaseService<SysConfig>
|
||||
*/
|
||||
boolean selectCaptchaEnabled();
|
||||
|
||||
/**
|
||||
* 获取注册开关(不走Mybatis-Flex租户插件)
|
||||
*
|
||||
* @param tenantId 租户id
|
||||
* @return true开启,false关闭
|
||||
*/
|
||||
boolean selectRegisterEnabled(Long tenantId);
|
||||
|
||||
/**
|
||||
* 查询参数配置列表
|
||||
*
|
||||
|
@ -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<SysSocial> {
|
||||
|
||||
|
||||
/**
|
||||
* 查询社会化关系
|
||||
*/
|
||||
SysSocialVo queryById(Long socialId);
|
||||
|
||||
/**
|
||||
* 查询社会化关系列表
|
||||
*/
|
||||
List<SysSocialVo> queryList();
|
||||
|
||||
/**
|
||||
* 查询社会化关系列表
|
||||
*/
|
||||
List<SysSocialVo> 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<SysSocialVo> selectListByAuthId(String authId);
|
||||
|
||||
|
||||
}
|
@ -13,8 +13,7 @@ import java.util.List;
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public interface ISysUserService extends IBaseService<SysUser>
|
||||
{
|
||||
public interface ISysUserService extends IBaseService<SysUser> {
|
||||
/**
|
||||
* 根据条件分页查询用户列表
|
||||
*
|
||||
@ -56,21 +55,39 @@ public interface ISysUserService extends IBaseService<SysUser>
|
||||
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查询用户
|
||||
|
@ -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<SysConfigMapper, SysCo
|
||||
return Convert.toBool(captchaEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取注册开关(不走Mybatis-Flex租户插件)
|
||||
*
|
||||
* @param tenantId 租户id
|
||||
* @return true开启,false关闭
|
||||
*/
|
||||
@Override
|
||||
public boolean selectRegisterEnabled(Long tenantId) {
|
||||
return TenantHelper.ignore(() -> {
|
||||
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());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造查询条件
|
||||
*
|
||||
|
@ -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<SysLogininforMappe
|
||||
logininfor.setStatus(Constants.FAIL);
|
||||
}
|
||||
// 插入数据
|
||||
insertLogininfor(logininfor);
|
||||
TenantHelper.dynamic(logininforEvent.getTenantId(), () -> insertLogininfor(logininfor));//支持注册时的动态多租户
|
||||
}
|
||||
|
||||
private String getBlock(Object msg) {
|
||||
|
@ -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<SysSocialMapper, SysSocial> implements ISysSocialService {
|
||||
|
||||
@Resource
|
||||
private SysSocialMapper sysSocialMapper;
|
||||
|
||||
|
||||
/**
|
||||
* 查询社会化关系
|
||||
*/
|
||||
@Override
|
||||
public SysSocialVo queryById(Long socialId) {
|
||||
return sysSocialMapper.selectOneWithRelationsByIdAs(socialId, SysSocialVo.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 授权列表
|
||||
*/
|
||||
@Override
|
||||
public List<SysSocialVo> queryList() {
|
||||
return sysSocialMapper.selectListByQueryAs(QueryWrapper.create().from(SYS_SOCIAL), SysSocialVo.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SysSocialVo> 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<SysSocialVo> selectListByAuthId(String authId) {
|
||||
return sysSocialMapper.selectListByQueryAs(QueryWrapper.create().from(SYS_SOCIAL).where(SYS_SOCIAL.AUTH_ID.eq(authId)), SysSocialVo.class);
|
||||
}
|
||||
|
||||
}
|
@ -140,8 +140,7 @@ public class SysUserServiceImpl extends BaseServiceImpl<SysUserMapper, SysUser>
|
||||
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<SysUserMapper, SysUser>
|
||||
/**
|
||||
* 登录时通过用户名、租户编号查询用户(不走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<SysUserMapper, SysUser>
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过邮箱查询用户
|
||||
* 登录时通过用户名、租户编号查询用户(不走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));
|
||||
}
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.system.mapper.SysSocialMapper">
|
||||
|
||||
</mapper>
|
Loading…
Reference in New Issue
Block a user