2

I'm learning to build Windows 10 apps with an azure backend. I'm using Micosoft Account as my authentication provider. I've learned how to cache access tokens but I'm a little hung up on refresh tokens.

As I understand it, the access token is short lived, and the longer expiring refresh token allows me to get a new access token. I've been trying to follow along with Adrian Hall's book here: https://adrianhall.github.io/develop-mobile-apps-with-csharp-and-azure/chapter2/realworld/#refresh-tokens

My problem is that I don't quite understand when/where to call or how to use "client.RefreshUserAsync();" and the book isn't really clear.

When should I call refresh?? I guess the problem is that the token might expire in the middle of the user using the app, forcing the user to login again right? So do I call refresh every time my user does anything? I'm confused.

Right now, my app just has a single AuthenticateAsync method on my mainpage that executes when a user clicks a login button. It looks for a cached token, if there is one it checks expiration and re-authenticates if expired.

private async System.Threading.Tasks.Task<bool> AuthenticateAsync()
    {
        string message;
        bool success = false;

        var provider = MobileServiceAuthenticationProvider.MicrosoftAccount;

        // Use the PasswordVault to securely store and access credentials
        PasswordVault vault = new PasswordVault();
        PasswordCredential credential = null;

        try
        {
            //try to get an existing credential from the vault.
            credential = vault.FindAllByResource(provider.ToString()).FirstOrDefault();

        }
        catch (Exception)
        {
            //When there is no matching resource an error occurs, which we ignore.
        }

        if (credential != null)
        {

            // Create a user from the stored credentials.
            user = new MobileServiceUser(credential.UserName);
            credential.RetrievePassword();
            user.MobileServiceAuthenticationToken = credential.Password;

            // Set the user from the stored credentials.
            App.MobileService.CurrentUser = user;


            success = true;
            message = string.Format("Cached credentials for user - {0}", user.UserId);

            // Consider adding a check to determine if the token is 
            // expired, as shown in this post: http://aka.ms/jww5vp

            //check expiration
            if (App.MobileService.IsTokenExpired())
            {
                //remove the expired credentials
                vault.Remove(credential);

                try
                {
                    // Login with the identity provider
                    user = await App.MobileService.LoginAsync(MobileServiceAuthenticationProvider.MicrosoftAccount);

                    // Create and store the user credentials.
                    credential = new PasswordCredential(provider.ToString(),
                        user.UserId, user.MobileServiceAuthenticationToken);

                    vault.Add(credential);

                    message = string.Format("Expired credentials caused re-authentication. You are now signed in - {0}", user.UserId);
                    success = true;
                }
                catch (InvalidOperationException)
                {
                    message = "You must log in. Login required.";
                }
            }
        }
        else
        {
            try
            {
                // Login with the identity provider
                user = await App.MobileService.LoginAsync(MobileServiceAuthenticationProvider.MicrosoftAccount);

                // Create and store the user credentials.
                credential = new PasswordCredential(provider.ToString(),
                    user.UserId, user.MobileServiceAuthenticationToken);
                vault.Add(credential);

                message = string.Format("You are now signed in - {0}", user.UserId);
                success = true;
            }
            catch (InvalidOperationException)
            {
                message = "You must log in. Login required.";
            }
        }

        var dialog = new MessageDialog(message);
        dialog.Commands.Add(new UICommand("OK"));
        await dialog.ShowAsync();

        return success;
    }
4

1 回答 1

1

我想问题是令牌可能会在用户使用应用程序的过程中过期,迫使用户再次登录,对吗?

根据你的描述,你使用 Azure 移动应用作为你的 UWP 后端。要访问移动应用程序,我们需要使用访问令牌。如您所知,访问令牌将过期。为了获得新的访问令牌,我们需要使用刷新令牌。如何通过刷新令牌获取访问令牌,请参考这篇文章。以下是详细的http请求信息:

// Line breaks for legibility only

POST /{tenant}/oauth2/token HTTP/1.1
Host: https://login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded

client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&refresh_token=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq...
&grant_type=refresh_token
&resource=https%3A%2F%2Fservice.contoso.com%2F
&client_secret=JqQX2PNo9bpM0uEihUPzyrh    // NOTE: Only required for web apps

从上面的 http 请求中,我们只提供了 client_id、refresh_token、grant_type、resource、client_secret(仅限 Web 应用程序)。所以我们不需要让用户再次登录。

我应该什么时候调用刷新?

如果访问令牌过期,我们访问移动应用程序时会出错。此时我们可以尝试在 catch{} 逻辑中通过刷新令牌来获取新的访问令牌。

于 2017-04-04T08:19:45.007 回答