概述
本主题介绍如何将基于云的身份验证添加到移动应用。 在本教程中,你将使用 Azure 应用服务支持的标识提供者向移动应用的通用 Windows 平台(UWP)快速入门项目添加身份验证。 在移动应用后端成功进行身份验证和授权后,将显示用户 ID 值。
本教程基于移动应用快速入门。 必须先完成本教程 移动应用入门。
注册应用以进行身份验证并配置应用服务
首先,需要在标识提供者的站点上注册应用,然后在移动应用后端设置提供程序生成的凭据。
按照提供商特定的说明配置首选标识提供者:
对要在应用中支持的每个提供商重复上述步骤。
将应用添加到允许的外部重定向 URL
安全身份验证要求为应用定义新的 URL 方案。 这样,身份验证系统就可以在身份验证过程完成后重定向回应用。 在本教程中,我们将在整个过程中使用 url 方案 appname。 但是,可以使用你选择的任何 URL 方案。 您的移动应用程序应该是唯一的。 若要在服务器端启用重定向,请执行以下作:
在 Azure 门户中,选择应用服务。
单击 身份验证/授权 菜单选项。
在 允许的外部重定向 URL中,输入
url_scheme_of_your_app://easyauth.callback
。 此字符串中的 url_scheme_of_your_app 是移动应用程序的 URL 方案。 它应遵循协议的正常 URL 规范(仅使用字母和数字,以字母开头)。 应记下所选字符串,因为需要在多个位置使用 URL 方案调整移动应用程序代码。单击“ 保存”。
限制对经过身份验证的用户的权限
默认情况下,移动应用后端中的 API 可以匿名调用。 接下来,需要限制仅对经过身份验证的客户端的访问。
Node.js 后端(通过 Azure 门户):
在移动应用设置中,单击“简易表” 并选择表。 单击 “更改权限”,选择 “仅限身份验证访问” 作为所有权限的设置,然后单击 “保存”。
.NET 后端 (C#):
在服务器项目中,导航至 Controllers>TodoItemController.cs。 将
[Authorize]
属性添加到 TodoItemController 类,如下所示。 若要仅限制对特定方法的访问,还可以仅将此属性应用于这些方法而不是类。 重新发布服务器项目。[Authorize] public class TodoItemController : TableController<TodoItem>
Node.js 后端(通过 Node.js 代码):
若要要求对表访问进行身份验证,请将以下行添加到 Node.js 服务器脚本:
table.access = 'authenticated';
有关详细信息,请参阅 如何:要求身份验证才能访问表。 若要了解如何从网站下载快速入门代码项目,请参阅 如何:使用 Git下载 Node.js 后端快速入门代码项目。
现在,可以验证是否已禁用对后端的匿名访问。 将 UWP 应用项目设置为启动项目后,部署并运行应用;验证应用启动时是否引发状态代码为 401(未授权)的未经处理的异常。 发生这种情况是因为应用尝试以未认证用户身份访问您的移动应用程序代码,但 TodoItem 表现在需要身份验证。
接下来,在从应用服务请求资源之前,将更新应用以对用户进行身份验证。
将身份验证添加到应用
在 UWP 应用项目文件中MainPage.xaml.cs并添加以下代码片段:
// Define a member variable for storing the signed-in user. private MobileServiceUser user; // Define a method that performs the authentication process // using a Facebook sign-in. private async System.Threading.Tasks.Task<bool> AuthenticateAsync() { string message; bool success = false; try { // Change 'MobileService' to the name of your MobileServiceClient instance. // Sign-in using Facebook authentication. user = await App.MobileService .LoginAsync(MobileServiceAuthenticationProvider.Facebook, "{url_scheme_of_your_app}"); 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; }
此代码使用 Facebook 登录名对用户进行身份验证。 如果您使用的标识提供者不是 Facebook,请将上面 MobileServiceAuthenticationProvider 的值更改为您提供者对应的值。
替换 MainPage.xaml.cs 中的 OnNavigatedTo() 方法。 接下来,将 登录 按钮添加到触发身份验证的应用。
protected override async void OnNavigatedTo(NavigationEventArgs e) { if (e.Parameter is Uri) { App.MobileService.ResumeWithURL(e.Parameter as Uri); } }
将以下代码片段添加到MainPage.xaml.cs:
private async void ButtonLogin_Click(object sender, RoutedEventArgs e) { // Login the user and then load data from the mobile app. if (await AuthenticateAsync()) { // Switch the buttons and load items from the mobile app. ButtonLogin.Visibility = Visibility.Collapsed; ButtonSave.Visibility = Visibility.Visible; //await InitLocalStoreAsync(); //offline sync support. await RefreshTodoItems(); } }
打开 MainPage.xaml 项目文件,找到定义 保存 按钮的元素,并将其替换为以下代码:
<Button Name="ButtonSave" Visibility="Collapsed" Margin="0,8,8,0" Click="ButtonSave_Click"> <StackPanel Orientation="Horizontal"> <SymbolIcon Symbol="Add"/> <TextBlock Margin="5">Save</TextBlock> </StackPanel> </Button> <Button Name="ButtonLogin" Visibility="Visible" Margin="0,8,8,0" Click="ButtonLogin_Click" TabIndex="0"> <StackPanel Orientation="Horizontal"> <SymbolIcon Symbol="Permissions"/> <TextBlock Margin="5">Sign in</TextBlock> </StackPanel> </Button>
将以下代码片段添加到App.xaml.cs:
protected override void OnActivated(IActivatedEventArgs args) { if (args.Kind == ActivationKind.Protocol) { ProtocolActivatedEventArgs protocolArgs = args as ProtocolActivatedEventArgs; Frame content = Window.Current.Content as Frame; if (content.Content.GetType() == typeof(MainPage)) { content.Navigate(typeof(MainPage), protocolArgs.Uri); } } Window.Current.Activate(); base.OnActivated(args); }
打开 Package.appxmanifest 文件,导航到 声明,在 可用声明 下拉列表中,选择 协议 并单击“添加 ”按钮。 现在配置 属性 的 协议 声明。 在 显示名称中,添加你希望展示给应用程序用户的名称。 请在 名称中加入你的 {url_scheme_of_your_app}。
按 F5 键运行应用,单击 登录 按钮,并使用所选标识提供者登录到应用。 登录成功后,应用将运行且不会出现错误,并且能够查询后端并更新数据。
将身份验证令牌存储在客户端上
前面的示例显示了一个标准登录,要求客户端每次启动应用时都联系标识提供者和应用服务。 如果许多客户尝试同时启动应用,此方法不仅效率低下,还可能会遇到与使用情况相关的问题。 更好的方法是缓存应用服务返回的授权令牌,并在使用基于提供程序的登录之前先尝试使用此令牌。
注释
无论使用的是客户端托管服务还是服务托管身份验证,都可以缓存应用服务颁发的令牌。 本教程使用服务管理的身份验证。
在MainPage.xaml.cs项目文件中,使用 语句添加以下:
using System.Linq; using Windows.Security.Credentials;
将 AuthenticateAsync 方法替换为以下代码:
private async System.Threading.Tasks.Task<bool> AuthenticateAsync() { string message; bool success = false; // This sample uses the Facebook provider. var provider = MobileServiceAuthenticationProvider.Facebook; // 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; // Consider adding a check to determine if the token is // expired, as shown in this post: https://aka.ms/jww5vp. success = true; message = string.Format("Cached credentials for user - {0}", user.UserId); } else { try { // Sign in with the identity provider. user = await App.MobileService .LoginAsync(provider, "{url_scheme_of_your_app}"); // Create and store the user credentials. credential = new PasswordCredential(provider.ToString(), user.UserId, user.MobileServiceAuthenticationToken); vault.Add(credential); success = true; message = string.Format("You are now signed in - {0}", user.UserId); } catch (MobileServiceInvalidOperationException) { message = "You must sign in. Sign-In Required"; } } var dialog = new MessageDialog(message); dialog.Commands.Add(new UICommand("OK")); await dialog.ShowAsync(); return success; }
在此版本的 AuthenticateAsync中,应用尝试使用存储在 PasswordVault 中的凭据来访问服务。 如果没有存储的凭据,也会执行常规登录。
注释
缓存令牌可能已过期,在应用正在使用时,身份验证后也可能发生令牌过期。 若要了解如何确定令牌是否已过期,请参阅 检查过期的身份验证令牌。 有关解决与令牌过期相关的授权错误的方法,请参阅帖子 在 Azure 移动服务托管 SDK 中缓存和处理过期的令牌。
重新启动应用两次。
请注意,在第一次启动时,再次需要使用提供程序登录。 但是,第二次重新启动时,将使用缓存的凭据并绕过登录。
后续步骤
完成此基本身份验证教程后,请考虑继续学习以下教程之一: