我正在将应用从Android移植到Windows Phone 8.1。我需要获取一些需要OAUTh身份验证的数据。我做了一些研究,我认为我需要一个0-legged OAuth身份验证,因为我只有一个密钥&秘密和获取数据的网址。
在Android项目中,代码就像这样(JAVA):
public JSONObject fetchData() {
try {
OAuthConsumer consumer = new DefaultOAuthConsumer(this.context.getString(R.string.consumer_key), this.context.getString(R.string.consumer_secret));
URL fullURL = new URL(url + "&start=" + start + "");
HttpURLConnection request = (HttpURLConnection) fullURL.openConnection();
consumer.sign(request);
request.setConnectTimeout(15000);
request.setRequestMethod("GET");
request.setRequestProperty("Accept", "application/json");
request.setRequestProperty("Accept-Encoding", "gzip");
request.connect();
switch (request.getResponseCode()) {
case 200:
case 201:
BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
br.close();
return new JSONObject(sb.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
我在Windows Phone 8.1项目中的代码是(C#):
public async Task<List<UiTEvent>> FetchEvents(ZoekResultatenExtras zre, double locationLatitude, double locationLongitude)
{
String completeURL;
List<UiTEvent> events = new List<UiTEvent>();
if (zre.CurrentLocation)
{
completeURL = SEARCH_EVENTS_URL + zre.SearchQuery + "&pt=" + locationLatitude + "," + locationLongitude + "";
}
else
{
completeURL = SEARCH_EVENTS_URL + zre.SearchQuery;
}
Debug.WriteLine(completeURL);
using (HttpClient client = new HttpClient())
{
OAuthBase oauth = new OAuthBase();
string normalizedUrl;
string normalizedqueryparameters;
var key = "MY_KEY";
var secret = "MY_SECRET";
var URL = new Uri("http://www.uitid.be/uitid/rest/searchv2/search?fq=type%3Aevent&fq=language%3Anl&group=event&rows=15&q=*%3A*&sfield=physical_gis&sort=geodist%28%29+asc&d=10&datetype=today&fq=-category_id%3A0.3.1.0.0&pt=51.0554827,3.7407583&start=0");
var oauth_nonce = oauth.GenerateNonce();
var oauth_timestamp = oauth.GenerateTimeStamp();
var oauth_signature_method = "HMAC-SHA1";
var oauth_signature = Uri.EscapeDataString(oauth.GenerateSignature(URL, key, secret, null, null, "GET", oauth_timestamp, oauth_nonce, out normalizedUrl, out normalizedqueryparameters));
String dfd = "OAuth oauth_consumer_key=\"" + key + "\", oauth_nonce=\"" + oauth_nonce + "\", oauth_signature=\"" + oauth_signature + "\", oauth_signature_method=\"" + oauth_signature_method + "\", oauth_timestamp=\"" + oauth_timestamp + "\", oauth_version=\"1.0\"";
client.DefaultRequestHeaders.Add("Authorization", dfd);
client.DefaultRequestHeaders.Add("Accept", "application/json");
client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip");
using (HttpResponseMessage response = await (client.GetAsync(completeURL)))
{
if (response.IsSuccessStatusCode)
{
String content = await response.Content.ReadAsStringAsync();
}
}
}
return events;
}
我使用https://code.google.com/p/oauth/issues/detail?id=223
中的OAuthBase.cs当我运行我的项目时,我可以在Charles看到我总是收到响应代码“401 Unauthorized”
我做错了什么?
我让OAuthBase.cs库工作了! 我的代码是:
OAuthBase o = new OAuthBase();
var normalizedUrl = String.Empty;
var normalizedParameters = String.Empty;
var oauth_consumer_key = "MY KEY";
var oauth_consumer_secret = "MY SECRET";
var oauth_timestamp = o.GenerateTimeStamp();
var oauth_nonce = o.GenerateNonce();
var oauth_signature_method = "HMAC-SHA1";
var oauth_signature = o.GenerateSignature(new Uri(completeURL), oauth_consumer_key, oauth_consumer_secret, null, null, "GET", oauth_timestamp, oauth_nonce, out normalizedUrl, out normalizedParameters);
var oauth = "OAuth oauth_consumer_key=\"" + oauth_consumer_key + "\",oauth_nonce=\"" + oauth_nonce + "\",oauth_signature=\"" + Uri.EscapeDataString(oauth_signature) +"\",oauth_signature_method=\"" + oauth_signature_method + "\",oauth_timestamp=\"" + oauth_timestamp + "\",oauth_version=\"1.0\"";
var basestring = o.GenerateSignatureBase(new Uri(completeURL), oauth_consumer_key, null, null, "GET", oauth_timestamp, oauth_nonce, oauth_signature_method, out normalizedUrl, out normalizedParameters);
Debug.WriteLine(completeURL);
Debug.WriteLine(basestring);
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", oauth);
client.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "application/json");
client.DefaultRequestHeaders.TryAddWithoutValidation("Accept-Encoding", "gzip");
using (HttpResponseMessage response = await (client.GetAsync(completeURL)))
{
if (response.IsSuccessStatusCode)
{
String content = await response.Content.ReadAsStringAsync();
Debug.WriteLine(content);
}
}
}
但我仍然遇到一些我想要获取数据的URL的问题。我发现这要归功于一个方便的网站:
我注意到有时我的basetring解码是错误的,这就是为什么它会给出401 Unauthorized错误。
良好的基线:
GET&http%3A%2F%2Fwww.uitid.be%2Fuitid%2Frest%2Fsearchv2%2Fsearch&fq%3Dlanguage%253Anl%26fq%3Dtype%253Aevent%26group%3Devent%26oauth_consumer_key%3Def08c84b91c842bbf4f182d188dd4e57%26oauth_nonce%3DNjM1NDY3MTE0NzI3NTM3MDIw%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1411107473%26oauth_version%3D1.0%26q%3D%252A%253A%252A%26rows%3D15
我的基本字符串:
GET&http%3A%2F%2Fwww.uitid.be%2Fuitid%2Frest%2Fsearchv2%2Fsearch&fq%3Dlanguage%253Anl%26fq%3Dtype%253Aevent%26group%3Devent%26oauth_consumer_key%3Def08c84b91c842bbf4f182d188dd4e57%26oauth_nonce%3DNjM1NDY3MTE0NzI3NTM3MDIw%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1411107473%26oauth_version%3D1.0%26q%3D%2A%253A%2A%26rows%3D15
我的网址中有*字符没有像OAuth那样编码。
对于我的解码,我使用方法:
private static String BuildQueryString(List<StringKeyValue> parameters)
{
if (parameters == null)
{
throw new ArgumentNullException("parameters");
}
StringBuilder builder = new StringBuilder();
foreach (var pair in parameters.Where(p => !String.IsNullOrEmpty(p.Value)))
{
if (builder.Length > 0)
{
builder.Append("&");
}
builder.Append(Uri.EscapeDataString(pair.Key));
builder.Append("=");
builder.Append(Uri.EscapeDataString(pair.Value));
}
return builder.ToString();
}
我认为我需要使用RFC3986编码..但我不知道如何实现它。 我发现了这个相关的问题:How to get Uri.EscapeDataString to comply with RFC 3986
但是Uri.HexEscape方法在WP8.1中不起作用
答案 0 :(得分:2)
我为自己的问题找到了解决方案。
查找与WP8.1兼容的OAuth库:
首先,您需要一个与Windows Phone 8.1兼容的工作库。就我而言,我使用了https://code.google.com/p/oauth/issues/detail?id=223
中的OAuthBase.cs类对您的网址进行编码&amp;参数因此它使用RFC3986(OAuth利用它)
我在使用OAuth时遇到了很多问题(获取数据时出现401 Unauthorized错误),因为我使用方法Uri.EscapeDataString()
对我的URL进行了编码,但是像@()这样的保留字符有问题! '[],
所以我搜索了一个解决方案并找到了这个:How to get Uri.EscapeDataString to comply with RFC 3986。唯一的问题是Uri.HexEscape函数在WP8.1中不再起作用所以我稍微改变了方法。
这个方法可以在这里找到:
private static readonly string[] UriRfc3986CharsToEscape = new[] { "!", "*", "'", "(", ",", ")", "[","]" };
internal static string EscapeUriDataStringRfc3986(string value)
{
StringBuilder escaped = new StringBuilder(Uri.EscapeDataString(value));
for (int i = 0; i < UriRfc3986CharsToEscape.Length; i++)
{
switch (UriRfc3986CharsToEscape[i])
{
case "!":
escaped.Replace(UriRfc3986CharsToEscape[i], "%21");
break;
case "*":
escaped.Replace(UriRfc3986CharsToEscape[i], "%2A");
break;
case "'":
escaped.Replace(UriRfc3986CharsToEscape[i], "%27");
break;
case "(":
escaped.Replace(UriRfc3986CharsToEscape[i], "%28");
break;
case ",":
escaped.Replace(UriRfc3986CharsToEscape[i], "%2C");
break;
case ")":
escaped.Replace(UriRfc3986CharsToEscape[i], "%29");
break;
case "[":
escaped.Replace(UriRfc3986CharsToEscape[i], "%5B");
break;
case "]":
escaped.Replace(UriRfc3986CharsToEscape[i], "%5D");
break;
}
}
return escaped.ToString();
}
构建OAuth标头并将其签名到HttpClient
为了构建OAuth标头,您可以使用OAuthBase.cs中的一些方法:
OAuthBase o = new OAuthBase();
var normalizedUrl = String.Empty;
var normalizedParameters = String.Empty;
var oauth_consumer_key = "MY KEY";
var oauth_consumer_secret = "MY SECRET";
var oauth_timestamp = o.GenerateTimeStamp();
var oauth_nonce = o.GenerateNonce();
var oauth_signature_method = "HMAC-SHA1";
var oauth_signature = o.GenerateSignature(new Uri(completeURL), oauth_consumer_key, oauth_consumer_secret, null, null, "GET", oauth_timestamp, oauth_nonce, out normalizedUrl, out normalizedParameters);
var oauth = "OAuth oauth_consumer_key=\"" + oauth_consumer_key + "\",oauth_nonce=\"" + oauth_nonce + "\",oauth_signature=\"" + Uri.EscapeDataString(oauth_signature) +"\",oauth_signature_method=\"" + oauth_signature_method + "\",oauth_timestamp=\"" + oauth_timestamp + "\",oauth_version=\"1.0\"";
构建OAuth标头字符串后,只需将其添加到HttpClient:
HttpClient client = new HttpClient()
client.DefaultRequestHeaders.Add("Authorization", oauth);
完整代码:
String completeURL = EscapeUriDataStringRfc3986("http://www.myurl.be/*!(),");
OAuthBase o = new OAuthBase();
var normalizedUrl = String.Empty;
var normalizedParameters = String.Empty;
var oauth_consumer_key = "MY KEY";
var oauth_consumer_secret = "MY SECRET";
var oauth_timestamp = o.GenerateTimeStamp();
var oauth_nonce = o.GenerateNonce();
var oauth_signature_method = "HMAC-SHA1";
var oauth_signature = o.GenerateSignature(new Uri(completeURL), oauth_consumer_key, oauth_consumer_secret, null, null, "GET", oauth_timestamp, oauth_nonce, out normalizedUrl, out normalizedParameters);
var oauth = "OAuth oauth_consumer_key=\"" + oauth_consumer_key + "\",oauth_nonce=\"" + oauth_nonce + "\",oauth_signature=\"" + Uri.EscapeDataString(oauth_signature) +"\",oauth_signature_method=\"" + oauth_signature_method + "\",oauth_timestamp=\"" + oauth_timestamp + "\",oauth_version=\"1.0\"";
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", oauth);
client.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "application/json");
client.DefaultRequestHeaders.TryAddWithoutValidation("Accept-Encoding", "gzip");
using (HttpResponseMessage response = await (client.GetAsync(completeURL)))
{
if (response.IsSuccessStatusCode)
{
String content = await response.Content.ReadAsStringAsync();
//DO SOMETHING WITH CONTENT
}
}
}