在katana web api中,我使用:
appBuilder.UseIdentityServerBearerTokenAuthentication(
new IdentityServerBearerTokenAuthenticationOptions
{
Authority = "https://...",
ValidationMode = ValidationMode.Local,
RequiredScopes = new[] { "..." },
});
这似乎很好地找到了来自权威机构的公共签名密钥,并且(希望?)缓存它们等等。虽然我还没有尝试过,但我知道那里有ASP的等价物。 NET Core。
现在我需要做同样的事情,但不是在web api中间件中。所以我试图找到IdentityServer3.AccessTokenValidation.IdentityServerBearerTokenValidationMiddleware用来执行此操作的代码。我只能看到它调用了UseOAuthBearerAuthentication,它似乎在Microsoft.Owin.Security.OAuth中。我还没有能够找到与该签名相匹配的源代码版本。
在我看来,有人可能正在使用System.IdentityModel.Tokens.JwtSecurityTokenHandler并将一小段代码放入TokenValidationParameters的IssuerSigningKeyResolver中。这个漂亮的小片段是从元数据地址获取签名密钥。有谁知道那个代码是什么,或者有一个效果很好的部分?显然,我可以写它,但我讨厌重新发明轮子,加上我的未经测试。
答案 0 :(得分:1)
我们正在使用这个插入JWT处理程序的类:
答案 1 :(得分:0)
谢谢,至少特权。深入了解DiscoverydocumentIssuerSecurityTokenProvider
课程,我找到ConfigurationManager<OpenIdConnectConfiguration>
。使用它,我已经为OWIN中间件之外的访问令牌验证提出了以下帮助器类。
征求意见!
using Microsoft.IdentityModel.Protocols;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Security.Claims;
namespace WpfClient
{
public class AccessTokenValidator
{
protected TokenValidationParameters _accessTokenValidationParameters;
public AccessTokenValidator(string stsRoot)
{
stsRoot = stsRoot.TrimEnd('/');
var discoveryEndpoint = stsRoot + "/.well-known/openid-configuration";
var webHandler = new WebRequestHandler();
var httpClient = new HttpClient(webHandler);
var configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(discoveryEndpoint, httpClient);
_accessTokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = stsRoot,
RequireSignedTokens = true,
ValidateIssuerSigningKey = true,
IssuerSigningKeyResolver = (string token, SecurityToken securityToken, SecurityKeyIdentifier keyIdentifier, TokenValidationParameters validationParameters) => {
var signingTokens = configurationManager.GetConfigurationAsync().Result.JsonWebKeySet.GetSigningTokens();
foreach (var signingToken in signingTokens)
{
foreach (var clause in keyIdentifier)
{
var key = signingToken.ResolveKeyIdentifierClause(clause);
if (key != null)
{
return key;
}
}
}
return null;
},
RequireExpirationTime = true,
ValidateAudience = false, // See https://github.com/IdentityServer/IdentityServer3/issues/1365: "OAuth2 does not use the term 'audience' ... it instead uses the term 'scope' ... 'audience' and the 'aud' claim are JWT specific concepts."
ValidateLifetime = true,
};
}
public void ValidateAccessToken(string accessToken, IEnumerable<string> requiredScopes, IEnumerable<string> requiredRoles)
{
ClaimsPrincipal claimsPrincipal;
SecurityToken securityToken;
var handler = new JwtSecurityTokenHandler();
claimsPrincipal = handler.ValidateToken(accessToken, _accessTokenValidationParameters, out securityToken);
if (claimsPrincipal == null)
{
throw new NullReferenceException("ClaimsPrincipal object returned is null");
}
RequireClaims("scope", requiredScopes, claimsPrincipal);
RequireClaims("role", requiredRoles, claimsPrincipal);
}
private static void RequireClaims(string type, IEnumerable<string> requiredValues, ClaimsPrincipal claimsPrincipal)
{
if (requiredValues != null)
{
var haveClaims = claimsPrincipal.FindAll(type);
var missingRequiredValues = requiredValues.Where(s => !haveClaims.Any(c => c.Value.Equals(s, StringComparison.InvariantCultureIgnoreCase))).ToArray();
if (missingRequiredValues.Any())
{
var list = string.Join(", ", missingRequiredValues);
throw new InvalidDataException($"Missing required {type} claims: {list}");
}
}
}
}
}