From 18e919bde3d925ee76fe29c7a6621c2716b1e4e4 Mon Sep 17 00:00:00 2001 From: baoshiwei <baoshiwei@shlanbao.cn> Date: 星期五, 21 三月 2025 09:43:31 +0800 Subject: [PATCH] feat(social): 添加 Keycloak社交登录支持 --- ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java | 159 ++++++++++++++++++++++++++++++++++------------------- 1 files changed, 102 insertions(+), 57 deletions(-) diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java b/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java index 4da2bb0..5966195 100644 --- a/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java @@ -3,40 +3,37 @@ 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.lang.Opt; import cn.hutool.core.util.ObjectUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import com.baomidou.lock.annotation.Lock4j; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import me.zhyd.oauth.model.AuthUser; +import org.dromara.common.core.constant.CacheConstants; import org.dromara.common.core.constant.Constants; -import org.dromara.common.core.constant.GlobalConstants; +import org.dromara.common.core.constant.SystemConstants; import org.dromara.common.core.constant.TenantConstants; -import org.dromara.common.core.domain.R; +import org.dromara.common.core.domain.dto.PostDTO; import org.dromara.common.core.domain.dto.RoleDTO; import org.dromara.common.core.domain.model.LoginUser; import org.dromara.common.core.enums.LoginType; -import org.dromara.common.core.enums.TenantStatus; -import org.dromara.common.core.enums.UserStatus; +import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.exception.user.UserException; -import org.dromara.common.core.utils.DateUtils; -import org.dromara.common.core.utils.MessageUtils; -import org.dromara.common.core.utils.ServletUtils; -import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.*; import org.dromara.common.log.event.LogininforEvent; +import org.dromara.common.mybatis.helper.DataPermissionHelper; import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.tenant.exception.TenantException; import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.system.domain.SysUser; import org.dromara.system.domain.bo.SysSocialBo; -import org.dromara.system.domain.vo.SysTenantVo; -import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.domain.vo.*; import org.dromara.system.mapper.SysUserMapper; -import org.dromara.system.service.ISysPermissionService; -import org.dromara.system.service.ISysSocialService; -import org.dromara.system.service.ISysTenantService; -import org.dromara.web.domain.vo.LoginVo; -import org.springframework.beans.BeanUtils; +import org.dromara.system.service.*; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -55,6 +52,12 @@ @Service public class SysLoginService { + @Value("${justauth.type.keycloak.server-url}") + private String keycloakServerUrl; + + @Value("${justauth.type.keycloak.realm}") + private String keycloakRealm; + @Value("${user.password.maxRetryCount}") private Integer maxRetryCount; @@ -64,25 +67,48 @@ private final ISysTenantService tenantService; private final ISysPermissionService permissionService; private final ISysSocialService sysSocialService; + private final ISysRoleService roleService; + private final ISysDeptService deptService; + private final ISysPostService postService; private final SysUserMapper userMapper; - /** * 缁戝畾绗笁鏂圭敤鎴� + * * @param authUserData 鎺堟潈鍝嶅簲瀹炰綋 - * @return 缁熶竴鍝嶅簲瀹炰綋 */ - public R<LoginVo> sociaRegister(AuthUser authUserData ){ - SysSocialBo bo = new SysSocialBo(); - bo.setUserId(LoginHelper.getUserId()); - bo.setAuthId(authUserData.getSource() + authUserData.getUuid()); + @Lock4j + public void socialRegister(AuthUser authUserData) { + String authId = authUserData.getSource() + authUserData.getUuid(); + // 绗笁鏂圭敤鎴蜂俊鎭� + SysSocialBo bo = BeanUtil.toBean(authUserData, SysSocialBo.class); + BeanUtil.copyProperties(authUserData.getToken(), bo); + Long userId = LoginHelper.getUserId(); + bo.setUserId(userId); + bo.setAuthId(authId); bo.setOpenId(authUserData.getUuid()); bo.setUserName(authUserData.getUsername()); - BeanUtils.copyProperties(authUserData, bo); - BeanUtils.copyProperties(authUserData.getToken(), bo); - sysSocialService.insertByBo(bo); - return R.ok(); + bo.setNickName(authUserData.getNickname()); + List<SysSocialVo> checkList = sysSocialService.selectByAuthId(authId); + if (CollUtil.isNotEmpty(checkList)) { + throw new ServiceException("姝や笁鏂硅处鍙峰凡缁忚缁戝畾!"); + } + // 鏌ヨ鏄惁宸茬粡缁戝畾鐢ㄦ埛 + SysSocialBo params = new SysSocialBo(); + params.setUserId(userId); + params.setSource(bo.getSource()); + List<SysSocialVo> list = sysSocialService.queryList(params); + if (CollUtil.isEmpty(list)) { + // 娌℃湁缁戝畾鐢ㄦ埛, 鏂板鐢ㄦ埛淇℃伅 + sysSocialService.insertByBo(bo); + } else { + // 鏇存柊鐢ㄦ埛淇℃伅 + bo.setId(list.get(0).getId()); + sysSocialService.updateByBo(bo); + // 濡傛灉瑕佺粦瀹氱殑骞冲彴璐﹀彿宸茬粡琚粦瀹氳繃浜� 鏄惁鎶涘紓甯歌嚜琛屽喅鏂� + // throw new ServiceException("姝ゅ钩鍙拌处鍙峰凡缁忚缁戝畾!"); + } } @@ -92,13 +118,40 @@ public void logout() { try { LoginUser loginUser = LoginHelper.getLoginUser(); + if (ObjectUtil.isNull(loginUser)) { + return; + } if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) { // 瓒呯骇绠$悊鍛� 鐧诲嚭娓呴櫎鍔ㄦ�佺鎴� TenantHelper.clearDynamic(); } - StpUtil.logout(); recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success")); + // 鏂板Keycloak鐧诲嚭閫昏緫 + + Long userId = loginUser.getUserId(); + + SysSocialVo social = sysSocialService.selectByUserId(userId); + if (social == null) { + return; + } + + String logoutUrl = keycloakServerUrl + "/realms/" + keycloakRealm + "/protocol/openid-connect/logout"; + HttpRequest request = HttpRequest.get(logoutUrl) + .form("refresh_token", social.getRefreshToken()) + .form("id_token_hint", social.getIdToken()); + + + HttpResponse response = request.execute(); + if (response.isOk()) { + System.out.println("1234"); + } + } catch (NotLoginException ignored) { + } finally { + try { + StpUtil.logout(); + } catch (NotLoginException ignored) { + } } } @@ -120,40 +173,29 @@ SpringUtils.context().publishEvent(logininforEvent); } - - private SysUserVo loadUserByUsername(String tenantId, String username) { - SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>() - .select(SysUser::getUserName, SysUser::getStatus) - .eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId) - .eq(SysUser::getUserName, username)); - if (ObjectUtil.isNull(user)) { - log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", username); - throw new UserException("user.not.exists", username); - } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { - log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", username); - throw new UserException("user.blocked", username); - } - if (TenantHelper.isEnable()) { - return userMapper.selectTenantUserByUserName(username, tenantId); - } - return userMapper.selectUserByUserName(username); - } - /** * 鏋勫缓鐧诲綍鐢ㄦ埛 */ public LoginUser buildLoginUser(SysUserVo user) { LoginUser loginUser = new LoginUser(); + Long userId = user.getUserId(); loginUser.setTenantId(user.getTenantId()); - loginUser.setUserId(user.getUserId()); + loginUser.setUserId(userId); loginUser.setDeptId(user.getDeptId()); loginUser.setUsername(user.getUserName()); + loginUser.setNickname(user.getNickName()); loginUser.setUserType(user.getUserType()); - loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId())); - loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId())); - loginUser.setDeptName(ObjectUtil.isNull(user.getDept()) ? "" : user.getDept().getDeptName()); - List<RoleDTO> roles = BeanUtil.copyToList(user.getRoles(), RoleDTO.class); - loginUser.setRoles(roles); + loginUser.setMenuPermission(permissionService.getMenuPermission(userId)); + loginUser.setRolePermission(permissionService.getRolePermission(userId)); + if (ObjectUtil.isNotNull(user.getDeptId())) { + Opt<SysDeptVo> deptOpt = Opt.of(user.getDeptId()).map(deptService::selectDeptById); + loginUser.setDeptName(deptOpt.map(SysDeptVo::getDeptName).orElse(StringUtils.EMPTY)); + loginUser.setDeptCategory(deptOpt.map(SysDeptVo::getDeptCategory).orElse(StringUtils.EMPTY)); + } + List<SysRoleVo> roles = roleService.selectRolesByUserId(userId); + List<SysPostVo> posts = postService.selectPostsByUserId(userId); + loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class)); + loginUser.setPosts(BeanUtil.copyToList(posts, PostDTO.class)); return loginUser; } @@ -162,20 +204,20 @@ * * @param userId 鐢ㄦ埛ID */ - public void recordLoginInfo(Long userId) { + public void recordLoginInfo(Long userId, String ip) { SysUser sysUser = new SysUser(); sysUser.setUserId(userId); - sysUser.setLoginIp(ServletUtils.getClientIP()); + sysUser.setLoginIp(ip); sysUser.setLoginDate(DateUtils.getNowDate()); sysUser.setUpdateBy(userId); - userMapper.updateById(sysUser); + DataPermissionHelper.ignore(() -> userMapper.updateById(sysUser)); } /** * 鐧诲綍鏍¢獙 */ public void checkLogin(LoginType loginType, String tenantId, String username, Supplier<Boolean> supplier) { - String errorKey = GlobalConstants.PWD_ERR_CNT_KEY + username; + String errorKey = CacheConstants.PWD_ERR_CNT_KEY + username; String loginFail = Constants.LOGIN_FAIL; // 鑾峰彇鐢ㄦ埛鐧诲綍閿欒娆℃暟锛岄粯璁や负0 (鍙嚜瀹氫箟闄愬埗绛栫暐 渚嬪: key + username + ip) @@ -214,6 +256,9 @@ if (!TenantHelper.isEnable()) { return; } + if (StringUtils.isBlank(tenantId)) { + throw new TenantException("tenant.number.not.blank"); + } if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) { return; } @@ -221,7 +266,7 @@ if (ObjectUtil.isNull(tenant)) { log.info("鐧诲綍绉熸埛锛歿} 涓嶅瓨鍦�.", tenantId); throw new TenantException("tenant.not.exists"); - } else if (TenantStatus.DISABLE.getCode().equals(tenant.getStatus())) { + } else if (SystemConstants.DISABLE.equals(tenant.getStatus())) { log.info("鐧诲綍绉熸埛锛歿} 宸茶鍋滅敤.", tenantId); throw new TenantException("tenant.blocked"); } else if (ObjectUtil.isNotNull(tenant.getExpireTime()) -- Gitblit v1.9.3