如何使用适用于 Azure 移动应用的 ASP.NET Framework SDK
本主题说明如何在关键的 Azure 应用服务移动应用方案中使用 .NET 后端服务器 SDK。 借助 Azure 移动应用 SDK 可从 ASP.NET 应用程序使用移动客户端。
创建 Azure 移动应用 ASP.NET Framework 后端
可使用 Visual Studio 2019 创建 ASP.NET Framework 应用。
- 选择“ASP.NET Web 应用程序 (.NET Framework)”模板。 如果定位此模板时遇到问题,请选择“C#”、“所有平台”和“Web”。
- 选择应用程序的名称和位置后,选择“Web API”项目模板。 将为应用程序安装正确的基本服务集合。
下载并初始化 SDK
SDK 提供了入门使用 Azure 移动应用所需的基本功能,可在 NuGet.org 获取。 安装此包:
- 右键单击项目,然后选择“管理 NuGet 包...”。
- 在“浏览”选项卡上,在搜索框中输入
Microsoft.Azure.Mobile.Server
,然后按 Enter。 - 选择
Microsoft.Azure.Mobile.Server.Quickstart
包。 - 单击“安装” 。
- 按照提示完成安装。
重复此步骤安装 Microsoft.Owin.Host.SystemWeb
。
注意
请勿更新用作依赖项的包,例如 Newtonsoft.JSON
或 System.IdentityModel.Jwt
。 在许多情况下,这些包的 API 已更改,现在与适用于 ASP.NET Framework 的 Azure 移动应用不兼容。
初始化服务器项目
Azure 移动应用服务器项目的初始化方式类似其他 ASP.NET Framework 项目,是通过提供 OWIN 启动类来完成的。 添加 OWIN 启动类:
右键单击项目,然后选择“添加”>“新项”
选择“Web”>“常规”,然后选择“OWIN 启动类”模板。
输入启动名称
Startup.cs
。Startup.cs
文件的内容应类似于以下代码:using Microsoft.Azure.Mobile.Server.Config; using Microsoft.Owin; using Owin; using System.Web.Http; [assembly: OwinStartup(typeof(WebApplication1.Startup))] namespace WebApplication1 { public class Startup { public void Configuration(IAppBuilder app) { HttpConfiguration config = new HttpConfiguration(); new MobileAppConfiguration() // no added features .ApplyTo(config); app.UseWebApi(config); } } }
OwinStartup
命名空间和类名将有所不同,具体取决于项目。 具体而言,应替换方法Configuration()
的内容,并相应调整using
指令。
若要启用单个功能,必须在调用 ApplyTo 之前对 MobileAppConfiguration 对象调用扩展方法。 例如,以下代码在初始化期间,将默认路由添加到具有属性 [MobileAppController]
的所有 API 控制器:
new MobileAppConfiguration()
.MapApiControllers()
.ApplyTo(config);
将以下设置视为“常规”用法,使表和 API 控制器使用实体框架访问 SQL 服务。
new MobileAppConfiguration()
.AddMobileAppHomeController()
.MapApiControllers()
.AddTables(
new MobileAppTableConfiguration()
.MapTableControllers()
.AddEntityFramework()
)
.MapLegacyCrossDomainController()
.ApplyTo(config);
使用的扩展方法包括:
AddMobileAppHomeController()
,用于提供默认的 Azure 移动应用主页。MapApiControllers()
,用于为使用[MobileAppController]
属性修饰的 WebAPI 控制器提供自定义 API 功能。AddTables()
,用于提供到表控制器的/tables
终结点映射。AddTablesWithEntityFramework()
,是使用基于实体框架的控制器映射/tables
终结点的简单方法。MapLegacyCrossDomainController()
,提供标准 CORS 标头进行本地开发。
SDK 扩展
以下基于 NuGet 的扩展包提供应用程序可以使用的多种移动功能。 可以使用 MobileAppConfiguration 对象在初始化期间启用扩展。
- Microsoft.Azure.Mobile.Server.Quickstart 支持基本的移动应用设置。 在初始化期间,通过调用 UseDefaultConfiguration 扩展方法添加到配置。 此扩展包含以下扩展:通知、身份验证、实体、表、跨域和主目录包。
- Microsoft.Azure.Mobile.Server.Home 为网站根目录实现默认的此移动应用已启动并正在运行页。 通过调用 AddMobileAppHomeController 扩展方法添加到配置。
- Microsoft.Azure.Mobile.Server.Tables 包含用于处理数据和设置数据管道的类。 通过调用 AddTables 扩展方法添加到配置。
- Microsoft.Azure.Mobile.Server.Entity 使实体框架能够访问 SQL 数据库中的数据。 通过调用 AddTablesWithEntityFramework 扩展方法添加到配置。
- Microsoft.Azure.Mobile.Server.Authentication 启用身份验证,并设置用于验证令牌的 OWIN 中间件。 通过调用 AddAppServiceAuthentication 与 IAppBuilder.UseAppServiceAuthentication 扩展方法添加到配置。
- Microsoft.Azure.Mobile.Server.Notifications 启用推送通知并定义推送注册终结点。 通过调用 AddPushNotifications 扩展方法添加到配置。
- Microsoft.Azure.Mobile.Server.CrossDomain 创建从移动应用向旧版 Web 浏览器提供数据的控制器。 通过调用 MapLegacyCrossDomainController 扩展方法添加到配置。
- Microsoft.Azure.Mobile.Server.Login 提供
AppServiceLoginHandler.CreateToken()
方法,该方法是在自定义身份验证方案下使用的静态方法。
发布服务器项目
本部分说明如何从 Visual Studio 发布 .NET 后端项目。 可通过其他方法发布应用程序。 有关详细信息,请参阅 Azure 应用服务文档。
- 在 Visual Studio 中,重新生成项目以还原 NuGet 包。
- 在“解决方案资源管理器”中,右键单击该项目并单击“发布”。
- 如果以前尚未发布此项目,则配置发布。
- 选择“Azure”作为目标。
- 选择 Azure 应用服务 (Windows) 作为特定目标。
- 选择要部署到的应用服务实例。 如果没有,请使用 创建一个+。
- 单击“完成” 。
- 如果之前尚未链接 SQL 数据库,请单击 SQL 数据库旁边的“配置”。
- 选择“Azure SQL 数据库”
- 选择数据库。 如果没有数据库或想要使用不同的数据库和服务器,请单击 创建新的数据库和服务器+。
- 输入数据库连接字符串名称
MS_TableConnectionString
。 在提供的框中填写用户名和密码。 - 单击“完成”
- 单击“发布”。
发布到 Azure 需要一些时间。 有关详细信息,请参阅 Visual Studio 文档。
定义表控制器
定义表控制器,使其向移动客户端公开 SQL 表。 配置表控制器需要三个步骤:
- 创建数据传输对象 (DTO) 类。
- 在 Mobile DbContext 类中配置表引用。
- 创建表控制器。
数据传输对象 (DTO) 是继承自 EntityData
的纯 C# 对象。 例如:
public class TodoItem : EntityData
{
public string Text { get; set; }
public bool Complete {get; set;}
}
DTO 用于定义 SQL 数据库中的表。 要创建数据库条目,请将 DbSet<>
属性添加到正在使用的 DbContext
中:
public class MobileServiceContext : DbContext
{
private const string connectionStringName = "Name=MS_TableConnectionString";
public MobileServiceContext() : base(connectionStringName)
{
}
public DbSet<TodoItem> TodoItems { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(
new AttributeToColumnAnnotationConvention<TableColumnAttribute, string>(
"ServiceColumnTable", (property, attributes) => attributes.Single().ColumnType.ToString()));
}
}
最后,创建新的控制器:
右键单击
Controllers
文件夹。选择“Web API”>“Web API 2 控制器 - 空”
输入控制器名称。
将控制器的新内容替换为以下代码:
public class TodoItemController : TableController<TodoItem> { protected override void Initialize(HttpControllerContext controllerContext) { base.Initialize(controllerContext); ZUMOAPPNAMEContext context = new ZUMOAPPNAMEContext(); DomainManager = new EntityDomainManager<TodoItem>(context, Request); } // GET tables/TodoItem public IQueryable<TodoItem> GetAllTodoItems() { return Query(); } // GET tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959 public SingleResult<TodoItem> GetTodoItem(string id) { return Lookup(id); } // PATCH tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959 public Task<TodoItem> PatchTodoItem(string id, Delta<TodoItem> patch) { return UpdateAsync(id, patch); } // POST tables/TodoItem public async Task<IHttpActionResult> PostTodoItem(TodoItem item) { TodoItem current = await InsertAsync(item); return CreatedAtRoute("Tables", new { id = current.Id }, current); } // DELETE tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959 public Task DeleteTodoItem(string id) { return DeleteAsync(id); } }
调整表分页大小
默认情况下,Azure 移动应用为每个请求返回 50 条记录。 分页可以确保客户端不会长时间占用其 UI 线程或服务器,从而提供良好的用户体验。 若要更改表分页大小,可增大服务器端“允许的查询大小”和客户端页面大小。服务器端“允许的查询大小”可使用 EnableQuery
属性进行调整:
[EnableQuery(PageSize = 500)]
确保 PageSize 等于或大于客户端请求的大小。 有关更改客户端页面大小的详细信息,请参阅具体的客户端操作指南文档。
定义自定义 API 控制器
自定义 API 控制器通过公开终结点,向移动应用后端提供最基本的功能。 可以使用 [MobileAppController] 属性注册移动设备特定的 API 控制器。 MobileAppController
属性将注册路由、设置移动应用 JSON 序列化程序,并打开客户端版本检查。
自定义 API 控制器的内容如下:
[MobileAppController]
public class CustomAPIController : ApiController
{
// Content here
}
配置 MobileAppController
属性后,可采用与任何其他 Web API 相同的方式定义自定义 API。
使用身份验证
Azure 移动应用使用应用服务身份验证/授权保护移动后端。 本部分说明如何在 .NET 后端服务器项目中执行以下身份验证相关的任务:
将身份验证添加到服务器项目
可以通过扩展 MobileAppConfiguration 对象并配置 OWIN 中间件,将身份验证添加到服务器项目。
在 Visual Studio 中,安装 Microsoft.Azure.Mobile.Server.Authentication 包。
在
Startup.cs
项目文件中,在“配置”方法的开头添加以下代码行:app.UseAppServiceAuthentication(config);
此 OWIN 中间件组件验证由关联的应用服务网关颁发的令牌。
将
[Authorize]
属性添加到任何要求身份验证的控制器或方法。
对应用程序使用自定义身份验证
重要
若要启用自定义身份验证,必须先启用应用服务身份验证,而不必在 Azure 门户中为应用服务选择提供程序。 这会使得在托管时启用 WEBSITE_AUTH_SIGNING_KEY
环境变量。
如果不想使用某个应用服务身份验证/授权提供程序,可以实现自己的登录系统。 安装 Microsoft.Azure.Mobile.Server.Login 包以协助生成身份验证令牌。 提供自己的代码验证用户凭据。 例如,可以针对数据库中的加盐密码和哈希密码进行检查。 在以下示例中,isValidAssertion()
方法(在其他位置定义)负责这些检查。
通过创建 ApiController 并公开 register
和 login
操作,可以公开自定义身份验证。 客户端应使用自定义 UI 从用户处收集信息。 随后再通过标准 HTTP POST 调用将信息提交到 API。 服务器验证断言后,便可以使用 AppServiceLoginHandler.CreateToken()
方法颁发令牌。 ApiController 不可使用 [MobileAppController]
属性。
示例 login
操作:
public IHttpActionResult Post([FromBody] JObject assertion)
{
if (isValidAssertion(assertion)) // user-defined function, checks against a database
{
JwtSecurityToken token = AppServiceLoginHandler.CreateToken(new Claim[] { new Claim(JwtRegisteredClaimNames.Sub, assertion["username"]) },
mySigningKey,
myAppURL,
myAppURL,
TimeSpan.FromHours(24) );
return Ok(new LoginResult()
{
AuthenticationToken = token.RawData,
User = new LoginResultUser() { UserId = userName.ToString() }
});
}
else // user assertion was not valid
{
return this.Request.CreateUnauthorizedResponse();
}
}
在前面的示例中,LoginResult
和 LoginResultUser
是可序列化的对象,用于公开所需属性。 客户端预期收到采用以下格式的 JSON 对象的登录响应:
{
"authenticationToken": "<token>",
"user": {
"userId": "<userId>"
}
}
AppServiceLoginHandler.CreateToken()
方法包含 audience 和 issuer 参数。 这两个参数使用 HTTPS 方案设置为应用程序根目录的 URL。 同样,应将 secretKey 设置为应用程序的签名密钥值。 请勿分发客户端中的签名密钥,因为该密钥可用于伪造密钥和模拟用户。 在应用服务中托管时,可通过引用 WEBSITE_AUTH_SIGNING_KEY
环境变量获取签名密钥。 如果在本地调试上下文中有需要,可根据使用身份验证进行本地调试部分中的说明检索密钥,并将它存储为应用程序设置。
颁发的令牌还可以包括其他声明和到期日期。 颁发的令牌至少应包含一个使用者 (sub) 声明。
可以通过重载身份验证路由支持标准客户端 loginAsync()
方法。 如果客户端通过调用 client.loginAsync('custom');
进行登录,则路由必须是 /.auth/login/custom
。 可以使用 MapHttpRoute()
设置自定义身份验证控制器的路由:
config.Routes.MapHttpRoute("custom", ".auth/login/custom", new { controller = "CustomAuth" });
提示
使用 loginAsync()
方法可确保将身份验证令牌附加到后续对服务的所有调用。
检索经过身份验证的用户信息
当应用服务对用户进行身份验证时,可以访问分配的用户 ID 和 .NET 后端代码中的其他信息。 用户信息可用于在后端作出授权决策。 可使用以下代码获取与某个请求关联的用户 ID:
// Get the SID of the current user.
var claimsPrincipal = this.User as ClaimsPrincipal;
string sid = claimsPrincipal.FindFirst(ClaimTypes.NameIdentifier).Value;
SID 派生自提供程序特定的用户 ID,对于给定的用户和登录提供程序而言是静态的。 SID 为 null 即表示无效的身份验证令牌。
应用服务还允许向登录提供程序请求特定声明。 每个标识提供者都可以使用标识提供者 SDK 提供更多信息。 例如,可以使用 Facebook Graph API 提供好友信息。 可以在 Azure 门户上的提供程序边栏选项卡中指定请求的声明。 某些声明需要标识提供者更多的配置。
可以使用以下代码调用 GetAppServiceIdentityAsync 扩展方法以获取登录凭据,包括对 Facebook Graph API 发出请求所需的访问令牌:
// Get the credentials for the logged-in user.
var credentials = await this.User.GetAppServiceIdentityAsync<FacebookCredentials>(this.Request);
if (credentials.Provider == "Facebook")
{
// Create a query string with the Facebook access token.
var fbRequestUrl = "https://graph.facebook.com/me/feed?access_token="
+ credentials.AccessToken;
// Create an HttpClient request.
var client = new System.Net.Http.HttpClient();
// Request the current user info from Facebook.
var resp = await client.GetAsync(fbRequestUrl);
resp.EnsureSuccessStatusCode();
// Do something here with the Facebook user information.
var fbInfo = await resp.Content.ReadAsStringAsync();
}
可以通过向 System.Security.Principal
添加 using 语句提供 GetAppServiceIdentityAsync 扩展方法。
对已获授权的用户限制数据访问
上一部分已说明如何检索经过身份验证的用户的用户 ID。 可以根据此值来限制对数据和其他资源的访问。 例如,将 userId 列添加到表以及根据用户 ID 筛选查询结果,是将返回的数据局限于已获授权用户的简单方式。 以下代码只会在 SID 与 TodoItem 表上 UserId 列中的值匹配时才返回数据行:
// Get the SID of the current user.
var claimsPrincipal = this.User as ClaimsPrincipal;
string sid = claimsPrincipal.FindFirst(ClaimTypes.NameIdentifier).Value;
// Only return data rows that belong to the current user.
return Query().Where(t => t.UserId == sid);
Query()
方法返回的 IQueryable
可通过 LINQ 操作来处理筛选。
对 .NET 服务器 SDK 进行调试和故障排除
Azure 应用服务提供多种适用于 ASP.NET 应用程序的调试和故障排除方法:
日志记录
可以使用标准的 ASP.NET 跟踪写入来写入应用服务诊断日志。 必须在 Azure 移动应用后端启用诊断后,才能写入日志。
启用诊断并写入日志:
按照启用应用程序日志记录(Windows)中的步骤操作。
在代码文件中添加以下 using 语句:
using System.Web.Http.Tracing;
创建跟踪写入器以便从 .NET 后端写入诊断日志,如下所示:
ITraceWriter traceWriter = this.Configuration.Services.GetTraceWriter(); traceWriter.Info("Hello, World");
重新发布服务器项目,并访问 Azure 移动应用后端,结合日志记录执行代码路径。
下载并评估日志,如 Access 日志文件中所述。
使用身份验证进行本地调试
可以先在本地运行应用程序以测试更改,然后将更改发布到云中。 对于大多数 Azure 移动应用后端,请在 Visual Studio 中按 F5。 但是,使用身份验证时需考虑其他一些事项。
必须有基于云的移动应用,已配置应用服务身份验证/授权,并且客户端必须有指定为备用登录主机的云终结点。 请参阅相关的客户端平台文档获取所需的具体步骤。
确保移动后端已安装 Microsoft.Azure.Mobile.Server.Authentication。 然后,在将 MobileAppConfiguration
应用到 HttpConfiguration
之后,在应用程序的 OWIN 启动类中添加以下代码:
app.UseAppServiceAuthentication(new AppServiceAuthenticationOptions()
{
SigningKey = ConfigurationManager.AppSettings["authSigningKey"],
ValidAudiences = new[] { ConfigurationManager.AppSettings["authAudience"] },
ValidIssuers = new[] { ConfigurationManager.AppSettings["authIssuer"] },
TokenHandler = config.GetAppServiceTokenHandler()
});
在上例中,应使用 HTTPS 方案将 Web.config 文件中的 authAudience 和 authIssuer 应用程序设置配置为每个应用程序根目录的 URL。 同样,应将 authSigningKey 设置为应用程序的签名密钥值。
获取签名密钥:
- 在 Azure 门户 中导航到应用
- 单击“工具”>“Kudu”>“转到”。
- 在 Kudu 管理站点中,单击“环境”。
- 查找
WEBSITE_AUTH_SIGNING_KEY
的值。
在本地应用程序配置中使用 authSigningKey 参数的签名密钥。移动后端现在可在本地运行时验证令牌,而客户端从基于云的终结点获取令牌。
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈