How to enable App Service Mobile App SSO for UWP

use*_*597 5 azure single-sign-on uwp

I am building a Universal Windows Platform (UWP) app that uses the Azure App Service Mobile App backend as well as the user's OneDrive account. I have 2 requirements for authentication:

  1. If the user is logged in to their UWP device with a Microsoft account (e.g. Windows 10) then I don't want them to be presented with a login prompt (i.e. Single Sign On, re-using their Microsoft account credentials).
  2. I want to have a single authentication event across Azure & OneDrive, i.e. the user authorises once and I re-use that token for both services.

我在Windows Phone 8中使用Azure移动服务执行此操作,方法是使用Live SDK登录,然后将返回的令牌传递给MobileServiceClient.LoginAsync()方法,但是我无法通过Azure移动应用程序在UWP中使用此功能.当我调用相同的方法时,我会收到401 Unauthorised回复.

  • 我已将我的UWP应用程序与商店关联,并在Microsoft帐户开发人员中心设置应用程序,包括从Azure移动应用程序添加重定向URI.
  • 我已经设置了Azure App Service移动应用程序,包括从Microsoft帐户开发人员中心添加客户端ID和密钥.
  • 我已经尝试了很多方法来检索令牌,包括 OnlineIdAuthenticator,WebAuthenticationCoreManagerWebAuthenticationBroker.迄今为止没有人工作过.

我目前在类中使用以下代码LiveAuthenticationService来检索访问令牌:

public async Task<bool> LoginAsync()
{
    AccessToken = null;
    bool success = false;
    OnlineIdAuthenticator onlineIdAuthenticator = new OnlineIdAuthenticator();
    EventWaitHandle waithandle = new ManualResetEvent(false);

    OnlineIdServiceTicketRequest serviceTicketRequest = new OnlineIdServiceTicketRequest(scopes, "DELEGATION");
    UserIdentity result = await onlineIdAuthenticator.AuthenticateUserAsync(serviceTicketRequest);
    if (!string.IsNullOrWhiteSpace(result?.Tickets[0]?.Value))
    {
        currentUserId = result.SafeCustomerId;
        AccessToken = result.Tickets[0].Value;
        success = true;
        waithandle.Set();
    }
    else
    {
        await logger.LogErrorAsync("Error signing in to Microsoft Live",
                                    new Dictionary<string, string> { { "errorCode", result?.Tickets[0]?.ErrorCode.ToString() } });
    }
    waithandle.WaitOne(10000);  //10 second timeout

    return success;
}
Run Code Online (Sandbox Code Playgroud)

And then this to attempt to login to my Azure Mobile App with that token, which uses LiveAuthenticationService from above:

private async Task RefreshUserIdAndAccessToken()
{
    try
    {
        var tcs = new TaskCompletionSource<MobileServiceUser>();

        var authService = new LiveAuthenticationService();
        await UiDispatcher.RunAsync(CoreDispatcherPriority.Normal,
                                    async () =>
                                    {
                                        try
                                        {
                                            await authService.LoginAsync();
                                            var jsonAuthenticationToken = JObject.Parse(@"{""authenticationToken"": """ + authService.AccessToken + @"""}");
                                            tcs.SetResult(await mobileService.LoginAsync(MobileServiceAuthenticationProvider.MicrosoftAccount, jsonAuthenticationToken));
                                        }
                                        catch (Exception ex)
                                        {
                                            tcs.SetException(ex);
                                        }
                                    });

        var user = await tcs.Task;
        currentUserId = user.UserId;
        AccessToken = user.MobileServiceAuthenticationToken;
    }
    catch (Exception ex)
    {
        await logger.LogExceptionAsync(ex,
                                        Constants.LOGGING_DATAKEY_REFRESHACCESSTOKENFAILURE,
                                        currentUserId);
        currentUserId = null;
        AccessToken = null;
    }
}
Run Code Online (Sandbox Code Playgroud)

As stated this results in a 401 Unauthorised response from Azure. I have run Fiddler and the request seems to be correct, the expected authentication token is included in a JSON payload with the request.

UPDATE One thing I can see is that the token issued by the code above is almost 900 characters long, all in the form YnElFkAAcK8bRSQab/FK+PT5n/wA4CPU..., while the token issued if I let Azure Mobile App handle the authentication, i.e. call MobileServiceClient.LoginAsync() without passing a token, is only about 350 characters long and in the form hbGciOi.eyJmdWWxsIiwiRGJn... (notice the period towards the beginning).

这个问题现在真的给我带来了麻烦.没有身份验证工作,我无法发布应用程序,我无法弄清楚如何解决它.任何帮助将不胜感激.

jms*_*and 4

这对我来说是一个很难解决的问题,因为我也面临着这个问题。

最重要的部分是OnlineIdServiceTicketRequest请求应该如下所示:

var mobileServicesTicket = new OnlineIdServiceTicketRequest("https://yourmobileservice.azure-mobile.net/", "JWT");
Run Code Online (Sandbox Code Playgroud)

请注意,我们正在指定您的端点,并请求 JWT 令牌而不是委托。这将获得您正在寻找的 350 多个字符令牌。

这是我正在做的事情的完整代码示例:

public async Task<bool> LoginAsync()
{
  var authenticator = new Windows.Security.Authentication.OnlineId.OnlineIdAuthenticator();
  var mobileServicesTicket = new Windows.Security.Authentication.OnlineId.OnlineIdServiceTicketRequest("https://yourendpoint.azure-mobile.net/", "JWT");

  var ticketRequests = new List<OnlineIdServiceTicketRequest>() { mobileServicesTicket };

  var authResult = await authenticator.AuthenticateUserAsync(ticketRequests, CredentialPromptType.PromptIfNeeded);

  if ((authResult.Tickets.Count == 1) && (authResult.Tickets[0].ErrorCode == 0))
  {                            
      var accessToken = authResult.Tickets[0];          
      var res = await _mobileServiceClient.LoginWithMicrosoftAccountAsync(accessToken.Value);

      return true;
  }
  else
  {          
    return false;
  }
}
Run Code Online (Sandbox Code Playgroud)

_mobileServiceClientMicrosoft.WindowsAzure.MobileServices.MobileServiceClient被注入到类中,并且是对库中对象的引用WindowsAzure.MobileServices

实际上我最终在这里写了一篇关于这个问题的博客文章http://jshapland.com/single-sign-on-with-azure-mobile-services-in-a-uwp-app/