我有一个现有的原生iOS应用程序,我需要能够通过身份验证多个Azure Active Directory实例用户.这些用户是内部和外部(注册我们服务的客户).为此,我实验性地实现了以下高级架构:
Native Client App(iOS / obj-c) – > ADAL iOS库 – > (Azure AD身份验证) – > Azure移动应用程序(服务层)
iOS应用程序利用ADAL iOS库获取访问令牌,该令牌用于调用Azure Mobile App项目中的授权Web API服务.
我能够对来自两个租户(内部Azure AD和外部Azure AD)的用户进行身份验证,但只有与服务(内部)相同的租户中的用户才能调用经过身份验证的API.我从外部租户使用的测试用户帐户被设置为全局管理员,并在进行身份验证时在本机应用程序中显示相应的同意视图.然后,我可以点击同意,然后我会收到一个访问令牌.然而,当使用该令牌调用测试API时,我得到了401.服务器上Azure Mobile App的详细日志显示以下消息(以下所有URL都是https,我只是没有代表发布它们):
2016-01-12T13:00:55 PID[7972] Verbose Received request: GET MyAzureMobileApp.azurewebsites.net/api/values 2016-01-12T13:00:55 PID[7972] Verbose Downloading OpenID configuration from sts.windows.net/<internal AD GUID>/.well-known/openid-configuration 2016-01-12T13:00:55 PID[7972] Verbose Downloading OpenID issuer keys from login.windows.net/common/discovery/keys 2016-01-12T13:00:56 PID[7972] Warning JWT validation failed: IDX10205: Issuer validation failed. Issuer: 'sts.windows.net/<external AD GUID>/'. Did not match: validationParameters.ValidIssuer: 'sts.windows.net/<internal ad guid>/' or validationParameters.ValidIssuers: 'null'.. 2016-01-12T13:00:56 PID[7972] Information Sending response: 401.71 Unauthorized
我在几篇帖子中读到,您可以通过将TokenValidationParameters中的ValidateIssuer参数设置为false来禁用服务中的令牌颁发者验证.我试过这样做,但它似乎没有任何影响.以下是我的Azure移动应用程序项目中的代码:
启动代码:
// Startup.cs using Microsoft.Owin; using Owin; [assembly: OwinStartup(typeof(MyAzureMobileApp.Startup))] namespace MyAzureMobileApp { public partial class Startup { public void Configuration(IAppBuilder app) { ConfigureMobileApp(app); ConfigureAuth(app); } } }
MobileApp的代码 – 这应该是库存,由Azure Mobile App项目模板生成:
// Startup.MobileApp.cs using System; using System.Collections.Generic; using System.Configuration; using System.Data.Entity; using System.Web.Http; using Microsoft.Azure.Mobile.Server; using Microsoft.Azure.Mobile.Server.Authentication; using Microsoft.Azure.Mobile.Server.Config; using MyAzureMobileApp.DataObjects; using MyAzureMobileApp.Models; using Owin; namespace MyAzureMobileApp { public partial class Startup { public static void ConfigureMobileApp(IAppBuilder app) { HttpConfiguration config = new HttpConfiguration(); new MobileAppConfiguration() .UseDefaultConfiguration() .ApplyTo(config); // Use Entity Framework Code First to create database tables based on your DbContext Database.SetInitializer(new MobileServiceInitializer()); MobileAppSettingsDictionary settings = config.GetMobileAppSettingsProvider().GetMobileAppSettings(); if (string.IsNullOrEmpty(settings.HostName)) { app.UseAppServiceAuthentication(new AppServiceAuthenticationOptions { // This middleware is intended to be used locally for debugging. By default, HostName will // only have a value when running in an App Service application. SigningKey = ConfigurationManager.AppSettings["SigningKey"], ValidAudiences = new[] { ConfigurationManager.AppSettings["ValidAudience"] }, ValidIssuers = new[] { ConfigurationManager.AppSettings["ValidIssuer"] }, TokenHandler = config.GetAppServiceTokenHandler() }); } app.UseWebApi(config); } } public class MobileServiceInitializer : CreateDatabaseIfNotExists<MobileServiceContext> { protected override void Seed(MobileServiceContext context) { List<TodoItem> todoItems = new List<TodoItem> { new TodoItem { Id = Guid.NewGuid().ToString(), Text = "First item", Complete = false }, new TodoItem { Id = Guid.NewGuid().ToString(), Text = "Second item", Complete = false } }; foreach (TodoItem todoItem in todoItems) { context.Set<TodoItem>().Add(todoItem); } base.Seed(context); } } }
身份验证启动代码:
// Startup.Auth.cs using System; using System.Collections.Generic; using System.Configuration; using System.IdentityModel.Tokens; using System.Linq; using Microsoft.Owin.Security; using Microsoft.Owin.Security.ActiveDirectory; using Owin; namespace MyAzureMobileApp { public partial class Startup { // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864 public void ConfigureAuth(IAppBuilder app) { app.UseWindowsAzureActiveDirectoryBearerAuthentication( new WindowsAzureActiveDirectoryBearerAuthenticationOptions { Tenant = ConfigurationManager.AppSettings["ida:Tenant"], AuthenticationMode = AuthenticationMode.Active, TokenValidationParameters = new TokenValidationParameters() { ValidAudience = ConfigurationManager.AppSettings["ida:Audience"], ValidateIssuer = false } }); } } }
服务实施:
using System.Web.Http; using Microsoft.Azure.Mobile.Server.Config; namespace MyAzureMobileApp.Controllers { // Use the MobileAppController attribute for each ApiController you want to use // from your mobile clients [MobileAppController] // Use the MobileAppController attribute for each ApiController you want to use // from your mobile clients [Authorize] public class ValuesController : ApiController { // GET api/values public string Get() { return "GET returned: Hello World!"; } // POST api/values public string Post() { return "POST returned: Hello World!"; } } }
我在web.config中的appSettings部分:
<appSettings> <add key="PreserveLoginUrl" value="true" /> <!-- Use these settings for local development. After publishing to your Mobile App, these settings will be overridden by the values specified in the portal. --> <add key="MS_SigningKey" value="Overridden by portal settings" /> <add key="EMA_RuntimeUrl" value="Overridden by portal settings" /> <!-- When using this setting, be sure to add matching Notification Hubs connection string in the connectionStrings section with the name "MS_NotificationHubConnectionString". --> <add key="MS_NotificationHubName" value="Overridden by portal settings" /> <add key="ida:ClientId" value="-- MyAzureMobileApp App ID from Azure AD --" /> <add key="ida:Tenant" value="InternalTestAD.onmicrosoft.com" /> <add key="ida:Audience" value="https://InternalTestAD.onmicrosoft.com/MyAzureMobileApp" /> <add key="ida:Password" value="-- password value removed --" /> </appSettings>
除了作为WindowsAzureActiveDirectoryBearerAuthenticationOptions中TokenValidationParameters集合的属性之外,我没有看到指定有效令牌颁发者的位置.
根据我对代码的理解,我应该禁用颁发者验证,但我尝试在此处添加外部Azure AD STS URL.不幸的是,它似乎没有任何影响.
有人知道这些代码是否因某种原因被忽略或覆盖?是否有其他设置我错过了完全禁用发行者验证,或指定有效发行人列表?
我当然可以按要求提供更多信息,我只是不确定其他什么可能相关.
谢谢!
我相信我发现我的验证逻辑的原因被忽略了.在Azure App Services中设置我的web api站点时,我通过在“身份验证/授权”>中填充颁发者URL文本框来指定主租户颁发者URL. “Azure Active Directory设置”刀片.事实证明,当你要拥有多个发行人时(如我的多租户场景),你应该把这个字段留空.完全合理的是,JWT将对您在该文本框中提供的发行者进行验证.对我来说不那么直观的是,当你有一个以上的发行人时,你应该把它留空.也许MS可以将其添加到它上面的信息泡泡中?要么是这样,要么提供一些允许多个发行者URL的机制.
希望这可以节省其他人一些时间来解决这个问题.