【问题标题】:Xamarin.Auth with Google APIs: Renew credentials?带有 Google API 的 Xamarin.Auth:续订凭据?
【发布时间】:2014-08-30 08:37:45
【问题描述】:

我正在尝试使用 Xamarin.Auth 和 Xamarin Google-APIs 登录 Google 并访问云端硬盘。我已经设法让几乎所有东西都正常工作,但身份验证令牌似乎在大约一个小时后过期。一切正常运行了一段时间,但大约一个小时后,当我尝试访问时,我收到 Invalid Credentials [401] 错误和泄漏:

Google.Apis.Requests.RequestError
Invalid Credentials [401]
Errors [
    Message[Invalid Credentials] Location[Authorization - header] Reason[authError] Domain[global]
]
: GoogleDriveAgent: FetchRemoteFileList() Failed! with Exception: {0}
[0:] Google.Apis.Requests.RequestError
Invalid Credentials [401]
Errors [
    Message[Invalid Credentials] Location[Authorization - header] Reason[authError] Domain[global]
]
: GoogleDriveAgent: FetchRemoteFileList() Failed! with Exception: {0}

objc[37488]: Object 0x7f1530c0 of class __NSDate autoreleased with no pool in place - just leaking - break on objc_autoreleaseNoPool() to debug
objc[37488]: Object 0x7f151e50 of class __NSCFString autoreleased with no pool in place - just leaking - break on objc_autoreleaseNoPool() to debug
//...more leaks.

我想确保按预期使用 Xamarin.Auth 和 Google API,所以这是我的代码:

在我的 GoogleDriveService 类中,我有一个帐户商店和一个保存的帐户:

AccountStore Store { 
    get {
        if (m_store == null)
            m_store = AccountStore.Create ();
        return m_store;
    }
}

Account SavedAccount { 
    get {
        var savedAccounts = Store.FindAccountsForService ("google");
        m_savedAccount = (savedAccounts as List<Account>).Count > 0 ? (savedAccounts as List<Account>) [0] : null;

        return m_savedAccount;
    }
}

我初始化一个会话并启动服务:

void InitializeSession ()
{
    Authenticator = new GoogleAuthenticator (ClientID, new Uri (RedirectUrl), GoogleDriveScope);
    Authenticator.Completed += HandleAuthenticationCompletedEvents;

    if (SavedAccount != null) {
        Authenticator.Account = SavedAccount;
        StartService ();
    }

    UpdateSignInStatus ();
}

bool StartService ()
{
    try {
        Service = new DriveService (Authenticator);
        return true;
    } catch (Exception ex) {
        // Log exception
        return false;
    }
}

...并响应身份验证完成事件:

void HandleAuthenticationCompletedEvents (object sender, AuthenticatorCompletedEventArgs e)
{
    if (e.IsAuthenticated) {  // Success
        UpdateSignInStatus();
        Store.Save (e.Account, "google");
        Authenticator.Account = e.Account;
        StartService();
        LoginController.DismissViewController(true, null);
    } else {                                    // Cancelled or no success
        UpdateSignInStatus();
        LoginController.DismissViewController(true, null);
        LoginController = null;
        InitializeSession ();  // Start a new session
    }
}

再次,一切正常,有一段时间,但随后身份验证过期。我了解it should,但我认为保存在 AccountStore 中的凭据应该仍然有效。

Xamarin.Auth getting started docs 中,它说再次调用 Save 将覆盖凭据,并且“这对于使存储在帐户对象中的凭据过期的服务很方便。”听起来很有希望...

所以我尝试了另一种方法:拥有一个始终覆盖 getter 中的凭据的 IsSignedIn 属性...

public bool IsSignedIn { 
    get {
        if (Authenticator == null) {
            m_isSignedIn = false;
            return m_isSignedIn;
        }

        if (Authenticator.Account != null) {
            Store.Save (Authenticator.Account, "google"); // refresh the account store
            Authenticator.Account = SavedAccount;
            m_isSignedIn = StartService ();
        } else {
            m_isSignedIn = false;
        }

        return m_isSignedIn;
    }
}

...然后我在任何 API 调用(获取元数据、下载等)之前访问 IsSignedIn。它不起作用:我仍然收到上面显示的过期凭据错误。

这是需要refresh the token的情况吗?我究竟做错了什么?

【问题讨论】:

    标签: authentication google-api xamarin xamarin.auth


    【解决方案1】:

    访问令牌应该相对较快地过期。这就是为什么在第一次身份验证之后,您还会收到一个 refresh_token,如果当前的访问令牌过期,您可以使用它来获取新的访问令牌。连续的身份验证不一定会给您刷新令牌,因此请确保保留收到的令牌!

    在访问令牌失效后,您只需使用 refresh_token 并向 Google 的 OAuth 端点的 token_url 发送 OAuthRequest。

    var postDictionary = new Dictionary<string, string>();
    postDictionary.Add("refresh_token", googleAccount.Properties["refresh_token"]);
    postDictionary.Add("client_id", "<<your_client_id>>");
    postDictionary.Add("client_secret", "<<your_client_secret>>");
    postDictionary.Add("grant_type", "refresh_token");
    
    var refreshRequest = new OAuth2Request ("POST", new Uri (OAuthSettings.TokenURL), postDictionary, googleAccount);
            refreshRequest.GetResponseAsync().ContinueWith (task => {
                if (task.IsFaulted)
                    Console.WriteLine ("Error: " + task.Exception.InnerException.Message);
                else {
                    string json = task.Result.GetResponseText();
                    Console.WriteLine (json);
                    try {
                        <<just deserialize the json response, eg. with Newtonsoft>>
                    }
                    catch (Exception exception) {
                        Console.WriteLine("!!!!!Exception: {0}", exception.ToString());
                        Logout();
                    }
                }
            });
    

    【讨论】:

    • 我看到反复提到的一点是,出于安全原因,移动应用程序不应该拥有客户端密码,因此应该获得短暂的令牌并且没有刷新令牌。我正在使用的流程是尝试将令牌传递给我的服务器,解压缩并发出我自己的令牌,我可以在使用它时对其进行更新。我还没有全部工作;-) 我还没有找到如何从 Xamarin Auth 实际获取令牌。其余的我都在工作。
    猜你喜欢
    • 2019-12-18
    • 2021-11-17
    • 2017-08-23
    • 2021-09-26
    • 2018-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多