.net 如何使用对称密钥配置 Microsoft JWT?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14735753/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to configure Microsoft JWT with symmetric key?
提问by Jim Mischel
I'm trying to configure my ASP.NET app to accept a JSON Web Token (JWT) that is signed with a symmetric key. The STS isn't capable of using certificates for this, so we're using their symmetric key support.
我正在尝试将我的 ASP.NET 应用程序配置为接受使用对称密钥签名的 JSON Web 令牌 (JWT)。STS 无法为此使用证书,因此我们使用它们的对称密钥支持。
On my end, I'm using Microsoft's JWT Developer Preview. Unfortunately, I've not seen any examples of how to use that with a symmetric key. After some digging around with various tools, I found the NamedKeyIssuerTokenResolverand discovered that I canconfigure it to use a symmetric key. For example:
最后,我使用的是Microsoft 的 JWT Developer Preview。不幸的是,我还没有看到任何有关如何将其与对称密钥一起使用的示例。在使用各种工具进行了一些挖掘之后,我发现NamedKeyIssuerTokenResolver并发现我可以将其配置为使用对称密钥。例如:
<securityTokenHandlers>
<add type="Microsoft.IdentityModel.Tokens.JWT.JWTSecurityTokenHandler,Microsoft.IdentityModel.Tokens.JWT" />
<securityTokenHandlerConfiguration>
<certificateValidation certificateValidationMode="PeerTrust" />
<issuerTokenResolver
type="Microsoft.IdentityModel.Tokens.JWT.NamedKeyIssuerTokenResolver,
Microsoft.IdentityModel.Tokens.JWT">
<securityKey
symmetricKey="+zqf97FD/xyzzyplugh42ploverFeeFieFoeFooxqjE="
name="https://localhost/TestRelyingParty" />
</issuerTokenResolver>
</securityTokenHandlerConfiguration>
</securityTokenHandlers>
I'm not entirely sure what I'm supposed to use for the namethere. Should it be the audience Uri, perhaps the issuer Uri? In any case, I know that if I don't include a name, I get an exception when my program starts because the securityKeyelement requires that attribute.
我不完全确定我应该在name那里使用什么。应该是观众Uri,还是发行人Uri?无论如何,我知道如果我不包含 a name,当我的程序启动时我会得到一个异常,因为该securityKey元素需要该属性。
Whatever the case, this still doesn't resolve the issue. After I authenticate against the STS, I get the following exception:
无论如何,这仍然不能解决问题。对 STS 进行身份验证后,出现以下异常:
[SecurityTokenValidationException: JWT10310: Unable to validate signature. validationParameters.SigningTokenResolver type: 'Microsoft.IdentityModel.Tokens.JWT.NamedKeyIssuerTokenResolver', was unable to resolve key to a token.
The SecurityKeyIdentifier is:
'SecurityKeyIdentifier
(
IsReadOnly = False,
Count = 1,
Clause[0] = Microsoft.IdentityModel.Tokens.JWT.NamedKeyIdentifierClause
)
'. validationParameters.SigningToken was null.]
Microsoft.IdentityModel.Tokens.JWT.JWTSecurityTokenHandler.ValidateSignature(JWTSecurityToken jwt, TokenValidationParameters validationParameters) +2111
Microsoft.IdentityModel.Tokens.JWT.JWTSecurityTokenHandler.ValidateToken(JWTSecurityToken jwt, TokenValidationParameters validationParameters) +138
Microsoft.IdentityModel.Tokens.JWT.JWTSecurityTokenHandler.ValidateToken(SecurityToken token) +599
System.IdentityModel.Tokens.SecurityTokenHandlerCollection.ValidateToken(SecurityToken token) +135
System.IdentityModel.Services.TokenReceiver.AuthenticateToken(SecurityToken token, Boolean ensureBearerToken, String endpointUri) +117
System.IdentityModel.Services.WSFederationAuthenticationModule.SignInWithResponseMessage(HttpRequestBase request) +698
System.IdentityModel.Services.WSFederationAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs args) +123924
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +80
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +165
Am I missing some other configuration step? Am I putting the wrong thing in the nameattribute? Or is this a known bug in the JWT Developer Preview?
我是否缺少其他一些配置步骤?我在name属性中放了错误的东西吗?或者这是 JWT 开发人员预览版中的已知错误?
回答by Jim Mischel
Update 2014/02/13:
2014/02/13 更新:
As @leastprivilege points out below, this is a whole lot easier with the RTM version of the JWT. I strongly suggest that you ignore this and go with the example he provides at http://leastprivilege.com/2013/07/16/identityserver-using-ws-federation-with-jwt-tokens-and-symmetric-signatures/.
正如@leastprivilege 在下面指出的那样,使用 JWT 的 RTM 版本要容易得多。我强烈建议您忽略这一点,并使用他在http://leastprivilege.com/2013/07/16/identityserver-using-ws-federation-with-jwt-tokens-and-symmetric-signatures/ 上提供的示例。
Note that the original answer below was for the Beta version, Microsoft.IdentityModel.Tokens.JWT. Upgrading to the release version, System.IdentityModel.Tokens.Jwt, required just a little more work. See below.
请注意,下面的原始答案适用于 Beta 版 Microsoft.IdentityModel.Tokens.JWT。升级到发行版 System.IdentityModel.Tokens.Jwt 只需要多做一点工作。见下文。
The primary problem turns out to be that the method JWTSecurityTokenHandler.ValidateToken(token)does not fully populate the TokenValidationParametersthat it passes to JWTSecurityTokenHandler.ValidateToken(token, validationParameters). In particular, it doesn't populate the SigningTokenmember or the ValidIssuers(or ValidIssuer).
主要问题是该方法JWTSecurityTokenHandler.ValidateToken(token)没有完全填充TokenValidationParameters它传递给的JWTSecurityTokenHandler.ValidateToken(token, validationParameters)。特别是,它不会填充SigningToken成员或ValidIssuers(或ValidIssuer)。
Interestingly, the configuration I showed in my original question actually is loaded by the token resolver, and is available at runtime, as you can see in the code below.
有趣的是,我在原始问题中显示的配置实际上是由令牌解析器加载的,并且在运行时可用,如下面的代码所示。
I don't know how to specify the valid issuer string in the configuration file, though. I strongly suspect that there's a place to put that info, but I haven't yet figured out where it belongs.
不过,我不知道如何在配置文件中指定有效的颁发者字符串。我强烈怀疑有一个地方可以放置这些信息,但我还没有弄清楚它属于哪里。
The solution to my problem is to create a custom security token handler that derives from JWTSecurityTokenHandler. Overriding ValidateToken(token, validationParameters)gives me the opportunity to set those parameters that I need, and then call the base class's ValidateTokenmethod.
我的问题的解决方案是创建一个从JWTSecurityTokenHandler. 覆盖ValidateToken(token, validationParameters)使我有机会设置我需要的那些参数,然后调用基类的ValidateToken方法。
public class CustomJwtSecurityTokenHandler: JWTSecurityTokenHandler
{
// Override ValidateSignature so that it gets the SigningToken from the configuration if it doesn't exist in
// the validationParameters object.
private const string KeyName = "https://localhost/TestRelyingParty";
private const string ValidIssuerString = "https://mySTSname/trust";
public override ClaimsPrincipal ValidateToken(JWTSecurityToken jwt, TokenValidationParameters validationParameters)
{
// set up valid issuers
if ((validationParameters.ValidIssuer == null) &&
(validationParameters.ValidIssuers == null || !validationParameters.ValidIssuers.Any()))
{
validationParameters.ValidIssuers = new List<string> {ValidIssuerString};
}
// and signing token.
if (validationParameters.SigningToken == null)
{
var resolver = (NamedKeyIssuerTokenResolver)this.Configuration.IssuerTokenResolver;
if (resolver.SecurityKeys != null)
{
List<SecurityKey> skeys;
if (resolver.SecurityKeys.TryGetValue(KeyName, out skeys))
{
var tok = new NamedKeySecurityToken(KeyName, skeys);
validationParameters.SigningToken = tok;
}
}
}
return base.ValidateToken(jwt, validationParameters);
}
}
In my Web.config, I just had to change the security token handler:
在我的 Web.config 中,我只需要更改安全令牌处理程序:
<securityTokenHandlers>
<!--<add type="Microsoft.IdentityModel.Tokens.JWT.JWTSecurityTokenHandler,Microsoft.IdentityModel.Tokens.JWT" />-->
<!-- replaces the default JWTSecurityTokenHandler -->
<add type="TestRelyingParty.CustomJwtSecurityTokenHandler,TestRelyingParty" />
Nothing like spending three or four days researching a problem that is solved with a couple dozen lines of code . . .
没有什么比花三四天时间研究一个用几十行代码解决的问题更合适的了。. .
Addition for new version
新版本的补充
In June of 2013, Microsoft officially released their JWT. They changed the namespace to System.IdentityModel.Tokens.Jwt. After upgrading to that, the solution above stopped working. To get it working, I had to add the following to my CustomJwtSecurityTokenHandler. That's in addition to the existing code.
2013 年 6 月,微软正式发布了他们的 JWT。他们将命名空间更改为 System.IdentityModel.Tokens.Jwt。升级到那个后,上面的解决方案停止工作。为了让它工作,我必须将以下内容添加到我的CustomJwtSecurityTokenHandler. 这是现有代码的补充。
public override ClaimsPrincipal ValidateToken(JwtSecurityToken jwt)
{
var vparms = new TokenValidationParameters
{
AllowedAudiences = Configuration.AudienceRestriction.AllowedAudienceUris.Select(s => s.ToString())
};
return ValidateToken(jwt, vparms);
}
回答by Vladik Branevich
Here is a usage example of this library with .Net 4.5 that issues and validates a JWT signed with symmetric key based HMAC SHA256 (all in code and without WIF):
下面是这个库的使用示例,它带有 .Net 4.5,它发布和验证使用基于对称密钥的 HMAC SHA256 签名的 JWT(全部在代码中,没有 WIF):
string jwtIssuer = "MyIssuer";
string jwtAudience = "MyAudience";
// Generate symmetric key for HMAC-SHA256 signature
RNGCryptoServiceProvider cryptoProvider = new RNGCryptoServiceProvider();
byte[] keyForHmacSha256 = new byte[64];
cryptoProvider.GetNonZeroBytes(keyForHmacSha256);
///////////////////////////////////////////////////////////////////
// Create signing credentials for the signed JWT.
// This object is used to cryptographically sign the JWT by the issuer.
SigningCredentials sc = new SigningCredentials(
new InMemorySymmetricSecurityKey(keyForHmacSha256),
"http://www.w3.org/2001/04/xmldsig-more#hmac-sha256",
"http://www.w3.org/2001/04/xmlenc#sha256");
///////////////////////////////////////////////////////////////////
// Create token validation parameters for the signed JWT
// This object will be used to verify the cryptographic signature of the received JWT
TokenValidationParameters validationParams =
new TokenValidationParameters()
{
AllowedAudience = s_jwtAudience,
ValidIssuer = s_jwtIssuer,
ValidateExpiration = true,
ValidateNotBefore = true,
ValidateIssuer = true,
ValidateSignature = true,
SigningToken = new BinarySecretSecurityToken(keyForHmacSha256),
};
///////////////////////////////////////////////////////////////////
// Create JWT handler
// This object is used to write/sign/decode/validate JWTs
JWTSecurityTokenHandler jwtHandler = new JWTSecurityTokenHandler();
// Create a simple JWT claim set
IList<Claim> payloadClaims = new List<Claim>() { new Claim("clm1", "clm1 value"), };
// Create a JWT with signing credentials and lifetime of 12 hours
JWTSecurityToken jwt =
new JWTSecurityToken(jwtIssuer, jwtAudience, payloadClaims, sc, DateTime.UtcNow, DateTime.UtcNow.AddHours(12.0));
// Serialize the JWT
// This is how our JWT looks on the wire: <Base64UrlEncoded header>.<Base64UrlEncoded body>.<signature>
string jwtOnTheWire = jwtHandler.WriteToken(jwt);
// Validate the token signature (we provide the shared symmetric key in `validationParams`)
// This will throw if the signature does not validate
jwtHandler.ValidateToken(jwtOnTheWire, validationParams);
// Parse JWT from the Base64UrlEncoded wire form (<Base64UrlEncoded header>.<Base64UrlEncoded body>.<signature>)
JWTSecurityToken parsedJwt = jwtHandler.ReadToken(jwtOnTheWire) as JWTSecurityToken;
回答by Brent Schmaltz
Jim,
吉姆,
Thanks for trying out the preview, sorry that you had some issues that weren't obvious :-(.
感谢您试用预览版,很抱歉您遇到了一些不明显的问题:-(。
The NamedKeyIssuerTokenResolverwas born from two ideas:
在NamedKeyIssuerTokenResolver从两个想法诞生了:
- the need to associate a key for checking the signature that is a shared secret;
- multiple valid keys could be in use at the same time.
- 需要关联密钥以检查作为共享秘密的签名;
- 可以同时使用多个有效密钥。
It was designed to work with the NamedKeySecurityTokenthat has a name and a number of keys. The NKITRcan return a NKSTwhich simplifies checking a signature when multiple keys are in play.
它旨在与NamedKeySecurityToken具有名称和多个键的 一起使用。该NKITR可以返回NKST当多个键在起作用从而简化了检查签名。
One goal for the NKITRwas to provide a mapping between the JWT issclaim (in the header) and a key. When it's time to check the signature, the JWTHandlerchecks:
的一个目标NKITR是提供 JWTiss声明(在标头中)和键之间的映射。当需要检查签名时,JWTHandler检查:
TokenValidationParamerter.SigningToken, if found use it;- A
SecurityKeyIdentifierobtained fromJWT.Header.SigningKeyIdentifier(currently only x5t is supported) is sent to the currentINR; - A
NamedKeyIdentifierClauseis created from theJwt.Issuerand sent to the currentINR.
TokenValidationParamerter.SigningToken, 如果发现使用它;SecurityKeyIdentifier从JWT.Header.SigningKeyIdentifier(目前仅支持 x5t)获取的A发送到当前INR;- A
NamedKeyIdentifierClause从 中创建Jwt.Issuer并发送到当前INR。
Since a SecurityTokencan contain multiple keys, each one in order is used to check the signature, first success stops and the JWT.SigningTokenwill contain the SecurityTokenthat validated the signature.
由于 aSecurityToken可以包含多个密钥,因此按顺序使用每个密钥来检查签名,第一个成功停止并且JWT.SigningToken将包含SecurityToken验证签名的 。
Jim and Willy,
吉姆和威利,
Sorry about the confusion with the ValidateToken(SecurityToken)overload method. Parameters are moved from Configurationto ValidationParameters, but not the properties like ValidIssuerthat have a single item, but
很抱歉与ValidateToken(SecurityToken)重载方法混淆。参数从Configurationto移动ValidationParameters,但没有像ValidIssuer这样的属性有单个项目,但是
IssuerNameRegistry -> VP.IssuerNameRegistry
IssuerTokenResolver -> VP.SigningTokenResolver
AllowedAudienceUris -> VP.AllowedAudiences
CertificateValidator -> VP.CertificateValidator
SaveBootStrapContext -> VP.SaveBootStrapContext
Brent
布伦特
回答by Willy Van den Driessche
AFAIK, the JWtSecurityTokenHandler is not yet ready to be used from a configuration file. The example given by Vittorio Bertocci is also a "code example". In that, he explicitly calls the overloaded ValidateToken with the additional tokenValidationParameters parameter that contains all stuff needed to do the validation (like the symmetric key).
Unfortunately, that overload is not called by the normal Wif pipeline (it calls the ValidateToken with just the token as a parameter)
I resolved to subclassing the jwtsecurity token handler, override LoadCustomConfiguration to manually load the stuff needed to create a tokenValidationParemeter object (I had to create some configuration objects for this). Then I did an override of validateToken to explictly call the overload with the additional parameter (which I could create on the fly with the parameters I read from the config). All very cumbersome to do but the only way to tap into the power of the tokenValidationparameters. (but I might be wrong of course)
AFAIK, JWtSecurityTokenHandler 尚未准备好从配置文件中使用。Vittorio Bertocci 给出的例子也是一个“代码示例”。在这种情况下,他显式调用重载的 ValidateToken 并带有附加的 tokenValidationParameters 参数,该参数包含进行验证所需的所有内容(如对称密钥)。
不幸的是,该重载不是由普通的 Wif 管道调用(它仅使用令牌作为参数调用 ValidateToken)我决定子类化 jwtsecurity 令牌处理程序,覆盖 LoadCustomConfiguration 以手动加载创建 tokenValidationParemeter 对象所需的东西(我有为此创建一些配置对象)。然后我覆盖了 validateToken 以使用附加参数显式调用重载(我可以使用从配置中读取的参数即时创建)。所有这些都非常繁琐,但这是利用 tokenValidationparameters 功能的唯一方法。(但我当然可能是错的)
<issuerTokenResolver type="Microsoft.IdentityModel.Tokens.JWT.NamedKeyIssuerTokenResolver, Microsoft.IdentityModel.Tokens.JWT">
<securityKey symmetricKey="01234567890123456789012345678901" name="MyIssuer"/>
</issuerTokenResolver>
<securityTokenHandlers>
回答by leastprivilege
Here is how it works with the RTM version of the JWT handler: http://leastprivilege.com/2013/07/16/identityserver-using-ws-federation-with-jwt-tokens-and-symmetric-signatures/
以下是 JWT 处理程序的 RTM 版本的工作方式:http: //leastprivilege.com/2013/07/16/identityserver-using-ws-federation-with-jwt-tokens-and-symmetric-signatures/

