Ostatnio wspomniałem o problemach, na jakie możemy natrafić bawiąc się OAuth w wersji 1. W sieci istnieje wiele różnych providerów, skracających nasze męki przy autoryzacji, jednak wcale nie ukracają one mąk jakie musimy przejść gdy chcemy coś więcej niż tylko autoryzację.

Na szczęście mały projekt RestSharp przychodzi nam na ratunek.

Dzięki niemu za pomocą kilku prostych metod, możemy dodać nagłówek authorization do zapytania z odpowiednimi parametrami jak iż z automatycznym podpisywaniem zapytań. Przez co nie musimy się męczyć w tworzeniu osobnego kodu do podpisywania requestów. Dużo szybciej w ten sposób możemy pisać nasz kod.

Dla przykładu, jeżeli chcemy pobrać request token w Flickr wystarczy że wykonamy taki o to kod:

// global, only once added, rest of the code reuse it
private const string ApiBaseUrl = "http://api.flickr.com/services";
private const string OAuthBaseUrl = "http://www.flickr.com/services";
private const string OAuthTokenKey = "oauth_token";
private const string OAuthTokenSecretKey = "oauth_token_secret";
private const string OAuthVerifierKey = "oauth_verifier";
private const string CallBackUri = "http://url";

private readonly string _consumerKey;
private readonly string _consumerSecret;
private readonly string _requestToken;
private readonly string _perms;
private readonly IRestClientFactory _restClientFactory;

private void retrieve_request_token()
{
    IRestResponse response;
            
    try
    {
        var restClient = _restClientFactory.CreateRestClient(OAuthBaseUrl);
        restClient.Authenticator = OAuth1Authenticator.ForRequestToken(_consumerKey
            , _consumerSecret
            , CallBackUri);

        var request = new RestRequest("oauth/request_token", Method.POST);
        response = restClient.Execute(request);
    }
    catch (Exception exception)
    {
        //
    }

    // Grab the params which should have the request token info.
    var parameters = HttpUtility.ParseQueryString(response.Content);
    var oAuthToken = parameters[OAuthTokenKey];
    // rememer that somewhere
    var oAuthTokenSecret = parameters[OAuthTokenSecretKey];
    _requestToken = oAuthTokenSecret;

    var request = new RestRequest("oauth/authorize");
    request.AddParameter(OAuthTokenKey, oAuthToken);

    if (string.IsNullOrEmpty(_perms) == false)
    {
        request.AddParameter("perms", _perms);
    }

    var restClient = _restClientFactory.CreateRestClient(OAuthBaseUrl);
    // this should redirect user to login page in flickr
    // this page will then redirect to CAllbackUri
}

Powyższy kod zwróci nam query string zawierający kod weryfikujący, który można wykorzystać do pobrania access I secret token:

private IToken get_params_from_callbacl(NameValueCollection parameters)
{
    var oAuthToken = parameters[OAuthTokenKey];
    var oAuthVerifier = parameters[OAuthVerifierKey];
            
    return new TokenImp
    {
        Token = oAuthToken,
        Verifier = oAuthVerifier
    };
}

private IToken retrieve_access_token(IToken verifierResult)
{
    IRestResponse response;
    try
    {
        var restClient = _restClientFactory.CreateRestClient(OAuthBaseUrl);
        var accessTokenAuthenticator = OAuth1Authenticator.ForAccessToken(_consumerKey
            , _consumerSecret
            , verifierResult.Token
            , _requestToken.IsNullOrEmpty() ? null : _requestToken
            , verifierResult.Verifier);

        var request = new RestRequest("oauth/access_token", Method.POST);
        response = restClient.Execute(request);
    }
    catch (Exception exception)
    {
        //
    }

    var parameters = HttpUtility.ParseQueryString(response.Content);
    return new TokenImp
    {
        Token = parameters[OAuthTokenKey],
        TokenSecret = parameters[OAuthTokenSecretKey]
    };
}

I sprawdzić czy wszystko się powiodło za pomocą metody login:

private FlickrLoginResult verify_login(IToken accessToken)
{
    IRestResponse<FlickrLoginResult> response;
    try
    {
        var restClient = _restClientFactory.CreateRestClient(ApiBaseUrl);

        restClient.Authenticator = OAuth1Authenticator.ForProtectedResource(_consumerKey
            , _consumerSecret
            , accessToken.Token
            , accessToken.TokenSecret);

        var request = new RestRequest("rest");
        request.AddParameter("nojsoncallback", 1);
        request.AddParameter("format", "json");
        request.AddParameter("method", "flickr.test.login");

        response = restClient.Execute<FlickrLoginResult>(request);
    }
    catch (Exception exception)
    {
        //
    }

    return response.Data;
}

public class FlickrLoginResult
{
    public UserInner User { get; set; }
    public string Stat { get; set; }

    public class UserInner
    {
        public string Id { get; set; }

        public UsernameInner Username { get; set; }

        public class UsernameInner
        {
            public string _content { get; set; }
        }
    }
}

Prawda, że dużo prościej i szybciej napisać coś takiego niż robić to ręcznie i sememu? Im więcej pracuje z RestSharp, tym bardziej mi się on podoba :)

Znacie może jakieś inne biblioteki, które coś takiego umożliwiają i są przynajmniej tak proste w użyciu jak RestSharp?