如何为UWP启用App Service Mobile App SSO

时间:2015-09-30 03:59:41

标签: azure single-sign-on uwp

我正在构建一个使用Azure App Service Mobile App后端的通用Windows平台(UWP)应用程序以及用户的OneDrive帐户。我有2个身份验证要求:

  1. 如果用户使用Microsoft帐户登录到他们的UWP设备(例如Windows 10),那么我不希望他们出现登录提示(即单点登录,重新使用他们的Microsoft帐户凭证)。
  2. 我希望在Azure和&amp ;; OneDrive,即用户授权一次,我将该令牌重新用于这两种服务。
  3. 我在Windows Phone 8中使用Azure移动服务执行此操作,方法是使用Live SDK登录,然后将返回的令牌传递给MobileServiceClient.LoginAsync()方法,但是我无法在UWP中使用它使用Azure移动应用程序。当我调用相同的方法时,我会收到401 Unauthorised响应。

    • 我已将我的UWP应用与商店相关联并设置了 Microsoft帐户开发人员中心的申请,包括 从Azure移动应用程序添加重定向URI。
    • 我已经设置了Azure App Service移动应用程序,包括添加 客户ID&来自Microsoft帐户开发人员中心的秘密。
    • 我尝试过多种方法来检索令牌,包括 OnlineIdAuthenticatorWebAuthenticationCoreManagerWebAuthenticationBroker。到目前为止,没有人工作过。

    我目前在类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;
    }
    

    然后尝试使用该令牌登录我的Azure移动应用程序,该令牌使用上面的LiveAuthenticationService

    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;
        }
    }
    

    如上所述,这会导致Azure发出401 Unauthorized响应。我运行了Fiddler并且请求似乎是正确的,预期的身份验证令牌包含在带有请求的JSON有效负载中。

    更新 我可以看到的一件事是,上面代码发出的令牌几乎是900个字符,全部采用YnElFkAAcK8bRSQab/FK+PT5n/wA4CPU...形式,而如果我让Azure Mobile App处理身份验证,则会发出令牌,即调用{{1}没有传递令牌,只有大约350个字符长,格式为MobileServiceClient.LoginAsync()(注意开头的时间段)。

    这个问题现在给我带来了麻烦。我无法在没有身份验证的情况下发布应用,但我无法弄清楚如何修复它。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:4)

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

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

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

请注意,我们正在指定您的端点,并且还请求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;
  }
}

_mobileServiceClient被注入到类中,是对Microsoft.WindowsAzure.MobileServices.MobileServiceClient库中WindowsAzure.MobileServices对象的引用。

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