gpt4 book ai didi

c# - 将 Google API 离线访问添加到 .NET Core 应用程序

转载 作者:行者123 更新时间:2023-12-05 02:11:21 30 4
gpt4 key购买 nike

我编写了一个 ASP.NET Core web 应用程序,它使用 Auth0 作为用户的主要授权机制,中间人是一大堆外部身份验证端点,例如 Google 和 Facebook。这工作正常,我在那里没有问题。

网络应用程序的核心是使用 Google Analytics 来执行自己的分析和业务逻辑。我的网络应用程序正在分析的 Google Analytics 帐户可能并且很可能与用户自己的 Google 帐户不同。明确地说,我的意思是,用户很可能会使用他们希望的任何登录提供商登录,然后他们将附加一个特定的 Google 企业帐户,以访问他们的企业 Google Analytics 系统。

网络应用程序在用户登录时和用户离线时执行分析。

所以我一直将用户身份验证 (Auth0) 步骤与 Analytics 帐户步骤的身份验证分开。大致流程如下:

  1. 用户使用任何提供商(Google、Facebook、电子邮件/密码)通过 Auth0 登录并访问私有(private)仪表板。
  2. 用户设置“公司”并点击一个按钮以授权我们的网络应用程序访问特定的 Google 帐户,其中包含 Analytics。
  3. 用户被重定向回私有(private)仪表板,Google 帐户的刷新 token 被存储以备将来使用。

以前我也一直通过 Auth0 推送 Analytics 身份验证,并且我使用缓存的 Auth0 刷新 token 来离线工作。但是它会在几天后过期,并且 Auth0 似乎不提供长期离线访问。

因此,我认为最简单的做法就是不将 auth0 用于 Analytics 身份验证步骤,直接使用 Google API 进行身份验证并长期存储 Google 刷新 token 。但是我找不到任何具体的例子来说明如何实现这一目标!

  • Official Google API .NET Example - 这看起来很旧,并且没有真正得到 ASPNET Core 的支持。我看不到将它塑造成任何可用的东西的明确方法,搜索 SO 发现它有明显的问题。
  • SO answer to a similar question - 这是一个很好的答案,但实现是针对用户身份验证的,我认为在我的场景中不会起作用。

最佳答案

我终于破解了!我最终扔掉了所有的库,发现使用普通的旧 REST API 是最简单的。下面的代码示例供好奇的人使用:

用户的浏览器获取以下内容并重定向到 Google 以获取身份验证 token :

public IActionResult OnGet([FromQuery]int id, [FromQuery]string returnAction)
{
var org = context.Organizations.Include(o => o.UserOrgs).First(o => o.Id == id);
var user = GetUser();

if (!IsUserMemberOfOrg(user, org)) return BadRequest("User is not a member of this organization!");

var redirectUri = Uri.EscapeUriString(GetBaseUri()+"dash/auth/google?handler=ReturnCode");
var uri = $"https://accounts.google.com/o/oauth2/v2/auth?"+
$"scope={Uri.EscapeUriString("https://www.googleapis.com/auth/analytics.readonly")}"+
$"&prompt=consent"+
$"&access_type=offline"+
//$"&include_granted_scopes=true"+
$"&state={Uri.EscapeUriString(JsonConvert.SerializeObject(new AuthState() { OrgId = id, ReturnAction = returnAction }))}"+
$"&redirect_uri={redirectUri}"+
$"&response_type=code"+
$"&client_id={_configuration["Authentication:Google:ClientId"]}";

return Redirect(uri);
}

Google 重定向回以下内容,我从网络服务器执行 POST 到 Google API 以将身份验证 token 交换为刷新 token 并将其存储以备后用:

public async Task<IActionResult> OnGetReturnCode([FromQuery]string state, [FromQuery]string code, [FromQuery]string scope)
{
var authState = JsonConvert.DeserializeObject<AuthState>(state);

var id = authState.OrgId;
var returnAction = authState.ReturnAction;

var org = await context.Organizations.Include(o => o.UserOrgs).SingleOrDefaultAsync(o => o.Id == id);
if (org == null) return BadRequest("This Org doesn't exist!");
using (var httpClient = new HttpClient())
{
var redirectUri = Uri.EscapeUriString(GetBaseUri()+"dash/auth/google?handler=ReturnCode");

var dict = new Dictionary<string, string>
{
{ "code", code },
{ "client_id", _configuration["Authentication:Google:ClientId"] },
{ "client_secret", _configuration["Authentication:Google:ClientSecret"] },
{ "redirect_uri", redirectUri },
{ "grant_type", "authorization_code" }
};

var content = new FormUrlEncodedContent(dict);
var response = await httpClient.PostAsync("https://www.googleapis.com/oauth2/v4/token", content);

var resultContent = JsonConvert.DeserializeObject<GoogleRefreshTokenPostResponse>(await response.Content.ReadAsStringAsync());

org.GoogleAuthRefreshToken = resultContent.refresh_token;
await context.SaveChangesAsync();

return Redirect($"{authState.ReturnAction}/{authState.OrgId}");
}
}

最后,我们可以在以后无需用户干预的情况下使用刷新 token 获取新的访问 token :

public async Task<string> GetGoogleAccessToken(Organization org)
{
if(string.IsNullOrEmpty(org.GoogleAuthRefreshToken))
{
throw new Exception("No refresh token found. " +
"Please visit the organization settings page" +
" to setup your Google account.");
}

using (var httpClient = new HttpClient())
{
var dict = new Dictionary<string, string>
{
{ "client_id", _configuration["Authentication:Google:ClientId"] },
{ "client_secret", _configuration["Authentication:Google:ClientSecret"] },
{ "refresh_token", org.GoogleAuthRefreshToken },
{ "grant_type", "refresh_token" }
};
var resp = await httpClient.PostAsync("https://www.googleapis.com/oauth2/v4/token",
new FormUrlEncodedContent(dict));

if (resp.IsSuccessStatusCode)
{
dynamic returnContent = JObject.Parse(await resp.Content.ReadAsStringAsync());
return returnContent.access_token;
} else
{
throw new Exception(resp.ReasonPhrase);
}
}
}

关于c# - 将 Google API 离线访问添加到 .NET Core 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57616296/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com