c# - 如何实现 Google API 刷新令牌
问题描述
我一直在从事一个项目,我必须在 7 个不同的平台上实施 OAuth,但由于某种原因,Google 的 OAuth 流程让我感到困惑。
该项目是在 .NET MVC 中开发的,我正在使用 RestSharp 发出传出 Http 请求。
我正在检索 OAuth 请求以访问 GoogleAnalytics API,并且在第一次尝试时,我获得了一个有效的访问令牌,我可以使用该令牌成功地从用户的 GA 帐户中检索数据。但是,尽管我在身份验证请求 URL 中指定了 access_type=offline,但在令牌过期后尝试刷新令牌时,我看到以下错误:
400 - 错误请求 - {“错误”:“invalid_grant”,“错误描述”:“错误请求”}
我的请求 URL 如下所示:
https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&scope=https://www.googleapis.com/auth/analytics.readonly&include_granted_scopes=true&response_type=code&state=8f692f0f-b177-4b0b-aa89- a757da9432e3&redirect_uri=https://localhost:44338/GoogleAnalytics&client_id=xxxx
当用户与代码一起被重定向回来时,我的令牌请求函数被调用:
public OAuth2Token GetToken(string code)
{
var client = new RestClient(_tokenUri);
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("undefined", $"client_id={_clientId}&client_secret={_secret}&code={code}&redirect_uri={_redirectUri}&grant_type=authorization_code", ParameterType.RequestBody);
var response = client.Execute<OAuth2Token>(request);
return response.Data;
}
访问和刷新令牌被返回,并存储在数据库中,然后在我的刷新函数中使用,这里的 tokenUri 是https://www.googleapis.com/oauth2/v4/token:
public OAuth2Token RefreshToken()
{
var client = new RestClient(_tokenUri);
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("undefined", $"client_id={_clientId}&client_secret={_secret}&refresh_token={_refreshToken}&grant_type=refresh_token", ParameterType.RequestBody);
var response = client.Execute<OAuth2Token>(request);
if (!response.IsSuccessful)
if (response.ErrorException == null)
throw new Exception(response.Content);
else
throw response.ErrorException;
return response.Data;
}
还有一点需要注意的是,我这里的 Google App 处于测试模式,并且我已经将用户添加到了测试用户列表中。关于我在这里做错了什么有什么建议吗?
干杯
解决方案
帖子请求希望看到帖子正文中的值。您将它们作为参数发送。
request.AddParameter("undefined", $"client_id={_clientId}&client_secret={_secret}&refresh_token={_refreshToken}&grant_type=refresh_token", ParameterType.RequestBody);
您可能应该使用 request.AddBody
request.AddBody("undefined", $"client_id={_clientId}&client_secret={_secret}&refresh_token={_refreshToken}&grant_type=refresh_token", ParameterType.RequestBody);
详细解释。
让我们从顶部开始。
谷歌授权或实际上所有的 Oauth2 服务器都会执行所谓的 Oauth 舞蹈,这个舞蹈有三个步骤。
请求同意
您需要的第一个 URL 将导致授权服务器向用户显示同意屏幕。
GET https://accounts.google.com/o/oauth2/auth?client_id={clientid}&redirect_uri={redirectURI}&scope={scope}&response_type=code
这将返回给您一个授权代码注意响应类型是 response_type=code
交换访问令牌和刷新令牌的授权代码。
这个调用是一个 HTTP Post 并且正文是一个 HTTP 请求字符串的形式。
POST https://accounts.google.com/o/oauth2/token
code={AUTHORIZATION CODE}&client_id={ClientId}&client_secret={ClientSecret}&redirect_uri={REDIRECT URI}&grant_type=authorization_code
这里的响应将是 Json 格式,将是一个刷新令牌和一个访问令牌。注意这里的grant_type 是授权码。
{
"access_token" : "ya29.1.AADtN_VSBMC2Ga2lhxsTKjVQ_ROco8VbD6h01aj4PcKHLm6qvHbNtn-_BIzXMw",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "1/J-3zPA8XR1o_cXebV9sDKn_f5MTqaFhKFxH-3PUPiJ4"
}
由于您的访问令牌将在一小时内到期,您需要使用刷新令牌对其进行刷新
刷新访问令牌。
这也是一个 HTTP POST 调用,并且正文再次采用查询字符串的形式。注意这里的授权类型是刷新令牌
POST https://accounts.google.com/o/oauth2/token
client_id={CLIENT ID}&client_secret={ClientSecret}&refresh_token={REFRESH TOKEN}&grant_type=refresh_token
然后你有一个新的访问令牌。
{
"access_token" : "ya29.1.AADtN_XK16As2ZHlScqOxGtntIlevNcasMSPwGiE3pe5ANZfrmJTcsI3ZtAjv4sDrPDRnQ",
"token_type" : "Bearer",
"expires_in" : 3600
}
推荐阅读
- java - Spring Boot Web 套接字中的实时通知
- ios - 如何在表格视图ios swift中获取谷歌地方自动完成预测中的选定地点坐标
- java - Tomcat 返回 http 状态错误:401,原因短语:未经授权
- java - 使用一台扫描仪在运行时显示可以同时保持和接受输入的多行
- ethereum - 当我添加一个简单的函数时,为什么我的 SmartContract 会耗尽燃料
- android - 如何添加 onclick imageview url 以及如何从 firebase 更新 url
- react-native - 带参数的反应导航
- sql - PostgreSQL 中的查询调优
- wordpress - Woocommerce 设置计费和运输信息
- xamarin.forms - Xamarin 表单,动态添加新项目到列表视图