我们有一个安全要求,我们必须验证从Azure AD B2C收到的ID令牌。我们需要至少对它们进行验证
customSecurityLevel ,受众,不早于“到期时间”,发行人,现时
在查看asp.net MVC OWIN中间件时,我注意到OpenIdConnectAuthenicationOptions提供了以下这些功能:
preprocess_input
作为OWIN的新手,我试图在下面进行了解:
OWIN中间件是否神奇地验证了我们从Azure AD B2C接收到的令牌,还是需要手动执行验证: https://azure.microsoft.com/en-us/resources/samples/active-directory-dotnet-webapi-manual-jwt-validation/
应该在什么时间进行令牌验证,即AuthorizationCodeReceived事件或在Azure AD B2C重定向URL上配置的重定向控制器/操作(页面)上?
我们需要验证TokenValidationParameters支持的更多属性,例如我们在初始有效载荷上发送的customSecurityAttribute。有办法扩展吗?
任何代码示例都将很方便。
答案 0 :(得分:1)
使您的问题更简单。
令牌背后的想法是解析令牌并从令牌中获取3部分
-Header : contain information about in which algorithm the token haven been encrypted
-Payload : information about the user
-Signature: it's the calculation of encryption of ( Header + Payload) using the Azure certificate or( your identity provider).
下一步,用户将请求与JWT一起发送到您的后端。
您的后端将解析令牌并获取证书类型,然后向身份提供者执行HTTP请求以获取证书
接下来,您的后端将构造证书选项,并尝试对来自令牌的(标头+有效负载)进行加密,输出字符串必须与您从前端在令牌中收到的签名完全相同。
如果一切正常 现在您的后端将开始验证其他属性,例如Audience,Issuer 如果您配置令牌以验证受众群体,则意味着提供令牌所包含的受众群体(应用程序ID)所需的前端与后端以及发行方完全相同。
现在的问题是我的后端如何了解证书?
使用OpenID connect,More information here的Azure AD
由于您在后端配置了承租人,因此身份验证包将致电https://login.microsoftonline.com/{tenant}/.well-known/openid-configuration
以获取有关身份提供者的详细信息
一个重要的链接将是("jwks_uri": "https://login.microsoftonline.com/common/discovery/keys")
托管签名的位置。
您可以阅读和搜索更多如何验证证书JWT并进行检查
https://codereview.stackexchange.com/questions/70005/authentication-with-jwt
移至第2部分,验证更多属性。
由于您使用的是OpenIdConnect,因此该软件包具有名为OpenIdConnectEvents
的类,您可以触发事件并执行所需的操作
.AddOpenIdConnect(o =>
{
//Additional config snipped
o.Events = new OpenIdConnectEvents
{
OnTokenValidated = async ctx =>
{
//Get user's immutable object id from claims that came from Azure AD
string oid = ctx.Principal.FindFirstValue("http://schemas.microsoft.com/identity/claims/objectidentifier");
//Get EF context
var db = ctx.HttpContext.RequestServices.GetRequiredService<AuthorizationDbContext>();
//Check is user a super admin
bool isSuperAdmin = await db.SuperAdmins.AnyAsync(a => a.ObjectId == oid);
if (isSuperAdmin)
{
//Add claim if they are
var claims = new List<Claim>
{
new Claim(ClaimTypes.Role, "superadmin")
};
var appIdentity = new ClaimsIdentity(claims);
ctx.Principal.AddIdentity(appIdentity);
}
}
};
});
移至第3部分 在javascript中解析令牌
function parseJwt (token) {
var base64Url = token.split('.')[1];
var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
return JSON.parse(window.atob(base64));
};
使用C#解析令牌
使用此库https://www.jsonwebtoken.io/
try {
string jsonPayload = JWT.JsonWebToken.Decode(token, secretKey);
Console.WriteLine(jsonPayload);
} catch (JWT.SignatureVerificationException) {
Console.WriteLine("Invalid token!");
}
或手册
var jwtHandler = new JwtSecurityTokenHandler();
var jwtInput = txtJwtIn.Text;
//Check if readable token (string is in a JWT format)
var readableToken = jwtHandler.CanReadToken(jwtInput);
if(readableToken != true)
{
txtJwtOut.Text = "The token doesn't seem to be in a proper JWT format.";
}
if(readableToken == true)
{
var token = jwtHandler.ReadJwtToken(jwtInput);
//Extract the headers of the JWT
var headers = token.Header;
var jwtHeader = "{";
foreach(var h in headers)
{
jwtHeader += '"' + h.Key + "\":\"" + h.Value + "\",";
}
jwtHeader += "}";
txtJwtOut.Text = "Header:\r\n" + JToken.Parse(jwtHeader).ToString(Formatting.Indented);
//Extract the payload of the JWT
var claims = token.Claims;
var jwtPayload = "{";
foreach(Claim c in claims)
{
jwtPayload += '"' + c.Type + "\":\"" + c.Value + "\",";
}
jwtPayload += "}";
txtJwtOut.Text += "\r\nPayload:\r\n" + JToken.Parse(jwtPayload).ToString(Formatting.Indented);
}
我希望能回答您的疑问