MaxKey 3 лет назад
Родитель
Сommit
b56496a6df

+ 172 - 0
maxkey-authentications/maxkey-authentication-social/src/main/java/me/zhyd/oauth/request/AuthHuaweiWeLinkRequest.java

@@ -0,0 +1,172 @@
+package me.zhyd.oauth.request;
+import com.alibaba.fastjson.JSONObject;
+import me.zhyd.oauth.cache.AuthStateCache;
+import me.zhyd.oauth.config.AuthConfig;
+import me.zhyd.oauth.enums.AuthUserGender;
+import me.zhyd.oauth.enums.scope.AuthHuaweiScope;
+import me.zhyd.oauth.exception.AuthException;
+import me.zhyd.oauth.model.AuthCallback;
+import me.zhyd.oauth.model.AuthResponse;
+import me.zhyd.oauth.model.AuthToken;
+import me.zhyd.oauth.model.AuthUser;
+import me.zhyd.oauth.utils.AuthScopeUtils;
+import me.zhyd.oauth.utils.HttpUtils;
+import me.zhyd.oauth.utils.UrlBuilder;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static me.zhyd.oauth.enums.AuthResponseStatus.SUCCESS;
+
+public class AuthHuaweiWeLinkRequest  extends AuthDefaultRequest {
+
+    public AuthHuaweiWeLinkRequest(AuthConfig config) {
+        super(config, WeLinkAuthDefaultSource.HUAWEI_WELINK);
+    }
+
+    public AuthHuaweiWeLinkRequest(AuthConfig config, AuthStateCache authStateCache) {
+        super(config, WeLinkAuthDefaultSource.HUAWEI_WELINK, authStateCache);
+    }
+
+    /**
+     * 获取access token
+     *
+     * @param authCallback 授权成功后的回调参数
+     * @return token
+     * @see AuthDefaultRequest#authorize()
+     * @see AuthDefaultRequest#authorize(String)
+     */
+    @Override
+    protected AuthToken getAccessToken(AuthCallback authCallback) {
+        Map<String, String> form = new HashMap<>(8);
+        form.put("grant_type", "authorization_code");
+        form.put("code", authCallback.getAuthorization_code());
+        form.put("client_id", config.getClientId());
+        form.put("client_secret", config.getClientSecret());
+        form.put("redirect_uri", config.getRedirectUri());
+
+        String response = new HttpUtils(config.getHttpConfig()).post(source.accessToken(), form, false).getBody();
+        return getAuthToken(response);
+    }
+
+    /**
+     * 使用token换取用户信息
+     *
+     * @param authToken token信息
+     * @return 用户信息
+     * @see AuthDefaultRequest#getAccessToken(AuthCallback)
+     */
+    @Override
+    protected AuthUser getUserInfo(AuthToken authToken) {
+        Map<String, String> form = new HashMap<>(7);
+        form.put("nsp_ts", System.currentTimeMillis() + "");
+        form.put("access_token", authToken.getAccessToken());
+        form.put("nsp_fmt", "JS");
+        form.put("nsp_svc", "OpenUP.User.getInfo");
+
+        String response = new HttpUtils(config.getHttpConfig()).post(source.userInfo(), form, false).getBody();
+        JSONObject object = JSONObject.parseObject(response);
+
+        this.checkResponse(object);
+
+        AuthUserGender gender = getRealGender(object);
+
+        return AuthUser.builder()
+            .rawUserInfo(object)
+            .uuid(object.getString("userId"))
+            .username(object.getString("userNameCn"))
+            .nickname(object.getString("userNameCn"))
+            .gender(gender)
+            //.avatar(object.getString("headPictureURL"))
+            .token(authToken)
+            .source(source.toString())
+            .build();
+    }
+
+    /**
+     * 刷新access token (续期)
+     *
+     * @param authToken 登录成功后返回的Token信息
+     * @return AuthResponse
+     */
+    @Override
+    public AuthResponse refresh(AuthToken authToken) {
+        Map<String, String> form = new HashMap<>(7);
+        form.put("client_id", config.getClientId());
+        form.put("client_secret", config.getClientSecret());
+        form.put("refresh_token", authToken.getRefreshToken());
+        form.put("grant_type", "refresh_token");
+
+        String response = new HttpUtils(config.getHttpConfig()).post(source.refresh(), form, false).getBody();
+        return AuthResponse.builder().code(SUCCESS.getCode()).data(getAuthToken(response)).build();
+    }
+
+    private AuthToken getAuthToken(String response) {
+        JSONObject object = JSONObject.parseObject(response);
+
+        this.checkResponse(object);
+
+        return AuthToken.builder()
+            .accessToken(object.getString("access_token"))
+            .expireIn(object.getIntValue("expires_in"))
+            .refreshToken(object.getString("refresh_token"))
+            .build();
+    }
+
+    /**
+     * 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
+     *
+     * @param state state 验证授权流程的参数,可以防止csrf
+     * @return 返回授权地址
+     * @since 1.9.3
+     */
+    @Override
+    public String authorize(String state) {
+        return UrlBuilder.fromBaseUrl(super.authorize(state))
+            .queryParam("access_type", "offline")
+            .queryParam("scope", this.getScopes(" ", true, AuthScopeUtils.getDefaultScopes(AuthHuaweiScope.values())))
+            .build();
+    }
+
+    /**
+     * 返回获取userInfo的url
+     *
+     * @param authToken token
+     * @return 返回获取userInfo的url
+     */
+    @Override
+    protected String userInfoUrl(AuthToken authToken) {
+        return UrlBuilder.fromBaseUrl(source.userInfo())
+            .queryParam("nsp_ts", System.currentTimeMillis())
+            .queryParam("access_token", authToken.getAccessToken())
+            .queryParam("nsp_fmt", "JS")
+            .queryParam("nsp_svc", "OpenUP.User.getInfo")
+            .build();
+    }
+
+    /**
+     * 获取用户的实际性别。华为系统中,用户的性别:1表示女,0表示男
+     *
+     * @param object obj
+     * @return AuthUserGender
+     */
+    private AuthUserGender getRealGender(JSONObject object) {
+        int genderCodeInt = object.getIntValue("gender");
+        String genderCode = genderCodeInt == 1 ? "0" : (genderCodeInt == 0) ? "1" : genderCodeInt + "";
+        return AuthUserGender.getRealGender(genderCode);
+    }
+
+    /**
+     * 校验响应结果
+     *
+     * @param object 接口返回的结果
+     */
+    private void checkResponse(JSONObject object) {
+        if (object.containsKey("NSP_STATUS")) {
+            throw new AuthException(object.getString("error"));
+        }
+        if (object.containsKey("error")) {
+            throw new AuthException(object.getString("sub_error") + ":" + object.getString("error_description"));
+        }
+    }
+}

+ 33 - 0
maxkey-authentications/maxkey-authentication-social/src/main/java/me/zhyd/oauth/request/WeLinkAuthDefaultSource.java

@@ -0,0 +1,33 @@
+package me.zhyd.oauth.request;
+
+import me.zhyd.oauth.config.AuthSource;
+
+public enum WeLinkAuthDefaultSource implements AuthSource{
+
+	 HUAWEI_WELINK {
+	        @Override
+	        public String authorize() {
+	            return "https://login.welink.huaweicloud.com/connect/oauth2/sns_authorize";
+	        }
+
+	        @Override
+	        public String accessToken() {
+	            return "https://open.welink.huaweicloud.com/api/auth/v2/tickets";
+	        }
+
+	        @Override
+	        public String userInfo() {
+	            return "https://open.welink.huaweicloud.com/api/contact/v1/users";
+	        }
+
+	        @Override
+	        public String refresh() {
+	            return "";
+	        }
+
+	        @Override
+	        public Class<? extends AuthDefaultRequest> getTargetClass() {
+	            return AuthHuaweiWeLinkRequest.class;
+	        }
+	    }
+}

+ 4 - 0
maxkey-authentications/maxkey-authentication-social/src/main/java/org/maxkey/authn/support/socialsignon/service/SocialSignOnProviderService.java

@@ -123,8 +123,12 @@ public class SocialSignOnProviderService{
             authRequest = new AuthWeChatEnterpriseQrcodeRequest(authConfig);
         }else if(provider.equalsIgnoreCase("workweixin")) {
             authRequest = new AuthWeChatEnterpriseWebRequest(authConfig);
+        }else if(provider.equalsIgnoreCase("welink")) {
+            authRequest = new AuthHuaweiWeLinkRequest(authConfig);
         }
 		
+		
+		
 		return authRequest;
 	}
 	

+ 20 - 6
maxkey-synchronizers/maxkey-synchronizer/src/main/java/org/maxkey/synchronizer/entity/ResponseData.java

@@ -21,39 +21,53 @@ public class ResponseData {
 
 	protected long errcode;
 	protected long code;
-	
+
 	protected String errmsg;
 	protected String msg;
-	
+	protected String message;
+
 	public long getErrcode() {
 		return errcode;
 	}
+
 	public void setErrcode(long errcode) {
 		this.errcode = errcode;
 	}
+
 	public String getErrmsg() {
 		return errmsg;
 	}
+
 	public void setErrmsg(String errmsg) {
 		this.errmsg = errmsg;
 	}
-	
-	
+
 	public long getCode() {
 		return code;
 	}
+
 	public void setCode(long code) {
 		this.code = code;
 	}
+
 	public String getMsg() {
 		return msg;
 	}
+
 	public void setMsg(String msg) {
 		this.msg = msg;
 	}
+
+	public String getMessage() {
+		return message;
+	}
+
+	public void setMessage(String message) {
+		this.message = message;
+	}
+
 	public ResponseData() {
 		super();
 	}
-	
-	
+
 }

+ 3 - 0
maxkey-webs/maxkey-web-maxkey/src/main/resources/templates/views/login.ftl

@@ -86,6 +86,9 @@
 							     <#if sspLogin.dingTalkLogin != 'none'>  
 							         <#include "loginscandingtalk.ftl">
 							     </#if>  
+							     <#if sspLogin.weLinkLogin != 'none'>  
+                                     <#include "loginscanwelink.ftl">
+                                 </#if>  
 							</div>
 						</td>
 					</tr>

+ 26 - 0
maxkey-webs/maxkey-web-maxkey/src/main/resources/templates/views/loginscanwelink.ftl

@@ -0,0 +1,26 @@
+     <#if sspLogin.weLinkLogin == 'https'> 
+     <script src="https://login.welink.huaweicloud.com/sso-proxy-front/public/qrcode/0.0.1/wlQrcodeLogin.js"></script>
+     </#if>  
+     <#if sspLogin.weLinkLogin == 'http'> 
+     <script src="http://login.welink.huaweicloud.com/sso-proxy-front/public/qrcode/0.0.1/wlQrcodeLogin.js"></script>
+     </#if>  
+     <script type="text/javascript"> 
+        $(function(){
+           $("#qrcodelogin").on("click",function(){
+              $.get("<@base />/logon/oauth20/scanqrcode/welink",function(data,status){
+                      var wlqrcodeLogin = wlQrcodeLogin({
+                          id:"div_qrcodelogin",//这里需要你在自己的页面定义一个HTML标签并设置id,例如<div id="login_container"></div>或<span id="login_container"></span>
+                          client_id: data.clientId,
+                          response_type: "code", 
+                          scope: "snsapi_login", 
+                          state: data.state, 
+                          redirect_uri: encodeURIComponent(data.redirectUri),
+                          style: "border:none;background-color:#FFFFFF;",
+                          width : "365",
+                          height: "400",
+                          self_redirect: false});
+                        $('#div_qrcodelogin').show();
+                    });
+            });
+        });
+    </script>