Commit 3c2b2faf20c4e201c2d51ded08207f57948d37ac

Authored by 戈灵虎
1 parent c7d2e3b7

feat(auth): 实现UAA单点登录功能并集成用户同步

urbanops-module-system/pom.xml
@@ -123,7 +123,21 @@ @@ -123,7 +123,21 @@
123 <artifactId>pinyin4j</artifactId> 123 <artifactId>pinyin4j</artifactId>
124 <version>2.5.1</version> <!-- 稳定版本 --> 124 <version>2.5.1</version> <!-- 稳定版本 -->
125 </dependency> 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 </dependencies> 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&lt;Integer&gt; { @@ -53,7 +53,11 @@ public enum SocialTypeEnum implements ArrayValuable&lt;Integer&gt; {
53 * @see <a href="https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html">接入文档</a> 53 * @see <a href="https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html">接入文档</a>
54 */ 54 */
55 WECHAT_MINI_PROGRAM(34, "WECHAT_MINI_PROGRAM"), 55 WECHAT_MINI_PROGRAM(34, "WECHAT_MINI_PROGRAM"),
56 - ; 56 +
  57 + /**
  58 + * UAA
  59 + */
  60 + UAA(35, "UAA");
57 61
58 public static final Integer[] ARRAYS = Arrays.stream(values()).map(SocialTypeEnum::getType).toArray(Integer[]::new); 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,9 +100,9 @@ public class AuthRequestFactory {
100 AuthRequest authRequest = getDefaultRequest(source); 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 if (authRequest == null) { 107 if (authRequest == null) {
108 throw new AuthException(AuthResponseStatus.UNSUPPORTED); 108 throw new AuthException(AuthResponseStatus.UNSUPPORTED);
@@ -159,134 +159,136 @@ public class AuthRequestFactory { @@ -159,134 +159,136 @@ public class AuthRequestFactory {
159 * @return {@link AuthRequest} 159 * @return {@link AuthRequest}
160 */ 160 */
161 private AuthRequest getDefaultRequest(String source) { 161 private AuthRequest getDefaultRequest(String source) {
162 - AuthDefaultSource authDefaultSource; 162 + AuthSource authDefaultSource;
163 163
164 try { 164 try {
165 authDefaultSource = EnumUtil.fromString(AuthDefaultSource.class, source.toUpperCase()); 165 authDefaultSource = EnumUtil.fromString(AuthDefaultSource.class, source.toUpperCase());
166 } catch (IllegalArgumentException e) { 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 if (config == null) { 173 if (config == null) {
174 return null; 174 return null;
175 } 175 }
176 176
177 // 配置 http config 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 return new AuthGithubRequest(config, authStateCache); 182 return new AuthGithubRequest(config, authStateCache);
183 - case WEIBO: 183 + case "WEIBO":
184 return new AuthWeiboRequest(config, authStateCache); 184 return new AuthWeiboRequest(config, authStateCache);
185 - case GITEE: 185 + case "GITEE":
186 return new AuthGiteeRequest(config, authStateCache); 186 return new AuthGiteeRequest(config, authStateCache);
187 - case DINGTALK: 187 + case "DINGTALK":
188 return new AuthDingTalkRequest(config, authStateCache); 188 return new AuthDingTalkRequest(config, authStateCache);
189 - case DINGTALK_V2: 189 + case "DINGTALK_V2":
190 return new AuthDingTalkV2Request(config, authStateCache); 190 return new AuthDingTalkV2Request(config, authStateCache);
191 - case DINGTALK_ACCOUNT: 191 + case "DINGTALK_ACCOUNT":
192 return new AuthDingTalkAccountRequest(config, authStateCache); 192 return new AuthDingTalkAccountRequest(config, authStateCache);
193 - case BAIDU: 193 + case "BAIDU":
194 return new AuthBaiduRequest(config, authStateCache); 194 return new AuthBaiduRequest(config, authStateCache);
195 - case CSDN: 195 + case "CSDN":
196 return new AuthCsdnRequest(config, authStateCache); 196 return new AuthCsdnRequest(config, authStateCache);
197 - case CODING: 197 + case "CODING":
198 return new AuthCodingRequest(config, authStateCache); 198 return new AuthCodingRequest(config, authStateCache);
199 - case OSCHINA: 199 + case "OSCHINA":
200 return new AuthOschinaRequest(config, authStateCache); 200 return new AuthOschinaRequest(config, authStateCache);
201 - case ALIPAY: 201 + case "ALIPAY":
202 return new AuthAlipayRequest(config, authStateCache); 202 return new AuthAlipayRequest(config, authStateCache);
203 - case QQ: 203 + case "QQ":
204 return new AuthQqRequest(config, authStateCache); 204 return new AuthQqRequest(config, authStateCache);
205 - case WECHAT_OPEN: 205 + case "WECHAT_OPEN":
206 return new AuthWeChatOpenRequest(config, authStateCache); 206 return new AuthWeChatOpenRequest(config, authStateCache);
207 - case WECHAT_MP: 207 + case "WECHAT_MP":
208 return new AuthWeChatMpRequest(config, authStateCache); 208 return new AuthWeChatMpRequest(config, authStateCache);
209 - case TAOBAO: 209 + case "TAOBAO":
210 return new AuthTaobaoRequest(config, authStateCache); 210 return new AuthTaobaoRequest(config, authStateCache);
211 - case GOOGLE: 211 + case "GOOGLE":
212 return new AuthGoogleRequest(config, authStateCache); 212 return new AuthGoogleRequest(config, authStateCache);
213 - case FACEBOOK: 213 + case "FACEBOOK":
214 return new AuthFacebookRequest(config, authStateCache); 214 return new AuthFacebookRequest(config, authStateCache);
215 - case DOUYIN: 215 + case "DOUYIN":
216 return new AuthDouyinRequest(config, authStateCache); 216 return new AuthDouyinRequest(config, authStateCache);
217 - case LINKEDIN: 217 + case "LINKEDIN":
218 return new AuthLinkedinRequest(config, authStateCache); 218 return new AuthLinkedinRequest(config, authStateCache);
219 - case MICROSOFT: 219 + case "MICROSOFT":
220 return new AuthMicrosoftRequest(config, authStateCache); 220 return new AuthMicrosoftRequest(config, authStateCache);
221 - case MICROSOFT_CN: 221 + case "MICROSOFT_CN":
222 return new AuthMicrosoftCnRequest(config, authStateCache); 222 return new AuthMicrosoftCnRequest(config, authStateCache);
223 223
224 - case MI: 224 + case "MI":
225 return new AuthMiRequest(config, authStateCache); 225 return new AuthMiRequest(config, authStateCache);
226 - case TOUTIAO: 226 + case "TOUTIAO":
227 return new AuthToutiaoRequest(config, authStateCache); 227 return new AuthToutiaoRequest(config, authStateCache);
228 - case TEAMBITION: 228 + case "TEAMBITION":
229 return new AuthTeambitionRequest(config, authStateCache); 229 return new AuthTeambitionRequest(config, authStateCache);
230 - case RENREN: 230 + case "RENREN":
231 return new AuthRenrenRequest(config, authStateCache); 231 return new AuthRenrenRequest(config, authStateCache);
232 - case PINTEREST: 232 + case "PINTEREST":
233 return new AuthPinterestRequest(config, authStateCache); 233 return new AuthPinterestRequest(config, authStateCache);
234 - case STACK_OVERFLOW: 234 + case "STACK_OVERFLOW":
235 return new AuthStackOverflowRequest(config, authStateCache); 235 return new AuthStackOverflowRequest(config, authStateCache);
236 - case HUAWEI: 236 + case "HUAWEI":
237 return new AuthHuaweiRequest(config, authStateCache); 237 return new AuthHuaweiRequest(config, authStateCache);
238 - case HUAWEI_V3: 238 + case "HUAWEI_V3":
239 return new AuthHuaweiV3Request(config, authStateCache); 239 return new AuthHuaweiV3Request(config, authStateCache);
240 - case WECHAT_ENTERPRISE: 240 + case "WECHAT_ENTERPRISE":
241 return new AuthWeChatEnterpriseQrcodeRequest(config, authStateCache); 241 return new AuthWeChatEnterpriseQrcodeRequest(config, authStateCache);
242 - case WECHAT_ENTERPRISE_V2: 242 + case "WECHAT_ENTERPRISE_V2":
243 return new AuthWeChatEnterpriseQrcodeV2Request(config, authStateCache); 243 return new AuthWeChatEnterpriseQrcodeV2Request(config, authStateCache);
244 - case WECHAT_ENTERPRISE_QRCODE_THIRD: 244 + case "WECHAT_ENTERPRISE_QRCODE_THIRD":
245 return new AuthWeChatEnterpriseThirdQrcodeRequest(config, authStateCache); 245 return new AuthWeChatEnterpriseThirdQrcodeRequest(config, authStateCache);
246 - case WECHAT_ENTERPRISE_WEB: 246 + case "WECHAT_ENTERPRISE_WEB":
247 return new AuthWeChatEnterpriseWebRequest(config, authStateCache); 247 return new AuthWeChatEnterpriseWebRequest(config, authStateCache);
248 - case KUJIALE: 248 + case "KUJIALE":
249 return new AuthKujialeRequest(config, authStateCache); 249 return new AuthKujialeRequest(config, authStateCache);
250 - case GITLAB: 250 + case "GITLAB":
251 return new AuthGitlabRequest(config, authStateCache); 251 return new AuthGitlabRequest(config, authStateCache);
252 - case MEITUAN: 252 + case "MEITUAN":
253 return new AuthMeituanRequest(config, authStateCache); 253 return new AuthMeituanRequest(config, authStateCache);
254 - case ELEME: 254 + case "ELEME":
255 return new AuthElemeRequest(config, authStateCache); 255 return new AuthElemeRequest(config, authStateCache);
256 - case TWITTER: 256 + case "TWITTER":
257 return new AuthTwitterRequest(config, authStateCache); 257 return new AuthTwitterRequest(config, authStateCache);
258 - case FEISHU: 258 + case "FEISHU":
259 return new AuthFeishuRequest(config, authStateCache); 259 return new AuthFeishuRequest(config, authStateCache);
260 - case JD: 260 + case "JD":
261 return new AuthJdRequest(config, authStateCache); 261 return new AuthJdRequest(config, authStateCache);
262 - case ALIYUN: 262 + case "ALIYUN":
263 return new AuthAliyunRequest(config, authStateCache); 263 return new AuthAliyunRequest(config, authStateCache);
264 - case XMLY: 264 + case "XMLY":
265 return new AuthXmlyRequest(config, authStateCache); 265 return new AuthXmlyRequest(config, authStateCache);
266 - case AMAZON: 266 + case "AMAZON":
267 return new AuthAmazonRequest(config, authStateCache); 267 return new AuthAmazonRequest(config, authStateCache);
268 - case SLACK: 268 + case "SLACK":
269 return new AuthSlackRequest(config, authStateCache); 269 return new AuthSlackRequest(config, authStateCache);
270 - case LINE: 270 + case "LINE":
271 return new AuthLineRequest(config, authStateCache); 271 return new AuthLineRequest(config, authStateCache);
272 - case OKTA: 272 + case "OKTA":
273 return new AuthOktaRequest(config, authStateCache); 273 return new AuthOktaRequest(config, authStateCache);
274 - case PROGINN: 274 + case "PROGINN":
275 return new AuthProginnRequest(config,authStateCache); 275 return new AuthProginnRequest(config,authStateCache);
276 - case AFDIAN: 276 + case "AFDIAN":
277 return new AuthAfDianRequest(config,authStateCache); 277 return new AuthAfDianRequest(config,authStateCache);
278 - case APPLE: 278 + case "APPLE":
279 return new AuthAppleRequest(config,authStateCache); 279 return new AuthAppleRequest(config,authStateCache);
280 - case FIGMA: 280 + case "FIGMA":
281 return new AuthFigmaRequest(config,authStateCache); 281 return new AuthFigmaRequest(config,authStateCache);
282 - case WECHAT_MINI_PROGRAM: 282 + case "WECHAT_MINI_PROGRAM":
283 config.setIgnoreCheckRedirectUri(true); 283 config.setIgnoreCheckRedirectUri(true);
284 config.setIgnoreCheckState(true); 284 config.setIgnoreCheckState(true);
285 return new AuthWechatMiniProgramRequest(config, authStateCache); 285 return new AuthWechatMiniProgramRequest(config, authStateCache);
286 - case QQ_MINI_PROGRAM: 286 + case "QQ_MINI_PROGRAM":
287 config.setIgnoreCheckRedirectUri(true); 287 config.setIgnoreCheckRedirectUri(true);
288 config.setIgnoreCheckState(true); 288 config.setIgnoreCheckState(true);
289 return new AuthQQMiniProgramRequest(config, authStateCache); 289 return new AuthQQMiniProgramRequest(config, authStateCache);
  290 + case "UAA":
  291 + return new AuthUaaRequest(config, authStateCache);
290 default: 292 default:
291 return null; 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 \ No newline at end of file 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,16 +175,27 @@ public class AdminAuthServiceImpl implements AdminAuthService {
175 // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号 175 // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号
176 SocialUserRespDTO socialUser = socialUserService.getSocialUserByCode(UserTypeEnum.ADMIN.getValue(), reqVO.getType(), 176 SocialUserRespDTO socialUser = socialUserService.getSocialUserByCode(UserTypeEnum.ADMIN.getValue(), reqVO.getType(),
177 reqVO.getCode(), reqVO.getState()); 177 reqVO.getCode(), reqVO.getState());
178 - if (socialUser == null || socialUser.getUserId() == null) { 178 + if (socialUser == null) {
179 throw exception(AUTH_THIRD_LOGIN_NOT_BIND); 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 if (user == null) { 189 if (user == null) {
185 throw exception(USER_NOT_EXISTS); 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 // 创建 Token 令牌,记录登录日志 199 // 创建 Token 令牌,记录登录日志
189 return createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL); 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,6 +27,7 @@ import com.zteits.urbanops.module.system.dal.mysql.user.AdminUserMapper;
27 import com.zteits.urbanops.module.system.service.dept.DeptService; 27 import com.zteits.urbanops.module.system.service.dept.DeptService;
28 import com.zteits.urbanops.module.system.service.dept.PostService; 28 import com.zteits.urbanops.module.system.service.dept.PostService;
29 import com.zteits.urbanops.module.system.service.dict.DictDataService; 29 import com.zteits.urbanops.module.system.service.dict.DictDataService;
  30 +import com.zteits.urbanops.module.system.service.oauth2.SsoService;
30 import com.zteits.urbanops.module.system.service.permission.PermissionService; 31 import com.zteits.urbanops.module.system.service.permission.PermissionService;
31 import com.zteits.urbanops.module.system.service.tenant.TenantService; 32 import com.zteits.urbanops.module.system.service.tenant.TenantService;
32 import com.google.common.annotations.VisibleForTesting; 33 import com.google.common.annotations.VisibleForTesting;
@@ -87,6 +88,10 @@ public class AdminUserServiceImpl implements AdminUserService { @@ -87,6 +88,10 @@ public class AdminUserServiceImpl implements AdminUserService {
87 @Resource 88 @Resource
88 private DictDataService dictDataService; 89 private DictDataService dictDataService;
89 90
  91 + @Resource
  92 + private SsoService ssoService;
  93 +
  94 +
90 @Override 95 @Override
91 @Transactional(rollbackFor = Exception.class) 96 @Transactional(rollbackFor = Exception.class)
92 @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_CREATE_SUB_TYPE, bizNo = "{{#user.id}}", 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,6 +120,8 @@ public class AdminUserServiceImpl implements AdminUserService {
115 120
116 // 3. 记录操作日志上下文 121 // 3. 记录操作日志上下文
117 LogRecordContext.putVariable("user", user); 122 LogRecordContext.putVariable("user", user);
  123 +
  124 + ssoService.syncUser(user);
118 return user.getId(); 125 return user.getId();
119 } 126 }
120 127
@@ -232,6 +239,8 @@ public class AdminUserServiceImpl implements AdminUserService { @@ -232,6 +239,8 @@ public class AdminUserServiceImpl implements AdminUserService {
232 updateObj.setId(id); 239 updateObj.setId(id);
233 updateObj.setStatus(status); 240 updateObj.setStatus(status);
234 userMapper.updateById(updateObj); 241 userMapper.updateById(updateObj);
  242 +
  243 + ssoService.syncUser(updateObj);
235 } 244 }
236 245
237 @Override 246 @Override
@@ -251,6 +260,8 @@ public class AdminUserServiceImpl implements AdminUserService { @@ -251,6 +260,8 @@ public class AdminUserServiceImpl implements AdminUserService {
251 260
252 // 3. 记录操作日志上下文 261 // 3. 记录操作日志上下文
253 LogRecordContext.putVariable("user", user); 262 LogRecordContext.putVariable("user", user);
  263 +
  264 + ssoService.syncUser(user);
254 } 265 }
255 266
256 @Override 267 @Override
urbanops-server/src/main/resources/application-dev.yaml
@@ -191,30 +191,27 @@ urbanops: @@ -191,30 +191,27 @@ urbanops:
191 justauth: 191 justauth:
192 enabled: true 192 enabled: true
193 type: 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 ignore-check-redirect-uri: true 198 ignore-check-redirect-uri: true
213 cache: 199 cache:
214 type: REDIS 200 type: REDIS
215 prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE:: 201 prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE::
216 timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟 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 --- #################### iot相关配置 TODO 芋艿【IOT】:再瞅瞅 #################### 215 --- #################### iot相关配置 TODO 芋艿【IOT】:再瞅瞅 ####################
219 pf4j: 216 pf4j:
220 # pluginsDir: /tmp/ 217 # pluginsDir: /tmp/
@@ -235,17 +232,7 @@ flow: @@ -235,17 +232,7 @@ flow:
235 - appid: wy 232 - appid: wy
236 secret: x3z7t6l2g2t2i4w3x5e2e0s5y9e6d1y3 233 secret: x3z7t6l2g2t2i4w3x5e2e0s5y9e6d1y3
237 url: https://pms.jichengshanshui.com.cn:9980/prod-api/task/third/report 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 wechat: 237 wechat:
251 mp: 238 mp:
urbanops-server/src/main/resources/application-prod.yaml
@@ -228,30 +228,32 @@ global: @@ -228,30 +228,32 @@ global:
228 justauth: 228 justauth:
229 enabled: true 229 enabled: true
230 type: 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 ignore-check-redirect-uri: true 235 ignore-check-redirect-uri: true
250 cache: 236 cache:
251 type: REDIS 237 type: REDIS
252 prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE:: 238 prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE::
253 timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟 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 --- #################### iot相关配置 TODO 芋艿【IOT】:再瞅瞅 #################### 257 --- #################### iot相关配置 TODO 芋艿【IOT】:再瞅瞅 ####################
256 pf4j: 258 pf4j:
257 # pluginsDir: /tmp/ 259 # pluginsDir: /tmp/
@@ -272,17 +274,7 @@ flow: @@ -272,17 +274,7 @@ flow:
272 - appid: wy 274 - appid: wy
273 secret: x3z7t6l2g2t2i4w3x5e2e0s5y9e6d1y3 275 secret: x3z7t6l2g2t2i4w3x5e2e0s5y9e6d1y3
274 url: https://pms.jichengshanshui.com.cn:9980/prod-api/task/third/report 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 wechat: 279 wechat:
288 mp: 280 mp:
urbanops-server/src/main/resources/application.yaml
@@ -3,7 +3,7 @@ spring: @@ -3,7 +3,7 @@ spring:
3 name: urbanops-server 3 name: urbanops-server
4 4
5 profiles: 5 profiles:
6 - active: prod 6 + active: dev
7 7
8 main: 8 main:
9 allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。 9 allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。
urbanops-server/src/main/resources/pub.cer 0 → 100644
No preview for this file type