Web Authenticator

浏览示例。 浏览示例

本文介绍如何使用 .NET Multi-platform App UI (.NET MAUI) IWebAuthenticator接口。 你可以通过该接口启动基于浏览器的身份验证流,此类身份验证流可侦听对注册到应用的特定 URL 的回叫。

IWebAuthenticator 接口的默认实现通过 WebAuthenticator.Default 属性提供。 IWebAuthenticator 接口和 WebAuthenticator 类都包含在 Microsoft.Maui.Authentication 命名空间中。

概述

许多应用需要添加用户身份验证,这通常表示用户能够登录到其现有 Microsoft、Facebook、Google 或 Apple 登录帐户。

提示

Microsoft 身份验证库 (MSAL) 提供了出色的统包解决方案,用于向应用添加身份验证。

如果你有兴趣使用自己的 Web 服务进行身份验证,可以使用 WebAuthenticator 来实现客户端功能。

为什么使用服务器后端

许多身份验证提供程序已转向仅提供显式或两步身份验证流,以确保获得更好的安全性。 这意味着,你将需要提供程序提供的“客户端密码”才能完成身份验证流。 遗憾的是,移动应用并不是存储秘密的好地方,任何存储在移动应用代码、二进制文件或其他文件中的内容都不安全。

最佳做法是使用网络后端作为移动应用和身份验证提供程序之间的中间层。

重要说明

强烈建议在身份验证流程中不使用不利用网络后端的旧版纯移动身份验证库和模式,因为它们在存储客户端机密方面本身就缺乏安全性。

开始使用

如果要访问 WebAuthenticator 功能,需要进行以下特定平台设置。

Android 需要设置意向筛选器,以便处理回调 URI。 这可以通过继承 WebAuthenticatorCallbackActivity 类来实现:

using Android.App;
using Android.Content.PM;

namespace YourNameSpace;

[Activity(NoHistory = true, LaunchMode = LaunchMode.SingleTop, Exported = true)]
[IntentFilter(new[] { Android.Content.Intent.ActionView },
              Categories = new[] { Android.Content.Intent.CategoryDefault, Android.Content.Intent.CategoryBrowsable },
              DataScheme = CALLBACK_SCHEME)]
public class WebAuthenticationCallbackActivity : Microsoft.Maui.Authentication.WebAuthenticatorCallbackActivity
{
    const string CALLBACK_SCHEME = "myapp";

}

如果项目的目标 Android 版本设置为 Android 11 (R API 30) 或更高版本,则必须通过使用 Android 包装可见性要求的查询更新 Android 清单

Platforms/Android/AndroidManifest.xml 文件中,在 manifest 节点中添加以下 queries/intent 节点:

<queries>
  <intent>
    <action android:name="android.support.customtabs.action.CustomTabsService" />
  </intent>
</queries>

使用 WebAuthenticator

API 主要由一个方法 AuthenticateAsync 组成,该方法需要两个参数:

  1. 用于启动 Web 浏览器流的 URL。
  2. 流程最终会回调到 URI,该 URI 已在应用中注册。

结果是 WebAuthenticatorResult,其中包括从回调 URI 中分析出的任何查询参数:

try
{
    WebAuthenticatorResult authResult = await WebAuthenticator.Default.AuthenticateAsync(
        new Uri("https://mysite.com/mobileauth/Microsoft"),
        new Uri("myapp://"));

    string accessToken = authResult?.AccessToken;

    // Do something with the token
}
catch (TaskCanceledException e)
{
    // Use stopped auth
}

WebAuthenticator API 负责在浏览器中启动 URL 并等待至收到回调:

典型的 Web 身份验证流。

如果用户在任何时候取消流,就会抛出 TaskCanceledException

专用身份验证会话

iOS 13 引入了临时的 Web 浏览器 API,使开发者能够将身份验证会话作为专用会话启动。 这使开发者能够请求身份验证会话之间不提供共享 cookie 或浏览数据,并且每次都是全新的登录会话。 这可以通过传递给 AuthenticateAsync 方法的 WebAuthenticatorOptions 参数实现:

try
{
    WebAuthenticatorResult authResult = await WebAuthenticator.Default.AuthenticateAsync(
        new WebAuthenticatorOptions()
        {
            Url = new Uri("https://mysite.com/mobileauth/Microsoft"),
            CallbackUrl = new Uri("myapp://"),
            PrefersEphemeralWebBrowserSession = true
        });

    string accessToken = authResult?.AccessToken;

    // Do something with the token
}
catch (TaskCanceledException e)
{
    // Use stopped auth
}

平台差异

本部分介绍特定平台与网络身份验证 API 之间的差异。

“自定义选项卡”在每当可用时使用,否则系统浏览器将用作回退。

Apple 登录

根据 Apple 的审核指南,如果 Apple 应用使用任何社交登录服务进行身份验证,则还必须提供 Apple 登录选项。 若要将 Apple 登录添加到应用,需要向应用添加使用 Apple 权利登录。 此权利是使用 StringArray 类型的 com.apple.developer.applesignin 密钥定义的:

<key>com.apple.developer.applesignin</key>
<array>
  <string>Default</string>
</array>

有关详细信息,请参阅 developer.apple.com 上的使用 Apple 权利登录

对于 iOS 13 和更高版本,需要调用 AppleSignInAuthenticator.AuthenticateAsync 方法。 这会使用本机 Apple 登录 API,以便用户在这些设备上获得最佳体验。 例如,可以编写共享代码,以便在运行时使用正确的 API:

var scheme = "..."; // Apple, Microsoft, Google, Facebook, etc.
var authUrlRoot = "https://mysite.com/mobileauth/";
WebAuthenticatorResult result = null;

if (scheme.Equals("Apple")
    && DeviceInfo.Platform == DevicePlatform.iOS
    && DeviceInfo.Version.Major >= 13)
{
    // Use Native Apple Sign In API's
    result = await AppleSignInAuthenticator.AuthenticateAsync();
}
else
{
    // Web Authentication flow
    var authUrl = new Uri($"{authUrlRoot}{scheme}");
    var callbackUrl = new Uri("myapp://");

    result = await WebAuthenticator.Default.AuthenticateAsync(authUrl, callbackUrl);
}

var authToken = string.Empty;

if (result.Properties.TryGetValue("name", out string name) && !string.IsNullOrEmpty(name))
    authToken += $"Name: {name}{Environment.NewLine}";

if (result.Properties.TryGetValue("email", out string email) && !string.IsNullOrEmpty(email))
    authToken += $"Email: {email}{Environment.NewLine}";

// Note that Apple Sign In has an IdToken and not an AccessToken
authToken += result?.AccessToken ?? result?.IdToken;

提示

对于非 iOS 13 设备,这将启动 web 身份验证流,也可用于在 Android 和 Windows 设备上启用 Apple 登录。 可在 iOS 模拟器上登录 iCloud 帐户来测试“Apple 登录”功能。

ASP.NET Core 服务器后端

可以将 WebAuthenticator API 与任何 web 后端服务一起使用。 如果要将它与 ASP.NET Core 应用一起使用,请按下列步骤配置 web 应用:

  1. 在 ASP.NET Core Web 应用中设置外部社交身份验证提供程序
  2. .AddAuthentication() 调用中将默认身份验证方案设置为 CookieAuthenticationDefaults.AuthenticationScheme
  3. Startup.cs .AddAuthentication() 调用中使用 .AddCookie()
  4. 必须将所有提供程序配置为 .SaveTokens = true;
services.AddAuthentication(o =>
    {
        o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    })
    .AddCookie()
    .AddFacebook(fb =>
    {
        fb.AppId = Configuration["FacebookAppId"];
        fb.AppSecret = Configuration["FacebookAppSecret"];
        fb.SaveTokens = true;
    });

提示

如果要添加“Apple 登录”,可以使用 AspNet.Security.OAuth.Apple NuGet 包。 可以查看完整的 Startup.cs 示例

添加自定义移动身份验证控制器

使用移动身份验证流,通常直接启动流到用户选择的提供程序。 例如,单击应用登录屏幕上的 "Microsoft" 按钮。 另外,还必须能够通过特定回调 URI 将相关信息返回到应用,以结束身份验证流。

为此,请使用自定义 API 控制器:

[Route("mobileauth")]
[ApiController]
public class AuthController : ControllerBase
{
    const string callbackScheme = "myapp";

    [HttpGet("{scheme}")] // eg: Microsoft, Facebook, Apple, etc
    public async Task Get([FromRoute]string scheme)
    {
        // 1. Initiate authentication flow with the scheme (provider)
        // 2. When the provider calls back to this URL
        //    a. Parse out the result
        //    b. Build the app callback URL
        //    c. Redirect back to the app
    }
}

使用此控制器是为了推断应用请求的方案(提供程序),并启动社交提供程序的身份验证流。 当提供程序回调到 Web 后端时,控制器将分析出结果,并使用参数重定向到应用的回调 URI。

有时,你可能希望将数据(例如提供程序的 access_token)返回给应用,这可通过回调 URI 的查询参数执行。 或者,你可能需要对服务器创建自己的标识,并将自己的令牌重新传递到应用。 选择哪种做法,以及如何完成,这都完全取决于你!

查看完整的控制器示例

注意

上述示例展示如何从第三方身份验证(即 OAuth)提供程序返回访问令牌。 若要获取可用于向 Web 后端本身授权 Web 请求的令牌,应在 Web 应用中创建自己的令牌,并返回该令牌。 ASP.NET Core 身份验证概述包含有关 ASP.NET Core 中的高级身份验证方案的详细信息。