Getting Twitter Access Secret using DotNetOpenAuth in MVC4

耗尽温柔 提交于 2019-12-01 00:48:47
Paul Manzotti

I've been banging my head against a wall with this for a few days now, but I finally have something that works. Would be interested to know if it's a valid solution though!

First off, create a new OAuthClient:

public class TwitterClient : OAuthClient
{
    /// <summary>
    /// The description of Twitter's OAuth protocol URIs for use with their "Sign in with Twitter" feature.
    /// </summary>
    public static readonly ServiceProviderDescription TwitterServiceDescription = new ServiceProviderDescription
    {
        RequestTokenEndpoint =
            new MessageReceivingEndpoint(
                "https://api.twitter.com/oauth/request_token",
                HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
        UserAuthorizationEndpoint =
            new MessageReceivingEndpoint(
                "https://api.twitter.com/oauth/authenticate",
                HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
        AccessTokenEndpoint =
            new MessageReceivingEndpoint(
                "https://api.twitter.com/oauth/access_token",
                HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
        TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
    };

    public TwitterClient(string consumerKey, string consumerSecret) :
        base("twitter", TwitterServiceDescription, consumerKey, consumerSecret) { }

    /// Check if authentication succeeded after user is redirected back from the service provider.
    /// The response token returned from service provider authentication result. 
    protected override AuthenticationResult VerifyAuthenticationCore(AuthorizedTokenResponse response)
    {
        string accessToken = response.AccessToken;
        string accessSecret = (response as ITokenSecretContainingMessage).TokenSecret;
        string userId = response.ExtraData["user_id"];
        string userName = response.ExtraData["screen_name"];

        var extraData = new Dictionary<string, string>()
                            {
                                {"accesstoken", accessToken},
                                {"accesssecret", accessSecret}
                            };
        return new AuthenticationResult(
            isSuccessful: true,
            provider: ProviderName,
            providerUserId: userId,
            userName: userName,
            extraData: extraData);
    }
}

The important part is where you cast the response to an ITokenSecretContainingMessage. It appears that the response has the TokenSecret all along, but it is only on an internal property. By casting it, you get access to a public property. I can't say that I'm a fan of doing this, but then I also don't understand why DotNetOpenAuth the Asp.Net team have hidden the property in the first place. There must be a good reason.

You then register this client in AuthConfig:

OAuthWebSecurity.RegisterClient( new TwitterClient(
    consumerKey: "",
    consumerSecret: ""), "Twitter", null);

Now, in the ExternalLoginCallback method on the AccountController, the accessSecret is available in the ExtraData dictionary.

The DotNetOpenAuth.AspNet.Clients.TwitterClient class only allows authentication, not authorization. So you wouldn't be able to post tweets as that user if you use that class.

Instead, you can use DotNetOpenAuth.ApplicationBlock.TwitterConsumer, which does not share this limitation and you can even copy the source code for this type into your application and extend it as necessary.

You should be able to enhance the TwitterConsumer class (once you've copied it into your own project) to implement the required interface so that the OAuthWebSecurity class will accept it. Otherwise, you can just use TwitterConsumer directly yourself to both authenticate and authorize your web app so the user only sees Twitter once but you get all the control you need. After all, folks using ASP.NET have been using TwitterConsumer to both login and authorize for subsequent calls to Twitter for long before OAuthWebSecurity even existed.

For a WebForms project template which references Microsoft.AspNet.Membership.OpenAuth in AuthConfig.cs instead of Microsoft.Web.WebPages.OAuth (MVC4 Internet Application) I was able to modify Paul Manzotti's answer to get it to work:

  1. Create a custom twitter client class that derives from DotNetOpenAuth.AspNet.Clients.TwitterClient

    public class CustomTwitterClient : TwitterClient { public CustomTwitterClient(string consumerKey, string consumerSecret) : base(consumerKey, consumerSecret) { }

    protected override AuthenticationResult VerifyAuthenticationCore(AuthorizedTokenResponse response)
    {
        //return base.VerifyAuthenticationCore(response);
        string accessToken = response.AccessToken;
        string accessSecret = (response as ITokenSecretContainingMessage).TokenSecret;
        string userId = response.ExtraData["user_id"];
        string userName = response.ExtraData["screen_name"];
    
        var extraData = new Dictionary<string, string>()
                        {
                            {"accesstoken", accessToken},
                            {"accesssecret", accessSecret}
                        };
        return new AuthenticationResult(
            isSuccessful: true,
            provider: ProviderName,
            providerUserId: userId,
            userName: userName,
            extraData: extraData);
    }
    

    }

  2. Add the custom client in AuthConfig.cs

    public static void RegisterOpenAuth()
    {
        OpenAuth.AuthenticationClients.Add("Twitter", () => new CustomTwitterClient(
            consumerKey: ConfigurationManager.AppSettings["twitterConsumerKey"], 
            consumerSecret: ConfigurationManager.AppSettings["twitterConsumerSecret"]));
    }
    

Ta-dow! Now you can haz access secret.

You can extract the oauth_token_secret from OAuthWebSecurity by designing your own TokenManager. You can register the token manager when you register your Twitter client in OAuthWebSecurity.RegisterClient.

I used this method to extract the needed values to be able to bypass the authorization step of the Linq-to-Twitter lib.

I will soon post my solution at my blog.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!