using System.Collections.Generic; using System.Net.Http; using System.Text; using Sog; using LitJson; using System.Text.Json; namespace HttpProxy { public class HuaweiAuth { // HMSCore接入信息 // 解析access Token信息的地址 private static string GetAccessTokenInfoUrl = "https://oauth-api.cloud.huawei.com/rest.php"; // 解析ID Token信息的地址 private static string GetIDTokenInfoUrl = "https://oauth-login.cloud.huawei.com/oauth2/v3/tokeninfo"; private static string NSP_SVC = "huawei.oauth2.user.getTokenInfo"; // 游戏产品在SDK平台的应用ID private static string ClientId = "105624843"; // 游戏产品在SDK平台的应用私钥 private static string ClientSecret = "1913208d8b4d11a0d9c1c3c096318ad84c8a41ef9105313ea5f2ad245ebc5d96"; // idtoken校验中返回的iss字段值, 需要验证是否匹配 private static string IDTOKEN_ISS = "https://accounts.huawei.com"; // AppGallery Connect接入信息 private static string AGC_ProductId = "737518067794508975"; private static string AGC_ClientId = "910058972399029696"; private static string AGC_ClientSecret = "F745EDA6D66B71030543B9B2D73E91951D5C3389930D7508648044ED195D441F"; private static string AGC_GetTokenUrl = "https://connect-api.cloud.huawei.com/api/oauth2/v1/token"; // 德国站点地址 private static string AGC_VerifyTokenInfoUrl = "https://connect-api-dre.cloud.huawei.com/api/oauth2/third/v1/verify-token?productId=737518067794508975"; // 服务器向华为SDK服务器请求时用的AccessToken private static string AGC_AccessToken; private static long AGC_AccessTokenExpireTime; private static long nextTickTimeMs; public static void Init(string clientId, string clientSecret, string accessTokenUrl, string idTokenUrl) { if (! string.IsNullOrEmpty(clientId)) { ClientId = clientId; } if (! string.IsNullOrEmpty(clientSecret)) { ClientSecret = clientSecret; } if (! string.IsNullOrEmpty(accessTokenUrl)) { GetAccessTokenInfoUrl = accessTokenUrl; } if (!string.IsNullOrEmpty(idTokenUrl)) { GetIDTokenInfoUrl = idTokenUrl; } TraceLog.Trace("HuaweiAuth.Init clientId {0} clientSecret {1} accessTokenUrl {2} idTokenUrl {3}" , ClientId, ClientSecret, GetAccessTokenInfoUrl, GetIDTokenInfoUrl); } public static void InitAGC(string clientId, string clientSecret, string getTokenUrl, string verifyTokenUrl, string productId) { if (! string.IsNullOrEmpty(clientId)) { AGC_ClientId = clientId; } if (! string.IsNullOrEmpty(clientSecret)) { AGC_ClientSecret = clientSecret; } if (! string.IsNullOrEmpty(getTokenUrl)) { AGC_GetTokenUrl = getTokenUrl; } if (! string.IsNullOrEmpty(productId)) { AGC_ProductId = productId; } if (! string.IsNullOrEmpty(verifyTokenUrl) && ! string.IsNullOrEmpty(productId)) { AGC_VerifyTokenInfoUrl = verifyTokenUrl + "productId=" + productId; } TraceLog.Trace("HuaweiAuth.InitAGC clientId {0} clientSecret {1} getTokenUrl {2} verifyTokenUrl {3}" , AGC_ClientId, AGC_ClientSecret, AGC_GetTokenUrl, AGC_VerifyTokenInfoUrl); } public static bool GetAccessTokenInfo(string openId, string accessToken) { var allParams = new Dictionary(); allParams["nsp_svc"] = NSP_SVC; allParams["open_id"] = "OPENID"; allParams["access_token"] = accessToken; var content = new FormUrlEncodedContent(allParams); string ret = HttpUtils.HttpPost(GetAccessTokenInfoUrl, content, out bool exception); if (ret == null) { TraceLog.Error("HuaweiAuth.GetAccessTokenInfo HttpPost failed"); return false; } TraceLog.Trace("HuaweiAuth.GetAccessTokenInfo ret {0}", ret); JsonData jsonData = JsonMapper.ToObject(ret); if (! jsonData.ContainsKey("open_id")) { TraceLog.Error("HuaweiAuth.GetAccessTokenInfo no [open_id]"); return false; } string resOpenId = jsonData["open_id"].ToString(); if (! resOpenId.Equals(openId)) { TraceLog.Error("HuaweiAuth.GetAccessTokenInfo openId {0} res {1} not same", openId, resOpenId); return false; } return true; } public static bool GetIDTokenInfo(string openId, string idToken) { var allParams = new Dictionary(); allParams["id_token"] = idToken; var content = new FormUrlEncodedContent(allParams); string ret = HttpUtils.HttpPost(GetIDTokenInfoUrl, content, out bool exception); if (ret == null) { TraceLog.Error("HuaweiAuth.GetIDTokenInfo HttpPost failed"); return false; } TraceLog.Trace("HuaweiAuth.GetIDTokenInfo ret {0}", ret); JsonData jsonData = JsonMapper.ToObject(ret); if (!jsonData.ContainsKey("iss")) { TraceLog.Error("HuaweiAuth.GetIDTokenInfo no [iss]"); return false; } if (!jsonData.ContainsKey("aud")) { TraceLog.Error("HuaweiAuth.GetIDTokenInfo no [aud]"); return false; } if (!jsonData.ContainsKey("exp")) { TraceLog.Error("HuaweiAuth.GetIDTokenInfo no [exp]"); return false; } long exp = (long)jsonData["exp"]; if (HttpProxyServerUtils.GetTimeSecond() >= exp) { TraceLog.Trace("HuaweiAuth.GetIDTokenInfo token expire at {0}", exp); return false; } string iss = jsonData["iss"].ToString(); string aud = jsonData["aud"].ToString(); if (! iss.Equals(IDTOKEN_ISS) || ! aud.Equals(ClientId)) { TraceLog.Error("HuaweiAuth.GetIDTokenInfo invalid iss {0} aud {1}", iss, aud); return false; } return true; } public static void Update(long nowSec) { //配置文件没配置,不update,要不一堆异常 2022/12/21 zouwei if(string.IsNullOrEmpty(HttpProxyServerUtils.GetServerConfig().huaweiAGC_ClientId)) { return; } if (nowSec < nextTickTimeMs) { return; } // 10秒tick 1次 nextTickTimeMs = nowSec + 10; // token过期前10分钟开始尝试刷新 if (nowSec + 600 >= AGC_AccessTokenExpireTime) { UpdateAGCAccessToken(); } } // 刷新AGC服务器请求时需要的AccessToken public static int UpdateAGCAccessToken() { Dictionary bodyMap = new Dictionary(); bodyMap.Add("client_id", AGC_ClientId); bodyMap.Add("client_secret", AGC_ClientSecret); bodyMap.Add("grant_type", "client_credentials"); var bodyString = JsonSerializer.Serialize(bodyMap); var httpContent = new StringContent(bodyString, Encoding.UTF8, "application/json"); string httpRet = HttpUtils.HttpPost(AGC_GetTokenUrl, httpContent, null, 10, out int statusCode); TraceLog.Debug("HuaweiAuth.UpdateAGCAccessToken HttpPost res status code {0}", statusCode); if (httpRet == null) { TraceLog.Error("HuaweiAuth.UpdateAGCAccessToken HttpPost return null"); return -1; } TraceLog.Trace("HuaweiAuth.UpdateAGCAccessToken ret {0}", httpRet); JsonData jsonData = JsonMapper.ToObject(httpRet); // 获取失败时会返回ret, 成功则不会 if (jsonData.ContainsKey("ret")) { TraceLog.Error("HuaweiAuth.UpdateAGCAccessToken get access token failed"); return -1; } JsonData accToken = jsonData["access_token"]; if (accToken == null) { TraceLog.Error("HuaweiAuth.UpdateAGCAccessToken res no [access_token]"); return -1; } JsonData validTime = jsonData["expires_in"]; if (validTime == null) { TraceLog.Error("HuaweiAuth.UpdateAGCAccessToken res no [expires_in]"); return -1; } if (! long.TryParse(validTime.ToString(), out long validTimeSec)) { TraceLog.Error("HuaweiAuth.UpdateAGCAccessToken invalid [expires_in] {0}", validTime.ToString()); return -1; } AGC_AccessToken = accToken.ToString(); AGC_AccessTokenExpireTime = HttpProxyServerUtils.GetTimeSecond() + validTimeSec; // 打印错误日志不容易被冲掉 TraceLog.Error("HuaweiAuth.UpdateAGCAccessToken succ, token {0} expire {1}", AGC_AccessToken, AGC_AccessTokenExpireTime); return 0; } // 校验用户上报的AccountToken public static int VerifyAGCUserToken(string accountId, string userToken) { Dictionary httpHeaders = new Dictionary(); httpHeaders.Add("client_id", AGC_ClientId); httpHeaders.Add("accessToken", userToken); httpHeaders.Add("Authorization", $"Bearer {AGC_AccessToken}"); string httpRet = HttpUtils.HttpGet(AGC_VerifyTokenInfoUrl, out bool ex, httpHeaders); if (httpRet == null) { TraceLog.Error("HuaweiAuth.VerifyAGCUserToken token {0} HttpGet return null", userToken); return -1; } TraceLog.Trace("HuaweiAuth.VerifyAGCUserToken token {0} ret {1}", userToken, httpRet); JsonData jsonData = JsonMapper.ToObject(httpRet); JsonData ret = jsonData["ret"]; if (! int.TryParse(ret["code"].ToString(), out int retCode)) { TraceLog.Error("HuaweiAuth.VerifyAGCUserToken invalid ret code {0}", ret["code"].ToString()); return -1; } if (retCode != 0) { TraceLog.Trace("HuaweiAuth.VerifyAGCUserToken invalid ret code {0}", retCode); return -1; } JsonData uid = jsonData["uid"]; if (uid == null) { TraceLog.Error("HuaweiAuth.VerifyAGCUserToken res no [uid]"); return -1; } string resUid = uid.ToString(); if (! accountId.Equals(resUid)) { TraceLog.Error("HuaweiAuth.VerifyAGCUserToken accountId {0} {1} not same", accountId, resUid); return -1; } JsonData accToken = jsonData["accessToken"]; if (accToken == null) { TraceLog.Error("HuaweiAuth.VerifyAGCUserToken res no [accessToken]"); return -1; } if (! long.TryParse(accToken["validPeriod"].ToString(), out long validTime)) { TraceLog.Error("HuaweiAuth.VerifyAGCUserToken invalid token time {0}", accToken["validPeriod"].ToString()); return -1; } if (validTime <= 0) { TraceLog.Error("HuaweiAuth.VerifyAGCUserToken invalid token time {0}", validTime); return -1; } TraceLog.Trace("HuaweiAuth.VerifyAGCUserToken {0} validTime {1} succ", userToken, validTime); return 0; } } }