Windows Phone 7.1和8.0上的Dropnet身份验证行为

时间:2014-08-03 21:29:01

标签: c# windows-phone-7 windows-phone-8 dropnet

我有一对使用Dropnet进行Dropbox集成的Windows Phone应用程序。一个在Visual Studio Express 2012中开发,目标是7.1,一个在Visual Studio 2013中开发,目标是8.0。

两者都通过NuGet使用Dropnet 1.9.6和RestSharp 104.4.0。

7.1项目使用以下静态类与DropNet身份验证进行交互(以及文件操作,但为了清楚起见,我已将其排除在外)。

public static class DropboxStorage
{
    const string UserToken = "UserToken";
    const string UserSecret = "UserSecret";

    private static DropNetClient _Dropbox;
    public static DropNetClient Dropbox
    {
        get
        {
            if (_Dropbox == null)
            {
                _Dropbox = new DropNetClient(AppKey, AppSecret);
                if (IsAuthenticated)
                {
                    _Dropbox.UserLogin = new UserLogin
                    {
                        Token = (string)IsolatedStorageSettings.ApplicationSettings[UserToken],
                        Secret = (string)IsolatedStorageSettings.ApplicationSettings[UserSecret]
                    };
                }
                _Dropbox.UseSandbox = true;
            }
            return _Dropbox;
        }
    }

    public static bool IsAuthenticated
    {
        get
        {
            return IsolatedStorageSettings.ApplicationSettings.Contains(UserToken) &&
                IsolatedStorageSettings.ApplicationSettings.Contains(UserSecret);
        }
    }

    public static void StartAuthentication(Action<Uri> success, Action<Exception> failure)
    {
        Dropbox.GetTokenAsync(userLogin =>
        {
            var url = Dropbox.BuildAuthorizeUrl(userLogin);
            if (success != null) success(new Uri(url, UriKind.RelativeOrAbsolute));
        }, error =>
        {
            if (failure != null) failure(error);
        });
    }

    public static void CheckAuthentication(Uri uri, Action success, Action<Exception> failure)
    {
        if (uri.LocalPath == "/1/oauth/authorize_submit")
        {
            Dropbox.GetAccessTokenAsync((accessToken) =>
            {
                IsolatedStorageSettings.ApplicationSettings[UserToken] = accessToken.Token;
                IsolatedStorageSettings.ApplicationSettings[UserSecret] = accessToken.Secret;
                IsolatedStorageSettings.ApplicationSettings.Save();
                if (success != null) success();
            },
            (error) =>
            {
                if (failure != null) failure(error);
            });
        }
    }

然后通过带有WebBrowser控件的页面访问它。

XAML

<phone:WebBrowser x:Name="Browser"
                              IsScriptEnabled="True"
                              Navigated="Browser_Navigated"/>

C#

public partial class DropboxPage : PhoneApplicationPage
{
    public DropboxPage()
    {
        InitializeComponent();

         DropboxStorage.StartAuthentication(
                uri => Browser.Navigate(uri),
                ex => ShowException(ex));
     }

    public void Browser_Navigated(object sender, NavigationEventArgs e)
    {
        Debug.WriteLine(e.Uri.OriginalString);
        DropboxStorage.CheckAuthentication(
            e.Uri,
            () => NavigationService.GoBack(),
            ex => ShowException(ex));
    }

    private void ShowException(Exception e)
    {
        MessageBox.Show(e.Message);
        NavigationService.GoBack();
    }
}

显示Dropbox身份验证网页

  • 登录
  • 允许应用访问
  • 成功,应用已连接

,当Dropbox网址包含/1/oauth/authorize_submit时,代码确定身份验证成功。

这一切都很完美,但8.0项目的表现略有不同。

第一个区别是BuildAuthorizeUrl来电返回的网址。

  • 7.1 https://www.dropbox.com/1/oauth/authorize?oauth_token=<token>
  • 8.0 https://api.dropbox.com/1/oauth/authorize?oauth_token=<token>

第二个区别是,一旦应用程序连接,Dropbox网址就不会从/authorize?oauth_token=更改为/authorize_submit,因此永远不会调用GetAccessTokenAsync用户令牌和用户秘密没有存储。

我迄今为止的调查提出了几种解决这个问题的方法

  1. GetAccessTokenAsync电话周围移除网址验证 并吃掉生成的DropboxExceptions
  2. 在最初的BuildAuthorizeUrl电话中添加回调网址。
  3. 我目前正在做的事情1.只是为了让事情顺利进行,但显然这不是一个长期的解决方案。我宁愿避免使用回调网址,因为它似乎对移动应用程序来说过于复杂。

    我之后的目标是让8.0项目的行为方式与7.1项目相同。我已经查看了Dropnet源代码,其中包含https://api.dropbox.com作为它的基本网址,因此我对第一代7.1代码的工作原理更加清晰

2 个答案:

答案 0 :(得分:1)

行为的差异是由8.0项目引起的,该项目使用System.Windows.Interactivity将Navigated事件转换为对ViewModel上的Command的调用。这似乎阻止网站和WebBrowser控件正确交互并重定向到https://www.dropbox.com


当前

XAML

<phone:WebBrowser x:Name="Browser"
                  IsScriptEnabled="True"
                  Visibility="{Binding IsAuthenticated, Converter={StaticResource BoolToInvisibilityConverter}}"
                  Source="{Binding AuthenticateUri}">               
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Navigated" >
            <i:InvokeCommandAction Command="{Binding BrowserNavigated}" 
                                    CommandParameter="{Binding Source, ElementName=Browser}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</phone:WebBrowser>

C#

BrowserNavigated = new RelayCommand<Uri>(u =>
                {                   
                    RemoteStorage.CheckAuthentication(u, () => IsAuthenticated = true, ex => ShowException(ex));
                });

<强>校正的

XAML

        <phone:WebBrowser x:Name="Browser"
                          IsScriptEnabled="True"
                          Visibility="{Binding IsAuthenticated, Converter={StaticResource BoolToInvisibilityConverter}}"
                          Source="{Binding AuthenticateUri}"
                          Navigated="Browser_Navigated"/>

C#

    private void Browser_Navigated(object sender, NavigationEventArgs e)
    {
        ViewModel.BrowserNavigated.Execute(e.Uri);
    }

在这两种情况下,绑定到WebBrowser Source的视图模型的AuthenticateUri属性由DropboxStorage类中的StartAuthentication方法设置。

添加事件处理程序后,8.0项目按预期工作。

答案 1 :(得分:0)

不久前我也开始看到这个问题了。直到那时我的应用程序在WP8上运行良好。我不记得所有的细节,但我看了我的签到修复它,我认为第一个网址的额外页面加载开始发生。 Dropbox没有关于更改的警告。

为了解决这个问题,我等待某个网址出现在LoadCompleted事件中。您使用我认为也应该有效的Navigated事件。

我会像这样修改你的事件处理程序:

public void Browser_Navigated(object sender, NavigationEventArgs e)
{
    if (e.Uri.AbsolutePath == "/1/oauth/authorize_submit")
    {
        DropboxStorage.CheckAuthentication(
            e.Uri,
            () => NavigationService.GoBack(),
            ex => ShowException(ex));
    }
}