猿问

添加 Google API 离线访问 .NET Core 应用程序

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

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

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

因此,我始终将用户身份验证 (Auth0) 步骤与 Analytics 帐户步骤的身份验证分开。大致流程如下:

  1. 用户使用任何提供商(Google、Facebook、电子邮件/通行证)通过 Auth0 登录并访问私人仪表板。

  2. 用户设置一个“公司”并单击一个按钮来授权我们的网络应用程序访问带有 Analytics 的特定 Google 帐户。

  3. 用户将被重定向回私人仪表板,并且 Google 帐户的刷新令牌将被存储以供将来使用。

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

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

达令说
浏览 65回答 1
1回答

冉冉说

我终于破解了!我最终扔掉了所有库,发现使用普通的旧 REST API 最简单。对于那些好奇的人来说,下面的代码示例:用户的浏览器获取以下内容并重定向到 Google 以获取身份验证令牌:public IActionResult OnGet([FromQuery]int id, [FromQuery]string returnAction){&nbsp; &nbsp; var org = context.Organizations.Include(o => o.UserOrgs).First(o => o.Id == id);&nbsp; &nbsp; var user = GetUser();&nbsp; &nbsp; if (!IsUserMemberOfOrg(user, org)) return BadRequest("User is not a member of this organization!");&nbsp; &nbsp; var redirectUri = Uri.EscapeUriString(GetBaseUri()+"dash/auth/google?handler=ReturnCode");&nbsp; &nbsp; var uri = $"https://accounts.google.com/o/oauth2/v2/auth?"+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $"scope={Uri.EscapeUriString("https://www.googleapis.com/auth/analytics.readonly")}"+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $"&prompt=consent"+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $"&access_type=offline"+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //$"&include_granted_scopes=true"+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $"&state={Uri.EscapeUriString(JsonConvert.SerializeObject(new AuthState() { OrgId = id, ReturnAction = returnAction }))}"+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $"&redirect_uri={redirectUri}"+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $"&response_type=code"+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $"&client_id={_configuration["Authentication:Google:ClientId"]}";&nbsp; &nbsp; return Redirect(uri);}Google 重定向回以下内容,此时我从网络服务器到 Google API 执行 POST,以将身份验证令牌交换为刷新令牌并将其存储以供以后使用:public async Task<IActionResult> OnGetReturnCode([FromQuery]string state, [FromQuery]string code, [FromQuery]string scope){&nbsp; &nbsp; var authState = JsonConvert.DeserializeObject<AuthState>(state);&nbsp; &nbsp; var id = authState.OrgId;&nbsp; &nbsp; var returnAction = authState.ReturnAction;&nbsp; &nbsp; var org = await context.Organizations.Include(o => o.UserOrgs).SingleOrDefaultAsync(o => o.Id == id);&nbsp; &nbsp; if (org == null) return BadRequest("This Org doesn't exist!");&nbsp; &nbsp; using (var httpClient = new HttpClient())&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var redirectUri = Uri.EscapeUriString(GetBaseUri()+"dash/auth/google?handler=ReturnCode");&nbsp; &nbsp; &nbsp; &nbsp; var dict = new Dictionary<string, string>&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { "code", code },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { "client_id", _configuration["Authentication:Google:ClientId"] },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { "client_secret", _configuration["Authentication:Google:ClientSecret"] },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { "redirect_uri", redirectUri },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { "grant_type", "authorization_code" }&nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; var content = new FormUrlEncodedContent(dict);&nbsp; &nbsp; &nbsp; &nbsp; var response = await httpClient.PostAsync("https://www.googleapis.com/oauth2/v4/token", content);&nbsp; &nbsp; &nbsp; &nbsp; var resultContent = JsonConvert.DeserializeObject<GoogleRefreshTokenPostResponse>(await response.Content.ReadAsStringAsync());&nbsp; &nbsp; &nbsp; &nbsp; org.GoogleAuthRefreshToken = resultContent.refresh_token;&nbsp; &nbsp; &nbsp; &nbsp; await context.SaveChangesAsync();&nbsp; &nbsp; &nbsp; &nbsp; return Redirect($"{authState.ReturnAction}/{authState.OrgId}");&nbsp; &nbsp; }}最后,我们可以稍后使用刷新令牌获取新的访问令牌,而无需用户干预:public async Task<string> GetGoogleAccessToken(Organization org){&nbsp; &nbsp; if(string.IsNullOrEmpty(org.GoogleAuthRefreshToken))&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; throw new Exception("No refresh token found. " +&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Please visit the organization settings page" +&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; " to setup your Google account.");&nbsp; &nbsp; }&nbsp; &nbsp; using (var httpClient = new HttpClient())&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var dict = new Dictionary<string, string>&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { "client_id", _configuration["Authentication:Google:ClientId"] },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { "client_secret", _configuration["Authentication:Google:ClientSecret"] },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { "refresh_token", org.GoogleAuthRefreshToken },&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { "grant_type", "refresh_token" }&nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; var resp = await httpClient.PostAsync("https://www.googleapis.com/oauth2/v4/token",&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new FormUrlEncodedContent(dict));&nbsp; &nbsp; &nbsp; &nbsp; if (resp.IsSuccessStatusCode)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dynamic returnContent = JObject.Parse(await resp.Content.ReadAsStringAsync());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return returnContent.access_token;&nbsp; &nbsp; &nbsp; &nbsp; } else&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new Exception(resp.ReasonPhrase);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}
随时随地看视频慕课网APP
我要回答