我们正在构建一个客户将使用AAD令牌命中的webAPI服务。因此,此服务需要对令牌进行身份验证以确保其有效。 这是一个多租户场景。
我通过AAD文档并且几乎没有问题。如果有人能帮助回答,我们将不胜感激。
1)根据我的理解,该服务将从AAD下载公共签名令牌并缓存它们。这些用于验证令牌,这是正确的吗?
2)刷新缓存签名令牌的建议间隔是多少?另外,针对按需刷新案例AAD的建议是否在刷新期内轮换密钥?
找到的每个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中,它以同步方式下载这些签名令牌,是否有代码的异步版本?
答案 0 :(得分: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}/" }
}
});