冉冉说
我终于破解了!我最终扔掉了所有库,发现使用普通的旧 REST API 最简单。对于那些好奇的人来说,下面的代码示例:用户的浏览器获取以下内容并重定向到 Google 以获取身份验证令牌: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 重定向回以下内容,此时我从网络服务器到 Google API 执行 POST,以将身份验证令牌交换为刷新令牌并将其存储以供以后使用: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}"); }}最后,我们可以稍后使用刷新令牌获取新的访问令牌,而无需用户干预: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); } }}