Neutral Scent

App developments & Gadgets

CoreTweetでWebAuthenticationBrokerを利用したUniversal Appを作る

以前、

AsyncOAuthとWebAuthenticationBrokerで作るuniversal App用Twitter APIラッパークラス - Neutral Scent
http://d.hatena.ne.jp/kaorun/20140518/1400392292

というエントリーを書きましたが、最近流行りの.NET用TwitterライブラリCoreTweetでも同様にWebAuthenticationBrokerを利用することが可能です。
WebAuthenticationBrokerを利用することによって、WebViewコントロールを張ってPINをコピペして...、などという煩雑な実装を自前でやる必要が無くなり、勝手にTwitterの認証ページを表示して、認証後にAccessTokenを取得し、APIを叩ける状態まで持っていくことができます。
基本的にCoreTweetでWebAuthenticationBrokerを使う場合のポイントは以下の2点:

  • AutorizeAsync()の第3引数に任意のコールバックURLを入れる(既定の"OOB"だとPIN認証になってしまう)
  • GetTokensAsync()の引数として、PINの代わりにVerifierを入れてやる

少々雑ですが、前回と同様のコードを一応張っておきます。

public class SimpleCoreTweetHandler
{
    // CoreTweet/CoreTweet
    // https://github.com/CoreTweet/CoreTweet
        
    internal const string API_CONSUMER_TOKEN = "";
    internal const string API_CONSUMER_SECRET = "";
    internal const string API_CONSUMER_CALLBACK_URL = "";

    public event EventHandler Authenticated; 
    public OAuth.OAuthSession Session { get; private set; }
    public Tokens Tokens { get; private set; }

    public SimpleCoreTweetHandler()
    {
    }
        
    public async Task Auth()
    {
        Session = await OAuth.AuthorizeAsync(API_CONSUMER_TOKEN, API_CONSUMER_SECRET, API_CONSUMER_CALLBACK_URL);

        var uriAuthorize = Session.AuthorizeUri;
        var uriCallback = new Uri(API_CONSUMER_CALLBACK_URL);
#if WINDOWS_PHONE_APP
        WebAuthenticationBroker.AuthenticateAndContinue(uriAuthorize, uriCallback, null, WebAuthenticationOptions.None);
#else // !WINDOWS_PHONE_APP
        var webAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.None, uriAuthorize, uriCallback);
        if (webAuthenticationResult.ResponseStatus == WebAuthenticationStatus.Success)
        {
            Debug.WriteLine(webAuthenticationResult.ResponseData.ToString());
            await GetAccessToken(webAuthenticationResult.ResponseData.ToString());
        }
        else if (webAuthenticationResult.ResponseStatus == WebAuthenticationStatus.ErrorHttp)
        {
            MessageDialog ErrMsg = new MessageDialog(string.Format("HTTP Error returned by AuthenticateAsync() : " + webAuthenticationResult.ResponseErrorDetail.ToString()), "Sorry");
            await ErrMsg.ShowAsync();
        }
        else
        {
            MessageDialog ErrMsg = new MessageDialog(string.Format("Error returned by AuthenticateAsync() : " + webAuthenticationResult.ResponseStatus.ToString()), "Sorry");
            await ErrMsg.ShowAsync();
        }
#endif // !WINDOWS_PHONE_APP
    }

#if WINDOWS_PHONE_APP
    //Windows Phone Web authentication broker sample in C#, C++, JavaScript for Visual Studio 2013
    //http://code.msdn.microsoft.com/wpapps/Web-Authentication-d0485122
    //How to continue your Windows Phone Store app after calling an AndContinue method (Windows)
    //http://msdn.microsoft.com/en-us/library/dn631755.aspx
    //How to Use the WebAuthenticationBroker for oAuth in a Windows Phone Runtime WP8.1 App | .NET Zone
    //http://dotnet.dzone.com/articles/how-use
    public async void ContinueWebAuthentication(WebAuthenticationBrokerContinuationEventArgs args)
    {
        WebAuthenticationResult result = args.WebAuthenticationResult;

        if (result.ResponseStatus == WebAuthenticationStatus.Success)
        {
            await GetAccessToken(result.ResponseData.ToString());
        }
        else if (result.ResponseStatus == WebAuthenticationStatus.ErrorHttp)
        {
            MessageDialog ErrMsg = new MessageDialog(string.Format("There was an error connecting to Twitter: \n {0}", result.ResponseErrorDetail.ToString()), "Sorry");
            await ErrMsg.ShowAsync();
        }
        else
        {
            MessageDialog ErrMsg = new MessageDialog(string.Format("Error returned: \n{0}", result.ResponseStatus.ToString()), "Sorry");
            await ErrMsg.ShowAsync();
        }
    }
#endif // WINDOWS_PHONE_APP

    private async Task GetAccessToken(string webAuthResultResponseData)
    {
        string responseData = webAuthResultResponseData.Substring(webAuthResultResponseData.IndexOf("oauth_token"));
        var oauthVerifier = responseData
            .Split('&')
            .Where(kv => kv.ToLower().StartsWith("oauth_verifier="))
            .Select(kv => kv.Split('=')[1])
            .FirstOrDefault();
        Tokens = await Session.GetTokensAsync(oauthVerifier);

        if (Authenticated != null)
            Authenticated(this, new EventArgs());
    }

    internal async Task Tweet(string tweets)
    {
        await Tokens.Statuses.UpdateAsync(status => tweets);
    }
}

Windows Phone版では、認証を終わらせるために、アプリが再アクティブ化されるため、App.xaml.csに以下のようなコードを追加する必要があります。(ViewModel.TwitterHandler〜は個々の実装に合わせて変更)

    public sealed partial class App : Application
    {
        protected override void OnActivated(IActivatedEventArgs args)
        {
            base.OnActivated(args);
#if WINDOWS_PHONE_APP
            if (args is WebAuthenticationBrokerContinuationEventArgs)
                ViewModel.SimpleCoreTweetHandler.ContinueWebAuthentication(args as WebAuthenticationBrokerContinuationEventArgs);
#endif // WINDOWS_PHONE_APP
        }
    }

SimpleCoreTweetHandlerのインスタンスを(↑の場合ならViewModel等に)作成してからAuth()を呼んでやり、認証が終わったらCoreTweetでAPIを叩いていくだけです。