You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

351 lines
12 KiB

1 month ago
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<string, string>();
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<string, string>();
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<string, string> bodyMap = new Dictionary<string, string>();
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<string, string> httpHeaders = new Dictionary<string, string>();
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;
}
}
}