我正在为WP8编写自己的Box SDK,以充分利用任务。我无法获得访问令牌。我总是把这作为回报:
{"error":"invalid_request","error_description":"Invalid grant_type parameter or parameter missing"}
我正在使用的代码(所有在C#中)是:
internal const String TokenURL = "https://api.box.com/oauth2/token";
CloudHttpAsync.DownloadResponceStreamAsync
(
CloudHttpAsync.PostAsync
(
TokenURL,
new MemoryStream
(
UTF8Encoding.UTF8.GetBytes
(
HttpUtility.UrlEncode
(
String.Format
(
"grant_type=authorization_code&code={0}&client_id={1}&client_secret={2}&redirect_uri={3}",
Code,
ClientID,
ClientSecret,
RedirectURI
)
)
)
),
null,
null
),
null
).ContinueWith((AsyncStream) =>
{
try
{
if (AsyncStream.Exception != null)
{
TaskSource.TrySetException(AsyncStream.Exception.InnerExceptions);
return;
}
String Result = "";
using (StreamReader Reader = new StreamReader(AsyncStream.Result))
{
Result = Reader.ReadToEnd();
}
BoxAuthToken Token = JsonConvert.DeserializeObject<BoxAuthToken>(Result);
TaskSource.TrySetResult(Token);
}
catch (Exception e)
{
TaskSource.TrySetException(e);
}
});
和
public static Task<HttpWebResponse> PostAsync(String URL, Stream UploadData, IRequestSigner Signer, IProgress<NetworkProgress> Progress)
{
TaskCompletionSource<HttpWebResponse> TaskSource = new TaskCompletionSource<HttpWebResponse>();
HttpWebRequest Request = WebRequest.CreateHttp(URL);
Request.Method = "POST";
if (Signer != null)
{
Signer.Sign(Request).ContinueWith((o) =>
{
if (o.Exception != null)
{
TaskSource.TrySetException(o.Exception.InnerExceptions);
return;
}
UploadDataAsync(Request, UploadData, Progress).ContinueWith((AsyncRequest) =>
{
if (AsyncRequest.Exception != null)
{
TaskSource.TrySetException(AsyncRequest.Exception.InnerExceptions);
return;
}
GetResponceAsync(Request).ContinueWith((AsyncResponce) =>
{
if (AsyncResponce.Exception != null)
{
TaskSource.TrySetException(AsyncResponce.Exception.InnerExceptions);
return;
}
TaskSource.TrySetResult(AsyncResponce.Result);
});
});
});
}
else
{
UploadDataAsync(Request, UploadData, Progress).ContinueWith((AsyncRequest) =>
{
if (AsyncRequest.Exception != null)
{
TaskSource.TrySetException(AsyncRequest.Exception.InnerExceptions);
return;
}
GetResponceAsync(Request).ContinueWith((AsyncResponce) =>
{
if (AsyncResponce.Exception != null)
{
TaskSource.TrySetException(AsyncResponce.Exception.InnerExceptions);
return;
}
TaskSource.TrySetResult(AsyncResponce.Result);
});
});
}
return TaskSource.Task;
}
internal static Task<HttpWebRequest> UploadDataAsync(HttpWebRequest Request, Stream Data, IProgress<NetworkProgress> Progress)
{
TaskCompletionSource<HttpWebRequest> TaskSource = new TaskCompletionSource<HttpWebRequest>();
if (Data.Length != 0)
{
Request.ContentLength = Data.Length;
Request.AllowWriteStreamBuffering = false;
Request.BeginGetRequestStream(new AsyncCallback((IAR) =>
{
try
{
using (Stream UploadStream = Request.EndGetRequestStream(IAR))
{
Int64 Upload = 0;
Int64 TotalUploaded = 0;
Int64 Total = Data.Length;
Byte[] Buffer = new Byte[4096];
while (TotalUploaded < Total)
{
Upload = Data.Read(Buffer, 0, Buffer.Length);
TotalUploaded += Upload;
UploadStream.Write(Buffer, 0, (Int32)Upload);
if (Progress != null)
{
Progress.Report(new NetworkProgress()
{
Operation = NetworkOperation.Uploading,
TotalBytes = Total,
BytesProcessed = TotalUploaded
});
}
}
}
TaskSource.TrySetResult(Request);
}
catch (Exception e)
{
TaskSource.TrySetException(e);
}
}),
null);
}
else
{
TaskSource.TrySetResult(Request);
}
return TaskSource.Task;
}
internal static Task<HttpWebResponse> GetResponceAsync(HttpWebRequest Request)
{
TaskCompletionSource<HttpWebResponse> TaskSource = new TaskCompletionSource<HttpWebResponse>();
Request.BeginGetResponse(new AsyncCallback((IAR) =>
{
try
{
HttpWebResponse Responce = (HttpWebResponse)Request.EndGetResponse(IAR);
TaskSource.TrySetResult(Responce);
}
catch (Exception e)
{
if (e is WebException && (e as WebException).Response.ContentLength > 0)
{
TaskSource.TrySetResult((HttpWebResponse)(e as WebException).Response);
}
else
{
TaskSource.TrySetException(e);
}
}
}),
null);
return TaskSource.Task;
}
public static Task<StreamAndLength> GetResponceStreamAsync(Task<HttpWebResponse> Task)
{
TaskCompletionSource<StreamAndLength> TaskSource = new TaskCompletionSource<StreamAndLength>();
Task.ContinueWith((AsyncHWR) =>
{
if (AsyncHWR.Exception != null)
{
TaskSource.TrySetException(AsyncHWR.Exception.InnerExceptions);
return;
}
HttpWebResponse Responce = AsyncHWR.Result;
TaskSource.TrySetResult( new StreamAndLength() { Stream = Responce.GetResponseStream(), Length = Responce.ContentLength });
});
return TaskSource.Task;
}
public static Task<MemoryStream> DownloadResponceStreamAsync(Task<HttpWebResponse> Task, IProgress<NetworkProgress> Progress)
{
TaskCompletionSource<MemoryStream> TaskSource = new TaskCompletionSource<MemoryStream>();
GetResponceStreamAsync(Task).ContinueWith((AsyncStream) =>
{
if (AsyncStream.Exception != null)
{
TaskSource.TrySetException(AsyncStream.Exception.InnerExceptions);
return;
}
MemoryStream MemStream = new MemoryStream();
MemStream.SetLength(AsyncStream.Result.Length);
Int64 CurrentRead = 0;
Int64 TotalRead = 0;
Int64 Total = AsyncStream.Result.Length;
Byte[] Buffer = new Byte[4096];
using (Stream DownloadStream = AsyncStream.Result.Stream)
while (TotalRead < Total)
{
CurrentRead = DownloadStream.Read(Buffer, 0, Buffer.Length);
MemStream.Write(Buffer, 0, (Int32)CurrentRead);
TotalRead += CurrentRead;
if (Progress != null)
{
Progress.Report(new NetworkProgress()
{
Operation = NetworkOperation.Downloading,
TotalBytes = Total,
BytesProcessed = TotalRead
});
}
}
MemStream.Position = 0;
TaskSource.TrySetResult(MemStream);
});
return TaskSource.Task;
}
internal class StreamAndLength
{
public Stream Stream { get; set; }
public Int64 Length { get; set; }
}
很抱歉有很多代码,我喜欢一般写:)
编辑:原始回复(删除了ClientID和客户端密钥)
当URL编码每个值时:
POST https://api.box.com/oauth2/token HTTP/1.1
Accept: */*
Content-Length: 196
Accept-Encoding: identity
User-Agent: NativeHost
Host: api.box.com
Connection: Keep-Alive
Cache-Control: no-cache
grant_type=authorization_code&code=JknaLbfT6lAXmey3FLYrp9eg1jMbpFuQ&client_id=[subbed]&client_secret=[subbed]&redirect_uri=https%3a%2f%2fCloudBoxWP8
返回:
HTTP/1.1 400 Bad Request
Server: nginx
Date: Fri, 01 Mar 2013 07:35:22 GMT
Content-Type: application/json
Connection: keep-alive
Set-Cookie: box_visitor_id=51305a3a187f34.52738262; expires=Sat, 01-Mar-2014 07:35:22 GMT; path=/; domain=.box.com
Set-Cookie: country_code=US; expires=Tue, 30-Apr-2013 07:35:22 GMT; path=/
Cache-Control: no-store
Content-Length: 99
{"error":"invalid_request","error_description":"Invalid grant_type parameter or parameter missing"}
当URL编码整个字符串时:
POST https://api.box.com/oauth2/token HTTP/1.1
Accept: */*
Content-Length: 214
Accept-Encoding: identity
User-Agent: NativeHost
Host: api.box.com
Connection: Keep-Alive
Cache-Control: no-cache
grant_type%3dauthorization_code%26code%3d3ikruv5elfdw3fOP55aMDSX7ybLqBFlA%26client_id%3d[subbed]%26client_secret%3d[subbed]%26redirect_uri%3dhttps%3a%2f%2fCloudBoxWP8
返回
HTTP/1.1 400 Bad Request
Server: nginx
Date: Fri, 01 Mar 2013 07:46:03 GMT
Content-Type: application/json
Connection: keep-alive
Set-Cookie: box_visitor_id=51305cbb339de4.03221876; expires=Sat, 01-Mar-2014 07:46:03 GMT; path=/; domain=.box.com
Set-Cookie: country_code=US; expires=Tue, 30-Apr-2013 07:46:03 GMT; path=/
Cache-Control: no-store
Content-Length: 99
{"error":"invalid_request","error_description":"Invalid grant_type parameter or parameter missing"}
无网址编码:
POST https://api.box.com/oauth2/token HTTP/1.1
Accept: */*
Content-Length: 190
Accept-Encoding: identity
User-Agent: NativeHost
Host: api.box.com
Connection: Keep-Alive
Cache-Control: no-cache
grant_type=authorization_code&code=2wgIzfqhvIgRtVIp2ZvqZ9X8R5u0QNaf&client_id=[subbed]&client_secret=[subbed]&redirect_uri=https://CloudBoxWP8
返回:
HTTP/1.1 400 Bad Request
Server: nginx
Date: Fri, 01 Mar 2013 07:50:31 GMT
Content-Type: application/json
Connection: keep-alive
Set-Cookie: box_visitor_id=51305dc751d7f5.67064854; expires=Sat, 01-Mar-2014 07:50:31 GMT; path=/; domain=.box.com
Set-Cookie: country_code=US; expires=Tue, 30-Apr-2013 07:50:31 GMT; path=/
Cache-Control: no-store
Content-Length: 99
{"error":"invalid_request","error_description":"Invalid grant_type parameter or parameter missing"}
答案 0 :(得分:3)
它未列在Box API文档的任何位置,但检索访问令牌的请求需要标题Content-Type: application/x-www-form-urlencoded
我也被困在这一部分上一段时间,直到我在StackOverflow上找到答案。我忘记了它的链接。
答案 1 :(得分:0)
请求/响应会有所帮助。看起来你是UrlEncoding整个查询字符串而不是每个值。哪个会提交给我们: grant_type%3Dauthorization_code%26code%3Dxyz%26client_id%3Dxyz%26client_secret%3Dxyz%26redirect_uri%3Dxyz
而不是: grant_type = authorization_code&安培;代码= XYZ&安培; CLIENT_ID = XYZ&安培; client_secret = XYZ&安培; REDIRECT_URI = XYZ
答案 2 :(得分:0)
我认为在您的请求正文中包含redirect_uri
可能会使事情变得复杂,特别是因为它看起来设置为无效值(https://CloudBoxWP8
)您可以通过将应用设置为处理来解决此问题自定义协议(cloudboxwp8://
)并预先配置Box以在授予令牌时重定向到该协议。
cloudboxwp8
。 cloudboxwp8://tokengranted
。在这里实现您的令牌处理逻辑。redirect_uri
字段中,将值设置为步骤2中的自定义协议和端点。保存更改。redirect_uri
并再次尝试您的请求。答案 3 :(得分:0)
Dictionary<string, string> contentList = new Dictionary<string, string>();
contentList.Add("code", code);
contentList.Add("client_id", client_id);
contentList.Add("client_secret", clientSecret);
contentList.Add("redirect_uri", redirectUri);
contentList.Add("grant_type", "authorization_code");
FormUrlEncodedContent content = new FormUrlEncodedContent(contentList);
var response = await client.PostAsync(baseURL, content);
YouTubeAutenticationResponse res = JsonConvert.DeserializeObject<YouTubeAutenticationResponse>(await response.Content.ReadAsStringAsync());
public class YouTubeAutenticationResponse
{
[JsonProperty("access_token")]
public string AccessToken { get; set; }
[JsonProperty("token_type")]
public string TokenType { get; set; }
[JsonProperty("expires_in")]
public string ExpiresIn { get; set; }
[JsonProperty("refresh_token")]
public string RefreshToken { get; set; }
}