2

我正在尝试使用 azure 活动目录验证多个客户端(从 Windows 服务器应用程序连接 - 无浏览器)访问我的 .Net4.51 webAPI。

我为我的 webapi 创建了一个名为“ServerWebApi”的 Azure AD 应用程序,并使用以下应用程序设置将我的 webapi 应用程序代码配置为在 webConfig 中指向它。

<add key="ida:Tenant" value="myDomainName.onmicrosoft.com" />
<add key="ida:Audience" value="https://myDomainName.onmicrosoft.com/ServerWebApi" />
<add key="ida:ClientID" value="<client id>" />

因此,当请求带有令牌时,它应该使用这些设置来针对我的名为 ServerWebApi 的 AD WebApi 应用程序验证令牌。

现在,为了让每个客户端都能获得令牌,我为每个客户端创建了一个 Azure 应用程序。(我没有将它创建为本机应用程序,而是作为 webapi 应用程序创建,以便我可以为每个客户端创建一个单独的密钥)。我还将 Azure 中的实际 webAPI 应用程序 (ServerWebApi) 添加到“此应用程序访问的 Web API”列表中。(对于这个例子,我的第一个客户端称为 myClientWebApiApp)

所以现在我的客户端可以成功地从其客户端应用程序在 AD 中请求一个令牌,但是当它发布到服务器(webapi)时,我得到一个 401 - 未经授权。因此,我认为我未能针对我的 Azure AD ServerWebApi webApi 验证令牌。

我用来获取令牌并调用我的 webApi 的客户端应用程序代码如下

// Create an ADAL AuthenticationContext object and link it to my tennant domain myDomainName.onmicrosoft.com
var authority = ConfigurationManager.AppSettings["Tenant"];
authenticationContext = new AuthenticationContext(authority);

//Client Cerdential Object used while Acquiring a token from Windows Azure AD
ClientCredential clientCred = new ClientCredential(clientId, clientSecret);

// Invoke AuthenticationContext.AcquireToken to obtain an AccessToken. 
// Uses previously-created ClientCredential to authenticate
authenticationResult = authenticationContext.AcquireToken(resource, clientCred);

httpClient.DefaultRequestHeaders.Clear();
//Add authorization header to HttpClient
httpClient.DefaultRequestHeaders.Authorization = new        AuthenticationHeaderValue("Bearer",authenticationResult.AccessToken);

var data = "new Value";

// Call the Service web api to update                    
HttpResponseMessage response = httpClient.PostAsJsonAsync(resourceurl + "api/Values", data).Result;

它使用以下配置设置

<add key="Tenant" value="https://login.windows.net/myDomainName.onmicrosoft.com"/>
<add key="ClientId" value= "<client id>"/>
<add key="ClientSecret" value= "<client secret>"/>
<add key="ResourceUrl" value="https://localhost:44300/"/>
<add key="AppIdUri" value="https://myDomainName.onmicrosoft.com/myClientWebApiApp"/>

Client Id 是我创建的 Client webapi 应用程序的 ID,ClientSecret 是我在 Azure AD 中针对该应用程序创建的密钥。

有谁知道我正在做的事情是否可行,如果可以,我做错了什么?

4

2 回答 2

1

我相信您的问题最终在于您如何设置 AuthorizationHeader 以及您的 ServerWebApi 如何响应请求。

看看这个博客。我相信这是您正在寻找的解决方案。

于 2014-02-15T16:36:45.730 回答
0

我也面临类似的问题并等待解决方案。但作为一项工作,我创建了如下。我确信这可能不是一个适当的修复。更好的答案建议肯定会对我们有所帮助。

Step1:在 WebApiConfig.cs 中的 Register 方法中添加以下行

config.MessageHandlers.Add(new AzureADAuthorizationHandler
{
    Audience = ConfigurationManager.AppSettings["Audience"],
    SymmetricKey = ConfigurationManager.AppSettings["ClientSecretKey"]
});

第2步:(注意下面的实现是评论中提到的正在进行中的工作)

using System;
using System.IdentityModel.Tokens;
using System.Net;
using System.Net.Http;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Controllers;

namespace MyDevWebApiService.Common
{
    public class AzureADAuthorizationHandler : DelegatingHandler //: AuthorizeAttribute
    {
         //public override void OnAuthorization(HttpActionContext actionContext)
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage httpRequestObject, CancellationToken cancellationToken)
        {
            HttpResponseMessage httpResponseMessage = null;

            try
            {
                var RequuestObj = System.Web.HttpContext.Current.Request;
                var AuthHeader = RequuestObj.Headers["Authorization"];

                if (AuthHeader == null)
                {
                    httpResponseMessage = httpRequestObject.CreateErrorResponse(HttpStatusCode.BadRequest, "No authorization header present in the request");
                }
                else
                {
                    string encodedTokenString = AuthHeader.StartsWith("Bearer ") ? AuthHeader.Substring(7) : AuthHeader;
                    //Validate date the token - Work in Progress. Should be able to handle Bearer and Basic headers.
                    //Extract the Azure Ad info (tenant, client id and client security key etc) and use ADAL to authenticate with Azure AD.
                    SetCurrentPrincipal(encodedTokenString);
                }
            }            
            catch (Exception ex)
            {
                httpResponseMessage = httpRequestObject.CreateErrorResponse(HttpStatusCode.BadRequest, ex + "Invalid header, header token extration failed");
            }

            return httpResponseMessage != null ? Task.FromResult(httpResponseMessage) : base.SendAsync(httpRequestObject, cancellationToken);
        }

        public void SetCurrentPrincipal(string encodedTokenString)
        {
            try
            {
                ClaimsIdentity ClaimsIdentityObject = new ClaimsIdentity();

                JwtSecurityToken JwtSecurityTokenObject = new System.IdentityModel.Tokens.JwtSecurityToken(encodedTokenString);

                foreach (Claim ClaimObj in JwtSecurityTokenObject.Claims)
                {
                    ClaimsIdentityObject.AddClaim(ClaimObj);
                }

                Thread.CurrentPrincipal = new ClaimsPrincipal(ClaimsIdentityObject);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}

==================================================== =================================================== 注意: 被动联邦:

当我们在 VS2013 和 .NET4.5.1 中创建 MVC 项目时,它将在项目中创建一个持久性本地数据库并存储所有身份验证详细信息。

将这种被动联合调整为主动联合,尤其是持久存储的观点,这并不自在。

下面的类将自动生成。

  1. Models.TenantDbContext
  2. Models.IssuingAuthorityKey
  3. 模特.租户
  4. Utils.DatabaseIssuerNameRegistry
  5. 身份配置
  6. 附加行 -> IdentityConfig.ConfigureIdentity(); 在 Global.asax.cs Application_Start()

  7. 配置文件条目。

于 2014-04-08T14:00:28.237 回答