如何在Windows Phone 8.1中执行0-legged OAuth

时间:2014-09-15 12:37:02

标签: c# oauth windows-phone-8.1

我正在将应用从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”

我做错了什么?

更新1:

我让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中不起作用

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                 
                }
            }
        }