首页 文章

在WebApi中验证Azure AD令牌

提问于
浏览
0

我们正在构建一个客户将使用AAD令牌命中的webAPI服务 . 因此,此服务需要对令牌进行身份验证以确保其有效 . 这是一个多租户方案 .

我通过了AAD文档并且几乎没有问题 . 如果有人能帮助回答,我们将不胜感激 .

1)根据我的理解,该服务将从AAD下载公共签名令牌并缓存它们 . 这些用于验证令牌,这是正确的吗?

2)刷新缓存签名令牌的建议间隔是多少?此外,针对按需刷新案例AAD的建议是否在刷新期内轮换密钥?

3)我在https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-signing-key-rollover找到的AAD示例代码

MetadataSerializer serializer = new MetadataSerializer()
                {
                    // Do not disable for production code
                    CertificateValidationMode = X509CertificateValidationMode.None
                };

启用证书验证不起作用,因为机器不信任AAD根证书,这里的建议是什么?我们是否需要在受信任的商店中手动安装证书?

4)在AAD示例代码@ https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-signing-key-rollover中,它以同步方式下载那些签名令牌,是否有代码的异步版本?

1 回答

  • 0

    AFAIK,该请求将获取Azure AD发布的令牌,该令牌由私钥签名 . Web API将自动使用Azure AD的key endpoints中的公钥验证令牌(OWIN组件) .

    要在Visual Studio 2013之后使用版本开发Web API,则无需手动验证令牌 . 以下是一段保护Web API的代码:

    public void ConfigureAuth(IAppBuilder app)
    {
        app.UseWindowsAzureActiveDirectoryBearerAuthentication(
            new WindowsAzureActiveDirectoryBearerAuthenticationOptions
            {
                Audience = ConfigurationManager.AppSettings["ida:Audience"],
                Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
                TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters() { ValidateIssuer = false }
            });
    }
    

    Here是保护多租户的Web API的完整代码示例的链接 .

    更新(支持不同控制器的密码和令牌认证)

    public void ConfigureAuth(IAppBuilder app)
            {
                app.UseWindowsAzureActiveDirectoryBearerAuthentication(
                    new WindowsAzureActiveDirectoryBearerAuthenticationOptions
                    {
                        Audience = ConfigurationManager.AppSettings["ida:Audience"],
                        Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
                        TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters() { ValidateIssuer = false }
                    });
    
                app.UsePasswordAuthentication();
            }
    
    public class PasswordAuthorization : AuthorizeAttribute
    {
        public override void OnAuthorization(HttpActionContext actionContext)
        {
            var principal = actionContext.RequestContext.Principal as ClaimsPrincipal;
    
            if (principal.FindFirst("authenticationType") == null)
            {
                actionContext.Response = new HttpResponseMessage
                {
                    StatusCode = HttpStatusCode.Unauthorized,
                    Content = new StringContent("You are unauthorized to access this resource!")
                };
    
            }
    
        }
    }
    
    public class TokenAuthorization : AuthorizeAttribute
    {
    
        public override void OnAuthorization(HttpActionContext actionContext)
        {
            var principal = actionContext.RequestContext.Principal as ClaimsPrincipal;
    
            if (principal.FindFirst("authenticationType") != null)
            {
                actionContext.Response = new HttpResponseMessage
                {
                    StatusCode = HttpStatusCode.Unauthorized,
                    Content = new StringContent("You are unauthorized to access this resource!")
                };
    
            }
    
        }
    }
    
    
    public class PasswordAuthenticationOptions : AuthenticationOptions
    {
        public PasswordAuthenticationOptions() : base("password")
        { }
    }
    
    public class PasswordAuthenticationHandler : AuthenticationHandler<PasswordAuthenticationOptions>
    {
        protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
        {
            bool authorized = await Task<bool>.Run(() => IsAuthorised(Request.Headers));
            if (authorized)
            {
                AuthenticationProperties authProperties = new AuthenticationProperties();
                authProperties.IssuedUtc = DateTime.UtcNow;
                authProperties.ExpiresUtc = DateTime.UtcNow.AddDays(1);
                authProperties.AllowRefresh = true;
                authProperties.IsPersistent = true;
                IList<Claim> claimCollection = new List<Claim>
                {
                    new Claim(ClaimTypes.Name, "Andras")
                    , new Claim(ClaimTypes.Country, "Sweden")
                    , new Claim(ClaimTypes.Gender, "M")
                    , new Claim(ClaimTypes.Surname, "Nemes")
                    , new Claim(ClaimTypes.Email, "hello@me.com")
                    , new Claim(ClaimTypes.Role, "IT")
                    , new Claim("authenticationType", "password")
                };
                ClaimsIdentity claimsIdentity = new ClaimsIdentity(claimCollection, "Custom");
                AuthenticationTicket ticket = new AuthenticationTicket(claimsIdentity, authProperties);
                return ticket;
            }
    
            return null;
        }
    
        private bool IsAuthorised(IHeaderDictionary requestHeaders)
        {
            string[] username,password;
            bool usernamePresent = requestHeaders.TryGetValue("username", out username);
            bool passwordPresent = requestHeaders.TryGetValue("password", out password);
    
            if (usernamePresent& passwordPresent)
            {
                if("user1".Equals(username[0])&&"pass".Equals(password[0]))
                    return true;
            }
    
            return false;
        }
    }
    
    
    public class PasswordAuthMiddleware : AuthenticationMiddleware<PasswordAuthenticationOptions>
    {
        public PasswordAuthMiddleware(OwinMiddleware nextMiddleware, PasswordAuthenticationOptions authOptions)
            : base(nextMiddleware, authOptions)
        { }
    
        protected override AuthenticationHandler<PasswordAuthenticationOptions> CreateHandler()
        {
            return new PasswordAuthenticationHandler();
        }
    }
    
    public static class PassworAuthenticationExtension
    {
        public static void UsePasswordAuthentication(this IAppBuilder appBuilder)
        {
            appBuilder.Use<PasswordAuthMiddleware>(new PasswordAuthenticationOptions());
        }
    }
    

    API控制器使用密码进行身份验证

    [PasswordAuthorization]
    public class Values2Controller : ApiController
    {
        // GET: api/Values2
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        } 
    }
    

    使用AAD进行身份验证的API控制器:

    [TokenAuthorization]
    public class ValuesController : ApiController
    { 
        // GET api/values
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }
    }
    

    更新(限制租户)

    app.UseWindowsAzureActiveDirectoryBearerAuthentication(
    new WindowsAzureActiveDirectoryBearerAuthenticationOptions
    {
        Audience = ConfigurationManager.AppSettings["ida:Audience"],
        Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
        TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters() {
            ValidateIssuer = true,
            ValidIssuers =new string[] { "https://sts.windows.net/{tenantId}/" } 
        }
    });
    

相关问题