Commit 3c2b2faf20c4e201c2d51ded08207f57948d37ac
1 parent
c7d2e3b7
feat(auth): 实现UAA单点登录功能并集成用户同步
Showing
13 changed files
with
379 additions
and
123 deletions
urbanops-module-system/pom.xml
| ... | ... | @@ -123,7 +123,21 @@ |
| 123 | 123 | <artifactId>pinyin4j</artifactId> |
| 124 | 124 | <version>2.5.1</version> <!-- 稳定版本 --> |
| 125 | 125 | </dependency> |
| 126 | - | |
| 126 | + <dependency> | |
| 127 | + <groupId>com.auth0</groupId> | |
| 128 | + <artifactId>java-jwt</artifactId> | |
| 129 | + <version>3.8.1</version> | |
| 130 | + </dependency> | |
| 131 | + <dependency> | |
| 132 | + <groupId>io.jsonwebtoken</groupId> | |
| 133 | + <artifactId>jjwt</artifactId> | |
| 134 | + <version>0.9.1</version> | |
| 135 | + </dependency> | |
| 136 | + <dependency> | |
| 137 | + <groupId>com.smart.uaa</groupId> | |
| 138 | + <artifactId>sdk</artifactId> | |
| 139 | + <version>1.0.1</version> | |
| 140 | + </dependency> | |
| 127 | 141 | |
| 128 | 142 | </dependencies> |
| 129 | 143 | ... | ... |
urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/enums/social/SocialTypeEnum.java
| ... | ... | @@ -53,7 +53,11 @@ public enum SocialTypeEnum implements ArrayValuable<Integer> { |
| 53 | 53 | * @see <a href="https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html">接入文档</a> |
| 54 | 54 | */ |
| 55 | 55 | WECHAT_MINI_PROGRAM(34, "WECHAT_MINI_PROGRAM"), |
| 56 | - ; | |
| 56 | + | |
| 57 | + /** | |
| 58 | + * UAA | |
| 59 | + */ | |
| 60 | + UAA(35, "UAA"); | |
| 57 | 61 | |
| 58 | 62 | public static final Integer[] ARRAYS = Arrays.stream(values()).map(SocialTypeEnum::getType).toArray(Integer[]::new); |
| 59 | 63 | ... | ... |
urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/framework/justauth/core/AuthRequestFactory.java
| ... | ... | @@ -100,9 +100,9 @@ public class AuthRequestFactory { |
| 100 | 100 | AuthRequest authRequest = getDefaultRequest(source); |
| 101 | 101 | |
| 102 | 102 | // 如果获取不到则尝试取自定义的 |
| 103 | - if (authRequest == null) { | |
| 104 | - authRequest = getExtendRequest(properties.getExtend().getEnumClass(), source); | |
| 105 | - } | |
| 103 | +// if (authRequest == null) { | |
| 104 | +// authRequest = getExtendRequest(properties.getExtend().getEnumClass(), source); | |
| 105 | +// } | |
| 106 | 106 | |
| 107 | 107 | if (authRequest == null) { |
| 108 | 108 | throw new AuthException(AuthResponseStatus.UNSUPPORTED); |
| ... | ... | @@ -159,134 +159,136 @@ public class AuthRequestFactory { |
| 159 | 159 | * @return {@link AuthRequest} |
| 160 | 160 | */ |
| 161 | 161 | private AuthRequest getDefaultRequest(String source) { |
| 162 | - AuthDefaultSource authDefaultSource; | |
| 162 | + AuthSource authDefaultSource; | |
| 163 | 163 | |
| 164 | 164 | try { |
| 165 | 165 | authDefaultSource = EnumUtil.fromString(AuthDefaultSource.class, source.toUpperCase()); |
| 166 | 166 | } catch (IllegalArgumentException e) { |
| 167 | 167 | // 无自定义匹配 |
| 168 | - return null; | |
| 168 | + authDefaultSource = EnumUtil.fromString(CustomerAuthSource.class, source.toUpperCase()); | |
| 169 | 169 | } |
| 170 | 170 | |
| 171 | - AuthConfig config = properties.getType().get(authDefaultSource.name()); | |
| 171 | + AuthConfig config = properties.getType().get(authDefaultSource.getName()); | |
| 172 | 172 | // 找不到对应关系,直接返回空 |
| 173 | 173 | if (config == null) { |
| 174 | 174 | return null; |
| 175 | 175 | } |
| 176 | 176 | |
| 177 | 177 | // 配置 http config |
| 178 | - configureHttpConfig(authDefaultSource.name(), config, properties.getHttpConfig()); | |
| 178 | + configureHttpConfig(authDefaultSource.getName(), config, properties.getHttpConfig()); | |
| 179 | 179 | |
| 180 | - switch (authDefaultSource) { | |
| 181 | - case GITHUB: | |
| 180 | + switch (authDefaultSource.getName()) { | |
| 181 | + case "GITHUB": | |
| 182 | 182 | return new AuthGithubRequest(config, authStateCache); |
| 183 | - case WEIBO: | |
| 183 | + case "WEIBO": | |
| 184 | 184 | return new AuthWeiboRequest(config, authStateCache); |
| 185 | - case GITEE: | |
| 185 | + case "GITEE": | |
| 186 | 186 | return new AuthGiteeRequest(config, authStateCache); |
| 187 | - case DINGTALK: | |
| 187 | + case "DINGTALK": | |
| 188 | 188 | return new AuthDingTalkRequest(config, authStateCache); |
| 189 | - case DINGTALK_V2: | |
| 189 | + case "DINGTALK_V2": | |
| 190 | 190 | return new AuthDingTalkV2Request(config, authStateCache); |
| 191 | - case DINGTALK_ACCOUNT: | |
| 191 | + case "DINGTALK_ACCOUNT": | |
| 192 | 192 | return new AuthDingTalkAccountRequest(config, authStateCache); |
| 193 | - case BAIDU: | |
| 193 | + case "BAIDU": | |
| 194 | 194 | return new AuthBaiduRequest(config, authStateCache); |
| 195 | - case CSDN: | |
| 195 | + case "CSDN": | |
| 196 | 196 | return new AuthCsdnRequest(config, authStateCache); |
| 197 | - case CODING: | |
| 197 | + case "CODING": | |
| 198 | 198 | return new AuthCodingRequest(config, authStateCache); |
| 199 | - case OSCHINA: | |
| 199 | + case "OSCHINA": | |
| 200 | 200 | return new AuthOschinaRequest(config, authStateCache); |
| 201 | - case ALIPAY: | |
| 201 | + case "ALIPAY": | |
| 202 | 202 | return new AuthAlipayRequest(config, authStateCache); |
| 203 | - case QQ: | |
| 203 | + case "QQ": | |
| 204 | 204 | return new AuthQqRequest(config, authStateCache); |
| 205 | - case WECHAT_OPEN: | |
| 205 | + case "WECHAT_OPEN": | |
| 206 | 206 | return new AuthWeChatOpenRequest(config, authStateCache); |
| 207 | - case WECHAT_MP: | |
| 207 | + case "WECHAT_MP": | |
| 208 | 208 | return new AuthWeChatMpRequest(config, authStateCache); |
| 209 | - case TAOBAO: | |
| 209 | + case "TAOBAO": | |
| 210 | 210 | return new AuthTaobaoRequest(config, authStateCache); |
| 211 | - case GOOGLE: | |
| 211 | + case "GOOGLE": | |
| 212 | 212 | return new AuthGoogleRequest(config, authStateCache); |
| 213 | - case FACEBOOK: | |
| 213 | + case "FACEBOOK": | |
| 214 | 214 | return new AuthFacebookRequest(config, authStateCache); |
| 215 | - case DOUYIN: | |
| 215 | + case "DOUYIN": | |
| 216 | 216 | return new AuthDouyinRequest(config, authStateCache); |
| 217 | - case LINKEDIN: | |
| 217 | + case "LINKEDIN": | |
| 218 | 218 | return new AuthLinkedinRequest(config, authStateCache); |
| 219 | - case MICROSOFT: | |
| 219 | + case "MICROSOFT": | |
| 220 | 220 | return new AuthMicrosoftRequest(config, authStateCache); |
| 221 | - case MICROSOFT_CN: | |
| 221 | + case "MICROSOFT_CN": | |
| 222 | 222 | return new AuthMicrosoftCnRequest(config, authStateCache); |
| 223 | 223 | |
| 224 | - case MI: | |
| 224 | + case "MI": | |
| 225 | 225 | return new AuthMiRequest(config, authStateCache); |
| 226 | - case TOUTIAO: | |
| 226 | + case "TOUTIAO": | |
| 227 | 227 | return new AuthToutiaoRequest(config, authStateCache); |
| 228 | - case TEAMBITION: | |
| 228 | + case "TEAMBITION": | |
| 229 | 229 | return new AuthTeambitionRequest(config, authStateCache); |
| 230 | - case RENREN: | |
| 230 | + case "RENREN": | |
| 231 | 231 | return new AuthRenrenRequest(config, authStateCache); |
| 232 | - case PINTEREST: | |
| 232 | + case "PINTEREST": | |
| 233 | 233 | return new AuthPinterestRequest(config, authStateCache); |
| 234 | - case STACK_OVERFLOW: | |
| 234 | + case "STACK_OVERFLOW": | |
| 235 | 235 | return new AuthStackOverflowRequest(config, authStateCache); |
| 236 | - case HUAWEI: | |
| 236 | + case "HUAWEI": | |
| 237 | 237 | return new AuthHuaweiRequest(config, authStateCache); |
| 238 | - case HUAWEI_V3: | |
| 238 | + case "HUAWEI_V3": | |
| 239 | 239 | return new AuthHuaweiV3Request(config, authStateCache); |
| 240 | - case WECHAT_ENTERPRISE: | |
| 240 | + case "WECHAT_ENTERPRISE": | |
| 241 | 241 | return new AuthWeChatEnterpriseQrcodeRequest(config, authStateCache); |
| 242 | - case WECHAT_ENTERPRISE_V2: | |
| 242 | + case "WECHAT_ENTERPRISE_V2": | |
| 243 | 243 | return new AuthWeChatEnterpriseQrcodeV2Request(config, authStateCache); |
| 244 | - case WECHAT_ENTERPRISE_QRCODE_THIRD: | |
| 244 | + case "WECHAT_ENTERPRISE_QRCODE_THIRD": | |
| 245 | 245 | return new AuthWeChatEnterpriseThirdQrcodeRequest(config, authStateCache); |
| 246 | - case WECHAT_ENTERPRISE_WEB: | |
| 246 | + case "WECHAT_ENTERPRISE_WEB": | |
| 247 | 247 | return new AuthWeChatEnterpriseWebRequest(config, authStateCache); |
| 248 | - case KUJIALE: | |
| 248 | + case "KUJIALE": | |
| 249 | 249 | return new AuthKujialeRequest(config, authStateCache); |
| 250 | - case GITLAB: | |
| 250 | + case "GITLAB": | |
| 251 | 251 | return new AuthGitlabRequest(config, authStateCache); |
| 252 | - case MEITUAN: | |
| 252 | + case "MEITUAN": | |
| 253 | 253 | return new AuthMeituanRequest(config, authStateCache); |
| 254 | - case ELEME: | |
| 254 | + case "ELEME": | |
| 255 | 255 | return new AuthElemeRequest(config, authStateCache); |
| 256 | - case TWITTER: | |
| 256 | + case "TWITTER": | |
| 257 | 257 | return new AuthTwitterRequest(config, authStateCache); |
| 258 | - case FEISHU: | |
| 258 | + case "FEISHU": | |
| 259 | 259 | return new AuthFeishuRequest(config, authStateCache); |
| 260 | - case JD: | |
| 260 | + case "JD": | |
| 261 | 261 | return new AuthJdRequest(config, authStateCache); |
| 262 | - case ALIYUN: | |
| 262 | + case "ALIYUN": | |
| 263 | 263 | return new AuthAliyunRequest(config, authStateCache); |
| 264 | - case XMLY: | |
| 264 | + case "XMLY": | |
| 265 | 265 | return new AuthXmlyRequest(config, authStateCache); |
| 266 | - case AMAZON: | |
| 266 | + case "AMAZON": | |
| 267 | 267 | return new AuthAmazonRequest(config, authStateCache); |
| 268 | - case SLACK: | |
| 268 | + case "SLACK": | |
| 269 | 269 | return new AuthSlackRequest(config, authStateCache); |
| 270 | - case LINE: | |
| 270 | + case "LINE": | |
| 271 | 271 | return new AuthLineRequest(config, authStateCache); |
| 272 | - case OKTA: | |
| 272 | + case "OKTA": | |
| 273 | 273 | return new AuthOktaRequest(config, authStateCache); |
| 274 | - case PROGINN: | |
| 274 | + case "PROGINN": | |
| 275 | 275 | return new AuthProginnRequest(config,authStateCache); |
| 276 | - case AFDIAN: | |
| 276 | + case "AFDIAN": | |
| 277 | 277 | return new AuthAfDianRequest(config,authStateCache); |
| 278 | - case APPLE: | |
| 278 | + case "APPLE": | |
| 279 | 279 | return new AuthAppleRequest(config,authStateCache); |
| 280 | - case FIGMA: | |
| 280 | + case "FIGMA": | |
| 281 | 281 | return new AuthFigmaRequest(config,authStateCache); |
| 282 | - case WECHAT_MINI_PROGRAM: | |
| 282 | + case "WECHAT_MINI_PROGRAM": | |
| 283 | 283 | config.setIgnoreCheckRedirectUri(true); |
| 284 | 284 | config.setIgnoreCheckState(true); |
| 285 | 285 | return new AuthWechatMiniProgramRequest(config, authStateCache); |
| 286 | - case QQ_MINI_PROGRAM: | |
| 286 | + case "QQ_MINI_PROGRAM": | |
| 287 | 287 | config.setIgnoreCheckRedirectUri(true); |
| 288 | 288 | config.setIgnoreCheckState(true); |
| 289 | 289 | return new AuthQQMiniProgramRequest(config, authStateCache); |
| 290 | + case "UAA": | |
| 291 | + return new AuthUaaRequest(config, authStateCache); | |
| 290 | 292 | default: |
| 291 | 293 | return null; |
| 292 | 294 | } | ... | ... |
urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/framework/justauth/core/AuthUaaRequest.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.system.framework.justauth.core; | |
| 2 | + | |
| 3 | +import com.alibaba.fastjson.JSONObject; | |
| 4 | +import com.auth0.jwt.JWT; | |
| 5 | +import com.auth0.jwt.JWTVerifier; | |
| 6 | +import com.auth0.jwt.algorithms.Algorithm; | |
| 7 | +import com.auth0.jwt.interfaces.DecodedJWT; | |
| 8 | +import me.zhyd.oauth.cache.AuthStateCache; | |
| 9 | +import me.zhyd.oauth.config.AuthConfig; | |
| 10 | +import me.zhyd.oauth.enums.AuthUserGender; | |
| 11 | +import me.zhyd.oauth.exception.AuthException; | |
| 12 | +import me.zhyd.oauth.model.AuthCallback; | |
| 13 | +import me.zhyd.oauth.model.AuthToken; | |
| 14 | +import me.zhyd.oauth.model.AuthUser; | |
| 15 | +import me.zhyd.oauth.request.AuthDefaultRequest; | |
| 16 | +import org.springframework.core.io.ClassPathResource; | |
| 17 | + | |
| 18 | +import java.security.cert.Certificate; | |
| 19 | +import java.security.cert.CertificateFactory; | |
| 20 | +import java.security.interfaces.RSAPublicKey; | |
| 21 | + | |
| 22 | +import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 23 | +import static com.zteits.urbanops.module.system.enums.ErrorCodeConstants.AUTH_LOGIN_USER_DISABLED; | |
| 24 | + | |
| 25 | + | |
| 26 | +/** | |
| 27 | + * HRHB SSO 单点登录实现 | |
| 28 | + * | |
| 29 | + * @author gelinghu | |
| 30 | + */ | |
| 31 | +public class AuthUaaRequest extends AuthDefaultRequest { | |
| 32 | + | |
| 33 | + public AuthUaaRequest(AuthConfig config, AuthStateCache authStateCache) { | |
| 34 | + super(config, CustomerAuthSource.UAA, authStateCache); | |
| 35 | + } | |
| 36 | + | |
| 37 | + @Override | |
| 38 | + public AuthToken getAccessToken(AuthCallback authCallback) { | |
| 39 | + try { | |
| 40 | + // doPostAuthorizationCode 会使用 source 中配置的 accessToken URL | |
| 41 | + String response = this.doPostAuthorizationCode(authCallback.getCode()); | |
| 42 | + JSONObject accessTokenObject = JSONObject.parseObject(response); | |
| 43 | + this.checkResponse(accessTokenObject); | |
| 44 | + | |
| 45 | + return AuthToken.builder() | |
| 46 | + .accessToken(accessTokenObject.getString("access_token")) | |
| 47 | + .refreshToken(accessTokenObject.getString("refresh_token")) | |
| 48 | + .scope(accessTokenObject.getString("scope")) | |
| 49 | + .tokenType(accessTokenObject.getString("token_type")) | |
| 50 | + .expireIn(accessTokenObject.getIntValue("expires_in")) | |
| 51 | + .build(); | |
| 52 | + } catch (Exception e) { | |
| 53 | + // 记录详细的错误信息,便于排查问题 | |
| 54 | + throw new AuthException("获取访问令牌失败: " + e.getMessage(), e); | |
| 55 | + } | |
| 56 | + } | |
| 57 | + | |
| 58 | + @Override | |
| 59 | + public AuthUser getUserInfo(AuthToken authToken) { | |
| 60 | + CertificateFactory certificateFactory = null; | |
| 61 | + try { | |
| 62 | + certificateFactory = CertificateFactory.getInstance("X.509"); | |
| 63 | + // 读取cer公钥证书来配置解码器 | |
| 64 | + ClassPathResource resource = new ClassPathResource("pub.cer"); | |
| 65 | + Certificate certificate = certificateFactory.generateCertificate(resource.getInputStream()); | |
| 66 | + RSAPublicKey publicKey = (RSAPublicKey) certificate.getPublicKey(); | |
| 67 | + | |
| 68 | + Algorithm algorithm = Algorithm.RSA256(publicKey, null); | |
| 69 | + | |
| 70 | + JWTVerifier verifier = JWT.require(algorithm).acceptLeeway(60) | |
| 71 | + .build(); | |
| 72 | + // 解析 JWT | |
| 73 | + DecodedJWT decodedJWT = verifier.verify(authToken.getAccessToken()); | |
| 74 | + DecodedJWT jwt = JWT.decode(authToken.getAccessToken()); | |
| 75 | + String staffNo = jwt.getClaim("account").asString(); | |
| 76 | + return AuthUser.builder() | |
| 77 | + .rawUserInfo(null) | |
| 78 | + .uuid(staffNo) | |
| 79 | + .username(staffNo) | |
| 80 | + .avatar("") | |
| 81 | + .blog("") | |
| 82 | + .nickname(staffNo) | |
| 83 | + .company("") | |
| 84 | + .location("") | |
| 85 | + .email("") | |
| 86 | + .remark("") | |
| 87 | + .gender(AuthUserGender.UNKNOWN) | |
| 88 | + .token(authToken) | |
| 89 | + .source(this.source.toString()) | |
| 90 | + .build(); | |
| 91 | + } catch (Exception e) { | |
| 92 | + throw exception(AUTH_LOGIN_USER_DISABLED, "UAA登录失败"); | |
| 93 | + } | |
| 94 | + } | |
| 95 | + | |
| 96 | + /** | |
| 97 | + * 检查响应是否有错误 | |
| 98 | + */ | |
| 99 | + private void checkResponse(JSONObject object) { | |
| 100 | + if (object.containsKey("error")) { | |
| 101 | + throw new AuthException(object.getString("error_description")); | |
| 102 | + } | |
| 103 | + } | |
| 104 | +} | |
| 0 | 105 | \ No newline at end of file | ... | ... |
urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/framework/justauth/core/CustomerAuthSource.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.system.framework.justauth.core; | |
| 2 | + | |
| 3 | +import me.zhyd.oauth.config.AuthSource; | |
| 4 | + | |
| 5 | +public enum CustomerAuthSource implements AuthSource { | |
| 6 | + | |
| 7 | + UAA { | |
| 8 | + @Override | |
| 9 | + public String authorize() { | |
| 10 | + return "https://test.jichengshanshui.com.cn:28301/oauth2/authorize"; | |
| 11 | +// return "http://localhost:8080/oauth2/authorize"; | |
| 12 | +// return "https://uaa.jichengshanshui.com.cn:28201/oauth2/authorize"; | |
| 13 | + } | |
| 14 | + | |
| 15 | + @Override | |
| 16 | + public String accessToken() { | |
| 17 | + return "https://test.jichengshanshui.com.cn:28301/oauth2/token"; | |
| 18 | +// return "http://localhost:8080/oauth2/token"; | |
| 19 | +// return "https://uaa.jichengshanshui.com.cn:28201/oauth2/token"; | |
| 20 | + } | |
| 21 | + | |
| 22 | + @Override | |
| 23 | + public String userInfo() { | |
| 24 | + return "https://test.jichengshanshui.com.cn:28301/oauth2/userinfo"; | |
| 25 | +// return "http://localhost:8080/oauth2/userinfo"; | |
| 26 | +// return "https://uaa.jichengshanshui.com.cn:28201/oauth2/userinfo"; | |
| 27 | + } | |
| 28 | + | |
| 29 | + @Override | |
| 30 | + public String getName() { | |
| 31 | + return "UAA"; | |
| 32 | + } | |
| 33 | + | |
| 34 | + | |
| 35 | + @Override | |
| 36 | + public Class getTargetClass() { | |
| 37 | + return CustomerAuthSource.class; | |
| 38 | + } | |
| 39 | + } | |
| 40 | +} | ... | ... |
urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/auth/AdminAuthServiceImpl.java
| ... | ... | @@ -175,16 +175,27 @@ public class AdminAuthServiceImpl implements AdminAuthService { |
| 175 | 175 | // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号 |
| 176 | 176 | SocialUserRespDTO socialUser = socialUserService.getSocialUserByCode(UserTypeEnum.ADMIN.getValue(), reqVO.getType(), |
| 177 | 177 | reqVO.getCode(), reqVO.getState()); |
| 178 | - if (socialUser == null || socialUser.getUserId() == null) { | |
| 178 | + if (socialUser == null) { | |
| 179 | 179 | throw exception(AUTH_THIRD_LOGIN_NOT_BIND); |
| 180 | 180 | } |
| 181 | 181 | |
| 182 | 182 | // 获得用户 |
| 183 | - AdminUserDO user = userService.getUser(socialUser.getUserId()); | |
| 183 | + AdminUserDO user = null; | |
| 184 | + user = userService.getUserByUsername(socialUser.getOpenid()); | |
| 185 | + if (user == null) { | |
| 186 | + user = userService.getUserByMobile(socialUser.getOpenid()); | |
| 187 | + } | |
| 188 | + | |
| 184 | 189 | if (user == null) { |
| 185 | 190 | throw exception(USER_NOT_EXISTS); |
| 186 | 191 | } |
| 187 | 192 | |
| 193 | + if (socialUser.getUserId() == null) { | |
| 194 | + SocialUserBindReqDTO reqDTO = new SocialUserBindReqDTO(user.getId(), UserTypeEnum.ADMIN.getValue(), | |
| 195 | + reqVO.getType(), reqVO.getCode(), reqVO.getState()); | |
| 196 | + socialUserService.bindSocialUser(reqDTO); | |
| 197 | + } | |
| 198 | + | |
| 188 | 199 | // 创建 Token 令牌,记录登录日志 |
| 189 | 200 | return createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL); |
| 190 | 201 | } | ... | ... |
urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/oauth2/SsoProperies.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.system.service.oauth2; | |
| 2 | + | |
| 3 | +import lombok.Data; | |
| 4 | +import org.springframework.boot.context.properties.ConfigurationProperties; | |
| 5 | +import org.springframework.context.annotation.Configuration; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * Description: <p></p> | |
| 9 | + * <p> | |
| 10 | + * Author: gelinghu | |
| 11 | + * Date: 2025年05月14 15:28 | |
| 12 | + * @author gelinghu | |
| 13 | + */ | |
| 14 | + | |
| 15 | +@Data | |
| 16 | +@Configuration | |
| 17 | +@ConfigurationProperties(prefix = "sso.client") | |
| 18 | +public class SsoProperies { | |
| 19 | + | |
| 20 | + private String switchState; | |
| 21 | + | |
| 22 | + private String clientId; | |
| 23 | + | |
| 24 | + private String clientSecret; | |
| 25 | + | |
| 26 | + private String authorizeUrl; | |
| 27 | + | |
| 28 | + private String baseUrl; | |
| 29 | + | |
| 30 | + private String redirectUri; | |
| 31 | + | |
| 32 | + private String authorizationUri; | |
| 33 | + | |
| 34 | + private String tokenUri; | |
| 35 | + | |
| 36 | + private String jwtPublicKey; | |
| 37 | + | |
| 38 | + private String syncUserUri; | |
| 39 | +} | |
| 40 | + | |
| 41 | + | ... | ... |
urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/oauth2/SsoService.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.system.service.oauth2; | |
| 2 | + | |
| 3 | +import com.smart.sdk.sso.client.Oauth2Client; | |
| 4 | +import com.smart.sdk.sso.client.SsoOauth2Client; | |
| 5 | +import com.smart.sdk.sso.domain.SsoUserSyncVo; | |
| 6 | +import com.zteits.urbanops.framework.common.enums.CommonStatusEnum; | |
| 7 | +import com.zteits.urbanops.module.system.dal.dataobject.user.AdminUserDO; | |
| 8 | +import org.springframework.boot.context.properties.EnableConfigurationProperties; | |
| 9 | +import org.springframework.stereotype.Component; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * Description: <p></p> | |
| 13 | + * <p> | |
| 14 | + * Author: gelinghu | |
| 15 | + * Date: 2025年5月17 17:33 | |
| 16 | + */ | |
| 17 | +@Component | |
| 18 | +@EnableConfigurationProperties(SsoProperies.class) | |
| 19 | +public class SsoService { | |
| 20 | + | |
| 21 | + private SsoProperies ssoProperies; | |
| 22 | + | |
| 23 | + private Oauth2Client client; | |
| 24 | + | |
| 25 | + public SsoService(SsoProperies ssoProperies) { | |
| 26 | + this.ssoProperies = ssoProperies; | |
| 27 | + client = new SsoOauth2Client(ssoProperies.getClientId(), ssoProperies.getClientSecret(), ssoProperies.getBaseUrl(), ssoProperies.getRedirectUri()); | |
| 28 | + } | |
| 29 | + | |
| 30 | + public Oauth2Client getClient() { | |
| 31 | + return client; | |
| 32 | + } | |
| 33 | + | |
| 34 | + public SsoProperies getSsoProperies() { | |
| 35 | + return ssoProperies; | |
| 36 | + } | |
| 37 | + | |
| 38 | + public void syncUser(AdminUserDO user) { | |
| 39 | + SsoUserSyncVo ssoUserSyncVo = new SsoUserSyncVo(); | |
| 40 | + ssoUserSyncVo.setStaffNo(user.getMobile()) | |
| 41 | + .setAccount(user.getUsername()) | |
| 42 | + .setName(user.getNickname()) | |
| 43 | + .setEmail(user.getEmail()) | |
| 44 | + .setState(CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus()) ? 1 : 0); | |
| 45 | + getClient().syncUser(ssoUserSyncVo); | |
| 46 | + } | |
| 47 | + | |
| 48 | +} | |
| 49 | + | |
| 50 | + | ... | ... |
urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/user/AdminUserServiceImpl.java
| ... | ... | @@ -27,6 +27,7 @@ import com.zteits.urbanops.module.system.dal.mysql.user.AdminUserMapper; |
| 27 | 27 | import com.zteits.urbanops.module.system.service.dept.DeptService; |
| 28 | 28 | import com.zteits.urbanops.module.system.service.dept.PostService; |
| 29 | 29 | import com.zteits.urbanops.module.system.service.dict.DictDataService; |
| 30 | +import com.zteits.urbanops.module.system.service.oauth2.SsoService; | |
| 30 | 31 | import com.zteits.urbanops.module.system.service.permission.PermissionService; |
| 31 | 32 | import com.zteits.urbanops.module.system.service.tenant.TenantService; |
| 32 | 33 | import com.google.common.annotations.VisibleForTesting; |
| ... | ... | @@ -87,6 +88,10 @@ public class AdminUserServiceImpl implements AdminUserService { |
| 87 | 88 | @Resource |
| 88 | 89 | private DictDataService dictDataService; |
| 89 | 90 | |
| 91 | + @Resource | |
| 92 | + private SsoService ssoService; | |
| 93 | + | |
| 94 | + | |
| 90 | 95 | @Override |
| 91 | 96 | @Transactional(rollbackFor = Exception.class) |
| 92 | 97 | @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_CREATE_SUB_TYPE, bizNo = "{{#user.id}}", |
| ... | ... | @@ -115,6 +120,8 @@ public class AdminUserServiceImpl implements AdminUserService { |
| 115 | 120 | |
| 116 | 121 | // 3. 记录操作日志上下文 |
| 117 | 122 | LogRecordContext.putVariable("user", user); |
| 123 | + | |
| 124 | + ssoService.syncUser(user); | |
| 118 | 125 | return user.getId(); |
| 119 | 126 | } |
| 120 | 127 | |
| ... | ... | @@ -232,6 +239,8 @@ public class AdminUserServiceImpl implements AdminUserService { |
| 232 | 239 | updateObj.setId(id); |
| 233 | 240 | updateObj.setStatus(status); |
| 234 | 241 | userMapper.updateById(updateObj); |
| 242 | + | |
| 243 | + ssoService.syncUser(updateObj); | |
| 235 | 244 | } |
| 236 | 245 | |
| 237 | 246 | @Override |
| ... | ... | @@ -251,6 +260,8 @@ public class AdminUserServiceImpl implements AdminUserService { |
| 251 | 260 | |
| 252 | 261 | // 3. 记录操作日志上下文 |
| 253 | 262 | LogRecordContext.putVariable("user", user); |
| 263 | + | |
| 264 | + ssoService.syncUser(user); | |
| 254 | 265 | } |
| 255 | 266 | |
| 256 | 267 | @Override | ... | ... |
urbanops-server/src/main/resources/application-dev.yaml
| ... | ... | @@ -191,30 +191,27 @@ urbanops: |
| 191 | 191 | justauth: |
| 192 | 192 | enabled: true |
| 193 | 193 | type: |
| 194 | - DINGTALK: # 钉钉 | |
| 195 | - client-id: dingvrnreaje3yqvzhxg | |
| 196 | - client-secret: i8E6iZyDvZj51JIb0tYsYfVQYOks9Cq1lgryEjFRqC79P3iJcrxEwT6Qk2QvLrLI | |
| 197 | - ignore-check-redirect-uri: true | |
| 198 | - WECHAT_ENTERPRISE: # 企业微信 | |
| 199 | - client-id: wwd411c69a39ad2e54 | |
| 200 | - client-secret: 1wTb7hYxnpT2TUbIeHGXGo7T0odav1ic10mLdyyATOw | |
| 201 | - agent-id: 1000004 | |
| 202 | - ignore-check-redirect-uri: true | |
| 203 | - # noinspection SpringBootApplicationYaml | |
| 204 | - WECHAT_MINI_PROGRAM: # 微信小程序 | |
| 205 | - client-id: ${wx.miniapp.appid} | |
| 206 | - client-secret: ${wx.miniapp.secret} | |
| 207 | - ignore-check-redirect-uri: true | |
| 208 | - ignore-check-state: true # 微信小程序,不会使用到 state,所以不进行校验 | |
| 209 | - WECHAT_MP: # 微信公众号 | |
| 210 | - client-id: ${wx.mp.app-id} | |
| 211 | - client-secret: ${wx.mp.secret} | |
| 194 | + UAA: | |
| 195 | + client-id: schoms | |
| 196 | + client-secret: secret | |
| 197 | + redirect-uri: https://test.jichengshanshui.com.cn:28302/test/social-login?type=35 | |
| 212 | 198 | ignore-check-redirect-uri: true |
| 213 | 199 | cache: |
| 214 | 200 | type: REDIS |
| 215 | 201 | prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE:: |
| 216 | 202 | timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟 |
| 217 | 203 | |
| 204 | +sso: | |
| 205 | + client: | |
| 206 | + switchState: on | |
| 207 | + clientId: schoms | |
| 208 | + clientSecret: secret | |
| 209 | + # 前端授权地址(改为justauth,不再这儿配置) | |
| 210 | + authorizeUrl: | |
| 211 | + # sso 服务地址 | |
| 212 | + baseUrl: https://test.jichengshanshui.com.cn:28301 | |
| 213 | + # 登录成功后跳转地址 (改为justauth,不再这儿配置) | |
| 214 | + redirectUri: | |
| 218 | 215 | --- #################### iot相关配置 TODO 芋艿【IOT】:再瞅瞅 #################### |
| 219 | 216 | pf4j: |
| 220 | 217 | # pluginsDir: /tmp/ |
| ... | ... | @@ -235,17 +232,7 @@ flow: |
| 235 | 232 | - appid: wy |
| 236 | 233 | secret: x3z7t6l2g2t2i4w3x5e2e0s5y9e6d1y3 |
| 237 | 234 | url: https://pms.jichengshanshui.com.cn:9980/prod-api/task/third/report |
| 238 | -sso: | |
| 239 | - client: | |
| 240 | - switchState: on | |
| 241 | - clientId: schoms | |
| 242 | - clientSecret: FVwUBd3ZCrt6mMrZ | |
| 243 | - # 前端授权地址 | |
| 244 | - authorizeUrl: https://giomp.jichengshanshui.com.cn:28205/authorize | |
| 245 | - # sso 服务地址 | |
| 246 | - baseUrl: https://uaa.jichengshanshui.com.cn:28201 | |
| 247 | - # 登录成功后跳转地址 | |
| 248 | - redirectUri: https://giomp.jichengshanshui.com.cn:28205/prod-api/admin-api/sso/callback | |
| 235 | + | |
| 249 | 236 | # 微信公众号配置 |
| 250 | 237 | wechat: |
| 251 | 238 | mp: | ... | ... |
urbanops-server/src/main/resources/application-prod.yaml
| ... | ... | @@ -228,30 +228,32 @@ global: |
| 228 | 228 | justauth: |
| 229 | 229 | enabled: true |
| 230 | 230 | type: |
| 231 | - DINGTALK: # 钉钉 | |
| 232 | - client-id: dingvrnreaje3yqvzhxg | |
| 233 | - client-secret: i8E6iZyDvZj51JIb0tYsYfVQYOks9Cq1lgryEjFRqC79P3iJcrxEwT6Qk2QvLrLI | |
| 234 | - ignore-check-redirect-uri: true | |
| 235 | - WECHAT_ENTERPRISE: # 企业微信 | |
| 236 | - client-id: wwd411c69a39ad2e54 | |
| 237 | - client-secret: 1wTb7hYxnpT2TUbIeHGXGo7T0odav1ic10mLdyyATOw | |
| 238 | - agent-id: 1000004 | |
| 239 | - ignore-check-redirect-uri: true | |
| 240 | - # noinspection SpringBootApplicationYaml | |
| 241 | - WECHAT_MINI_PROGRAM: # 微信小程序 | |
| 242 | - client-id: ${wx.miniapp.appid} | |
| 243 | - client-secret: ${wx.miniapp.secret} | |
| 244 | - ignore-check-redirect-uri: true | |
| 245 | - ignore-check-state: true # 微信小程序,不会使用到 state,所以不进行校验 | |
| 246 | - WECHAT_MP: # 微信公众号 | |
| 247 | - client-id: ${wx.mp.app-id} | |
| 248 | - client-secret: ${wx.mp.secret} | |
| 231 | + UAA: | |
| 232 | + client-id: schoms | |
| 233 | + client-secret: FVwUBd3ZCrt6mMrZ | |
| 234 | + redirect-uri: https://giomp.jichengshanshui.com.cn:4080/social-login?type=35 | |
| 249 | 235 | ignore-check-redirect-uri: true |
| 250 | 236 | cache: |
| 251 | 237 | type: REDIS |
| 252 | 238 | prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE:: |
| 253 | 239 | timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟 |
| 254 | 240 | |
| 241 | +sso: | |
| 242 | + client: | |
| 243 | + switchState: on | |
| 244 | + clientId: schoms | |
| 245 | + clientSecret: FVwUBd3ZCrt6mMrZ | |
| 246 | + # 前端授权地址(改为justauth,不再这儿配置) | |
| 247 | + authorizeUrl: | |
| 248 | + # sso 服务地址 | |
| 249 | + baseUrl: https://uaa.jichengshanshui.com.cn:28201 | |
| 250 | + # 登录成功后跳转地址 (改为justauth,不再这儿配置) | |
| 251 | + redirectUri: | |
| 252 | + cache: | |
| 253 | + type: REDIS | |
| 254 | + prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE:: | |
| 255 | + timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟 | |
| 256 | + | |
| 255 | 257 | --- #################### iot相关配置 TODO 芋艿【IOT】:再瞅瞅 #################### |
| 256 | 258 | pf4j: |
| 257 | 259 | # pluginsDir: /tmp/ |
| ... | ... | @@ -272,17 +274,7 @@ flow: |
| 272 | 274 | - appid: wy |
| 273 | 275 | secret: x3z7t6l2g2t2i4w3x5e2e0s5y9e6d1y3 |
| 274 | 276 | url: https://pms.jichengshanshui.com.cn:9980/prod-api/task/third/report |
| 275 | -sso: | |
| 276 | - client: | |
| 277 | - switchState: on | |
| 278 | - clientId: schoms | |
| 279 | - clientSecret: FVwUBd3ZCrt6mMrZ | |
| 280 | - # 前端授权地址 | |
| 281 | - authorizeUrl: https://giomp.jichengshanshui.com.cn:28205/authorize | |
| 282 | - # sso 服务地址 | |
| 283 | - baseUrl: https://uaa.jichengshanshui.com.cn:28201 | |
| 284 | - # 登录成功后跳转地址 | |
| 285 | - redirectUri: https://giomp.jichengshanshui.com.cn:28205/prod-api/admin-api/sso/callback | |
| 277 | + | |
| 286 | 278 | # 微信公众号配置 |
| 287 | 279 | wechat: |
| 288 | 280 | mp: | ... | ... |
urbanops-server/src/main/resources/application.yaml
urbanops-server/src/main/resources/pub.cer
0 → 100644
No preview for this file type