問題描述
我正在嘗試將我的 ASP.NET 應用程序配置為接受使用對稱密鑰簽名的 JSON Web 令牌 (JWT).STS 無法為此使用證書,因此我們正在使用它們的對稱密鑰支持.
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.
就我而言,我正在使用 微軟的 JWT 開發者預覽版.不幸的是,我還沒有看到任何關于如何將其與對稱密鑰一起使用的示例.在使用各種工具進行了一些挖掘之后,我找到了 NamedKeyIssuerTokenResolver
并發現我可以 將其配置為使用對稱密鑰.例如:
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 NamedKeyIssuerTokenResolver
and discovered that I can configure it to use a symmetric key. For example:
<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>
我不完全確定我應該為那里的 name
使用什么.應該是受眾Uri,還是發行者Uri?無論如何,我知道如果我不包含 name
,我的程序啟動時會出現異常,因為 securityKey
元素需要該屬性.
I'm not entirely sure what I'm supposed to use for the name
there. 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 securityKey
element requires that attribute.
無論如何,這仍然不能解決問題.對 STS 進行身份驗證后,出現以下異常:
Whatever the case, this still doesn't resolve the issue. After I authenticate against the STS, I get the following exception:
[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
我是否缺少其他配置步驟?我在 name
屬性中放置了錯誤的東西嗎?或者這是 JWT 開發者預覽版中的一個已知錯誤?
Am I missing some other configuration step? Am I putting the wrong thing in the name
attribute? Or is this a known bug in the JWT Developer Preview?
推薦答案
2014/02/13 更新:
正如@leastprivilege 在下面指出的那樣,使用 JWT 的 RTM 版本要容易得多.我強烈建議您忽略這一點并使用他在 http://leastprivilege.com/2013/07/16/identityserver-using-ws-federation-with-jwt-tokens-and-symmetric-signatures/.
請注意,下面的原始答案是針對 Beta 版 Microsoft.IdentityModel.Tokens.JWT.升級到發布版本 System.IdentityModel.Tokens.Jwt 只需要多做一點工作.見下文.
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.
原來的主要問題是 JWTSecurityTokenHandler.ValidateToken(token)
方法沒有完全填充它傳遞給 JWTSecurityTokenHandler.ValidateToken(令牌,驗證參數)
.特別是,它不會填充 SigningToken
成員或 ValidIssuers
(或 ValidIssuer
).
The primary problem turns out to be that the method JWTSecurityTokenHandler.ValidateToken(token)
does not fully populate the TokenValidationParameters
that it passes to JWTSecurityTokenHandler.ValidateToken(token, validationParameters)
. In particular, it doesn't populate the SigningToken
member or the ValidIssuers
(or 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.
我的問題的解決方案是創建一個從 JWTSecurityTokenHandler
派生的自定義安全令牌處理程序.重寫 ValidateToken(token, validationParameters)
讓我有機會設置我需要的那些參數,然后調用基類的 ValidateToken
方法.
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 ValidateToken
method.
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);
}
}
在我的 Web.config 中,我只需要更改安全令牌處理程序:
In my Web.config, I just had to change the security token handler:
<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 . . .
2013 年 6 月,微軟正式發布了他們的 JWT.他們將命名空間更改為 System.IdentityModel.Tokens.Jwt.升級到那個之后,上面的解決方案停止工作.為了讓它工作,我必須將以下內容添加到我的 CustomJwtSecurityTokenHandler
中.這是對現有代碼的補充.
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.
public override ClaimsPrincipal ValidateToken(JwtSecurityToken jwt)
{
var vparms = new TokenValidationParameters
{
AllowedAudiences = Configuration.AudienceRestriction.AllowedAudienceUris.Select(s => s.ToString())
};
return ValidateToken(jwt, vparms);
}
這篇關于如何使用對稱密鑰配置 Microsoft JWT?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!