JwtFormat:为啥将令牌的颁发者添加到 ValidIssuers 属性中?
Posted
技术标签:
【中文标题】JwtFormat:为啥将令牌的颁发者添加到 ValidIssuers 属性中?【英文标题】:JwtFormat: why does it add the token's issuer to the ValidIssuers property?JwtFormat:为什么将令牌的颁发者添加到 ValidIssuers 属性中? 【发布时间】:2018-04-25 11:25:49 【问题描述】:我正在查看 JwtFormat 类的源代码,我想知道为什么它将它从令牌中恢复的 Issuer 添加到 ValidIssuers 列表中。这是否意味着如果我不指定密钥或向正在使用的 TokenValidationParameters 提供 IssueValidator 处理程序,它将接受所有颁发者为有效?
顺便说一句,我正在看这个课程,因为我正在调查一个关于在似乎忽略 ValidIssuer 属性的 Web api 应用程序中使用 JWT 令牌(azure ad v2.0)的问题:
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
AccessTokenFormat = new JwtFormat(
GetTokenValidationParameters(),
new OpenIdConnectCachingSecurityTokenProvider(authority)),
Provider = new OAuthBearerAuthenticationProvider
OnValidateIdentity = ValidateIdentity
);
private TokenValidationParameters GetTokenValidationParameters()
return new TokenValidationParameters
ValidAudience = ConfigData.ClientId,
ValidIssuer = "nobody",
ValidIssuers = null,
IssuerValidator = ValidateIssuer
;
我正在编辑此内容以提供有关正在发生的事情的更多信息。
根据源码,ValidateIssuer默认为true,无需重新设置。只是为了确定,这里是源代码:
public TokenValidationParameters()
this.RequireExpirationTime = true;
this.RequireSignedTokens = true;
this.SaveSigninToken = false;
this.ValidateActor = false;
this.ValidateAudience = true;
this.ValidateIssuer = true;
this.ValidateIssuerSigningKey = false;
this.ValidateLifetime = true;
我正在设置 IssuerValidator,因为我想确保如果设置了 ValidIssuer,那么我想将令牌的颁发者与该值进行比较(并且不想在 ValidIssuer 验证时检查 ValidIssuers 集合失败)。
如果您想知道 ValidIssuers 的填充位置(是的,即使在我的示例中,它也会自动填充,即使我已将其显式设置为 null),它发生在 JwtFormat 的 Unprotect 方法中:
public AuthenticationTicket Unprotect(string protectedText)
if (string.IsNullOrWhiteSpace(protectedText))
throw new ArgumentNullException(nameof (protectedText));
if (!(this.TokenHandler.ReadToken(protectedText) is JwtSecurityToken))
throw new ArgumentOutOfRangeException(nameof (protectedText), Microsoft.Owin.Security.Jwt.Properties.Resources.Exception_InvalidJwt);
TokenValidationParameters validationParameters = this._validationParameters;
if (this._issuerCredentialProviders != null)
validationParameters = validationParameters.Clone();
IEnumerable<string> second1 = this._issuerCredentialProviders.Select<IIssuerSecurityTokenProvider, string>((Func<IIssuerSecurityTokenProvider, string>) (provider => provider.Issuer));
validationParameters.ValidIssuers = validationParameters.ValidIssuers != null ? validationParameters.ValidIssuers.Concat<string>(second1) : second1;
IEnumerable<SecurityToken> second2 = this._issuerCredentialProviders.Select<IIssuerSecurityTokenProvider, IEnumerable<SecurityToken>>((Func<IIssuerSecurityTokenProvider, IEnumerable<SecurityToken>>) (provider => provider.SecurityTokens)).Aggregate<IEnumerable<SecurityToken>>((Func<IEnumerable<SecurityToken>, IEnumerable<SecurityToken>, IEnumerable<SecurityToken>>) ((left, right) => left.Concat<SecurityToken>(right)));
validationParameters.IssuerSigningTokens = validationParameters.IssuerSigningTokens != null ? validationParameters.IssuerSigningTokens.Concat<SecurityToken>(second2) : second2;
SecurityToken validatedToken;
ClaimsIdentity identity = (ClaimsIdentity) this.TokenHandler.ValidateToken(protectedText, validationParameters, out validatedToken).Identity;
AuthenticationProperties properties = new AuthenticationProperties();
if (this.UseTokenLifetime)
DateTime validFrom = validatedToken.ValidFrom;
if (validFrom != DateTime.MinValue)
properties.IssuedUtc = new DateTimeOffset?((DateTimeOffset) validFrom.ToUniversalTime());
DateTime validTo = validatedToken.ValidTo;
if (validTo != DateTime.MinValue)
properties.ExpiresUtc = new DateTimeOffset?((DateTimeOffset) validTo.ToUniversalTime());
properties.AllowRefresh = new bool?(false);
return new AuthenticationTicket(identity, properties);
顺便说一句,当需要反序列化令牌时,AuthenticateCoreAsync 方法最终会(间接)调用此方法:
protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
try
string requestToken = (string) null;
string authorization = this.Request.Headers.Get("Authorization");
if (!string.IsNullOrEmpty(authorization) && authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
requestToken = authorization.Substring("Bearer ".Length).Trim();
OAuthRequestTokenContext requestTokenContext = new OAuthRequestTokenContext(this.Context, requestToken);
await this.Options.Provider.RequestToken(requestTokenContext);
if (string.IsNullOrEmpty(requestTokenContext.Token))
return (AuthenticationTicket) null;
AuthenticationTokenReceiveContext tokenReceiveContext = new AuthenticationTokenReceiveContext(this.Context, this.Options.AccessTokenFormat, requestTokenContext.Token);
await this.Options.AccessTokenProvider.ReceiveAsync(tokenReceiveContext);
if (tokenReceiveContext.Ticket == null)
tokenReceiveContext.DeserializeTicket(tokenReceiveContext.Token);
//remaining code removed
由于我真的没有阅读规范,我想知道是否有人可以向我解释这种行为(始终将令牌的发行者添加到 ValidIssuers 集合中并检查令牌的发行者是否在 ValidIssuers 中 - 这将始终是正确的!)
最终编辑
好吧,我的错...咖啡不够,我想...实际上,发行者不是从令牌本身添加的,而是从传递给 JwtFormat ctor 的 IIssuerSecurityTokenProvider 添加的(从元数据中获取)端点)...
对不起各位...
谢谢。
路易斯
【问题讨论】:
您是否在 TokenValidationProperties 中将 validateIssuer 设置为 true? 你能提供你正在审查的源代码的 URL 吗? 【参考方案1】:我目前没有Vs,因为我在手机上写,TokenValidationParameters里面应该有ValidateIssuer属性,但是貌似你把IssuerValidator设置为ValidateIssuer,应该是真的,所以试试看方式:
private TokenValidationParameters GetTokenValidationParameters()
return new TokenValidationParameters
ValidAudience = ConfigData.ClientId,
ValidIssuer = "nobody",
ValidateIssuer = true
;
【讨论】:
你好尼古拉斯。是的,有,默认情况下它是真的(这就是我不设置它的原因)。我已经设置了 IssueValidator,以便我可以复制/粘贴默认身份验证代码并查看为什么更改 ValidIssuer 不会禁止令牌。这就是我找到问题中提到的“问题”的方式...... @LuisAbreu 但是您的代码似乎将 IssueValidator 设置为 ValidateIssuer,这意味着按照惯例为 true。然后你的代码设置了问题,不是吗? 我已经用更多信息更新了帖子。我不明白为什么令牌的颁发者总是添加到 ValidIssuers 集合中,为什么默认的 IssueValidator 方法总是会在设置 ValidIssuer 属性时根据 ValidIssuers 集合检查颁发者(这将始终返回 true,因为令牌的颁发者最终被添加到 ValidIssuers 集合中!)。谢谢以上是关于JwtFormat:为啥将令牌的颁发者添加到 ValidIssuers 属性中?的主要内容,如果未能解决你的问题,请参考以下文章
Keycloak:从内部 docker 容器运行时令牌颁发者无效
Keycloak:作为 docker 服务运行时令牌颁发者无效
WSO2IS 5.10 自定义 JWT 令牌颁发者未在服务提供者配置中列出
验证使用 JSON Web 加密 (JWE) 加密的安全令牌的颁发者?