Asp.net mvc 为什么我没有收到来自Google OAuth请求的RefreshToken?
我试图将Google Calendar集成到我的应用程序中,但我在OAuth授权传递RefreshToken时遇到了一些问题。我收到一个没有问题的AccessToken,但RefreshToken属性为null。请参阅标记为“ERROR HERE:”的行,了解问题所在 我的Asp.Net MVC控制器(名为Asp.net mvc 为什么我没有收到来自Google OAuth请求的RefreshToken?,asp.net-mvc,oauth,oauth-2.0,dotnetopenauth,Asp.net Mvc,Oauth,Oauth 2.0,Dotnetopenauth,我试图将Google Calendar集成到我的应用程序中,但我在OAuth授权传递RefreshToken时遇到了一些问题。我收到一个没有问题的AccessToken,但RefreshToken属性为null。请参阅标记为“ERROR HERE:”的行,了解问题所在 我的Asp.Net MVC控制器(名为OAuthController)如下所示: public ActionResult Index() { var client = CreateClient();
OAuthController
)如下所示:
public ActionResult Index()
{
var client = CreateClient();
client.RequestUserAuthorization(new[] { "https://www.googleapis.com/auth/calendar" }, new Uri("http://localhost/FL.Evaluation.Web/OAuth/CallBack"));
return View();
}
public ActionResult CallBack()
{
if (string.IsNullOrEmpty(Request.QueryString["code"])) return null;
var client = CreateClient();
// Now getting a 400 Bad Request here
var state = client.ProcessUserAuthorization();
// ERROR HERE: The RefreshToken is NULL
HttpContext.Session["REFRESH_TOKEN"] = Convert.ToBase64String(Encoding.Unicode.GetBytes(state.RefreshToken));
return JavaScript("Completed!");
}
private static WebServerClient CreateClient()
{
return
new WebServerClient(
new AuthorizationServerDescription()
{
TokenEndpoint = new Uri("https://accounts.google.com/o/oauth2/token"),
AuthorizationEndpoint = new Uri("https://accounts.google.com/o/oauth2/auth"),
ProtocolVersion = ProtocolVersion.V20
}
, _GoogleClientId, _GoogleSecret);
}
我在Google的API文档中看到,我需要确保请求的
access\u type
设置为offline
,以便发送RefreshToken。如何在验证器请求中设置此值?调整GoogleAuthenticationServer.Description
以拥有一个授权端点URI,该URI在查询字符串中包含?access\u type=offline
。在几个小时的摆弄和为.Net发布的应用程序之后,我什么也没有得到。我决定绕过这些库,直接使用原生HttpRequest和HttpResponse对象。我的MVC控制器的净化代码如下:
private static string _GoogleClientId = "CLIENT_ID";
private static string _GoogleSecret = "SECRET";
private static string _ReturnUrl = "http://localhost/OAuth/CallBack";
public ActionResult Index()
{
return Redirect(GenerateGoogleOAuthUrl());
}
private string GenerateGoogleOAuthUrl()
{
//NOTE: Key piece here, from Andrew's reply -> access_type=offline forces a refresh token to be issued
string Url = "https://accounts.google.com/o/oauth2/auth?scope={0}&redirect_uri={1}&response_type={2}&client_id={3}&state={4}&access_type=offline&approval_prompt=force";
string scope = UrlEncodeForGoogle("https://www.googleapis.com/auth/calendar https://www.googleapis.com/auth/calendar.readonly").Replace("%20", "+");
string redirect_uri_encode = UrlEncodeForGoogle(_ReturnUrl);
string response_type = "code";
string state = "";
return string.Format(Url, scope, redirect_uri_encode, response_type, _GoogleClientId, state);
}
private static string UrlEncodeForGoogle(string url)
{
string UnReservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
var result = new StringBuilder();
foreach (char symbol in url)
{
if (UnReservedChars.IndexOf(symbol) != -1)
{
result.Append(symbol);
}
else
{
result.Append('%' + String.Format("{0:X2}", (int)symbol));
}
}
return result.ToString();
}
class GoogleTokenData
{
public string Access_Token { get; set; }
public string Refresh_Token { get; set; }
public string Expires_In { get; set; }
public string Token_Type { get; set; }
}
public ActionResult CallBack(string code, bool? remove)
{
if (remove.HasValue && remove.Value)
{
Session["GoogleAPIToken"] = null;
return HttpNotFound();
}
if (string.IsNullOrEmpty(code)) return Content("Missing code");
string Url = "https://accounts.google.com/o/oauth2/token";
string grant_type = "authorization_code";
string redirect_uri_encode = UrlEncodeForGoogle(_ReturnUrl);
string data = "code={0}&client_id={1}&client_secret={2}&redirect_uri={3}&grant_type={4}";
HttpWebRequest request = HttpWebRequest.Create(Url) as HttpWebRequest;
string result = null;
request.Method = "POST";
request.KeepAlive = true;
request.ContentType = "application/x-www-form-urlencoded";
string param = string.Format(data, code, _GoogleClientId, _GoogleSecret, redirect_uri_encode, grant_type);
var bs = Encoding.UTF8.GetBytes(param);
using (Stream reqStream = request.GetRequestStream())
{
reqStream.Write(bs, 0, bs.Length);
}
using (WebResponse response = request.GetResponse())
{
var sr = new StreamReader(response.GetResponseStream());
result = sr.ReadToEnd();
sr.Close();
}
var jsonSerializer = new JavaScriptSerializer();
var tokenData = jsonSerializer.Deserialize<GoogleTokenData>(result);
Session["GoogleAPIToken"] = tokenData.Access_Token;
return JavaScript("Refresh Token: " + tokenData.Refresh_Token);
}
private静态字符串\u GoogleClientId=“CLIENT\u ID”;
私有静态字符串_GoogleSecret=“SECRET”;
私有静态字符串_ReturnUrl=”http://localhost/OAuth/CallBack";
公共行动结果索引()
{
返回重定向(generateLogleOAuthull());
}
私有字符串generateLogleOAuthull()
{
//注意:这里的关键部分来自Andrew的回复->access\u type=offline强制发布刷新令牌
字符串Url=”https://accounts.google.com/o/oauth2/auth?scope={0}&redirect_uri={1}&response_type={2}&client_id={3}&state={4}&access_type=offline&approval_prompt=force”;
字符串范围=UrlEncodeForGoogle(“https://www.googleapis.com/auth/calendar https://www.googleapis.com/auth/calendar.readonly“”。替换(“%20”和“+”);
字符串重定向\u uri\u encode=UrlEncodeForGoogle(\u ReturnUrl);
字符串响应\u type=“code”;
字符串状态=”;
返回string.Format(Url、作用域、重定向uri、编码、响应类型、GoogleClientId、状态);
}
私有静态字符串UrlEncodeForGoogle(字符串url)
{
字符串UnReservedChars=“abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzo123456789-”;
var result=新的StringBuilder();
foreach(url中的字符符号)
{
if(无保留字符索引of(符号)!=-1)
{
结果。追加(符号);
}
其他的
{
追加('%'+String.Format(“{0:X2}”,(int)符号));
}
}
返回result.ToString();
}
类GoogleTokenData
{
公共字符串访问\u令牌{get;set;}
公共字符串刷新\u标记{get;set;}
{get;set;}中的公共字符串过期
公共字符串标记\u类型{get;set;}
}
公共ActionResult回调(字符串代码,bool?删除)
{
if(remove.HasValue&&remove.Value)
{
会话[“GoogleAPIToken”]=null;
返回HttpNotFound();
}
if(string.IsNullOrEmpty(code))返回内容(“缺少代码”);
字符串Url=”https://accounts.google.com/o/oauth2/token";
字符串grant\u type=“授权码”;
字符串重定向\u uri\u encode=UrlEncodeForGoogle(\u ReturnUrl);
string data=“code={0}&client_id={1}&client_secret={2}&redirect_uri={3}&grant_type={4}”;
HttpWebRequest request=HttpWebRequest.Create(Url)为HttpWebRequest;
字符串结果=null;
request.Method=“POST”;
request.KeepAlive=true;
request.ContentType=“application/x-www-form-urlencoded”;
string param=string.Format(数据、代码、_GoogleClientId、_GoogleSecret、重定向、uri编码、授权类型);
var bs=Encoding.UTF8.GetBytes(参数);
使用(Stream reqStream=request.GetRequestStream())
{
请求流写入(bs,0,bs.长度);
}
使用(WebResponse=request.GetResponse())
{
var sr=新的StreamReader(response.GetResponseStream());
结果=sr.ReadToEnd();
高级关闭();
}
var jsonSerializer=新的JavaScriptSerializer();
var tokenData=jsonSerializer.Deserialize(结果);
会话[“GoogleAPIToken”]=tokenData.Access_Token;
返回JavaScript(“刷新令牌:+tokenData.Refresh_-Token”);
}
非常感谢您在这段代码中提供了一些代码。只需添加
AccessType = "offline",
到
GoogleOAuth2AuthenticationOptions()
object。我已经精简了我的代码,现在我在尝试查询谷歌时遇到了400个错误请求。我通过手动将httprequest来回编码到谷歌解决了我的问题。我将整理并发布代码作为答案感谢这一非常有用的提示AuthorizationServerDescription descServer=GoogleAuthenticationServer.Description;descServer.AuthorizationEndpoint=新Uri(descServer.AuthorizationEndpoint.ToString()+“?访问类型=脱机”)代码>以这种方式使用它并为我工作