azure - 如何为 UWP 启用应用服务移动应用 SSO

标签 azure single-sign-on uwp

我正在构建一个通用 Windows 平台 (UWP) 应用,该应用使用 Azure 应用服务移动应用后端以及用户的 OneDrive 帐户。我对身份验证有 2 个要求:

  1. 如果用户使用 Microsoft 帐户(例如 Windows 10)登录其 UWP 设备,那么我不希望向他们显示登录提示(即单点登录、重新使用其 Microsoft 帐户凭据) .
  2. 我希望跨 Azure 和 OneDrive 进行单一身份验证事件,即用户授权一次,然后我为这两项服务重复使用该 token 。

我在 Windows Phone 8 中使用 Azure 移动服务执行此操作,方法是使用 Live SDK 登录,然后将返回的 token 传递给 MobileServiceClient.LoginAsync() 方法,但是我无法获取这可以在 UWP 中与 Azure 移动应用程序一起使用。当我调用相同的方法时,我收到 401 Unauthorized 响应。

  • 我已将我的 UWP 应用与商店关联并设置 在 Microsoft 帐户开发人员中心申请,包括 从 Azure 移动应用添加重定向 URI。
  • 我已设置 Azure 应用服务移动应用,包括添加 来自 Microsoft 帐户开发人员中心的客户端 ID 和密码。
  • 我尝试了多种方法来检索 token ,包括 OnlineIdAuthenticatorWebAuthenticationCoreManagerWebAuthenticationBroker。到目前为止还没有任何效果。

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

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

然后尝试使用该 token 登录我的 Azure 移动应用程序,该 token 使用上面的 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 未经授权的响应。我已经运行了 Fiddler,请求似乎是正确的,预期的身份验证 token 包含在请求的 JSON 负载中。

更新 我可以看到的一件事是,上面的代码发出的 token 几乎有 900 个字符长,全部采用 YnElFkAAcK8bRSQab/FK+PT5n/wA4CPU... 的形式,而如果我让 Azure 发出的 token 移动应用程序处理身份验证,即调用 MobileServiceClient.LoginAsync() 而不传递 token ,长度仅为约 350 个字符,格式为 hbGciOi.eyJmdWWxsIiwiRGJn... (注意接近开始的时期)。

这个问题现在确实给我带来了麻烦。如果没有身份验证工作,我无法发布该应用程序,并且我不知道如何修复它。任何帮助将不胜感激。

最佳答案

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

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

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

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

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

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 被注入(inject)到类中,并且是对 WindowsAzure.MobileServices 库中的 Microsoft.WindowsAzure.MobileServices.MobileServiceClient 对象的引用。

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

关于azure - 如何为 UWP 启用应用服务移动应用 SSO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32857551/

相关文章:

windows - 等效于 system.Reflection.Assembly.GetExecutingAssembly().FullName

azure - "Storage account management operations"和客户端限制错误

c# - UWP - 文本框验证标志

java - 为 Azure 存储访问生成 SAS

certificate - 公钥/私钥认证和签名

authentication - 如何创建单点登录体验?

ldap - 单点登录 : SAML vs LDAP?

c# - 在 UWP 应用程序(通用应用程序)中呈现电子书(比如 .epub 和 .pdf)

javascript - 向 Azure Blob 存储 [REST API][Azure Blob 存储] 发出 GET 请求时授权失败

Azure 数据工厂管道日志