如何将 JWT 令牌与 WCF 和 WIF 一起使用? [英] How to use JWT tokens with WCF and WIF?
问题描述
我们正在使用 IdentityServer3 并且到目前为止对它非常满意.
在 MS 和 Thinktecture OWIN 中间件的帮助下,我们可以非常轻松地保护 MVC 和 ASP.NET Web API 应用程序.
We're using IdentityServer3 and have been very happy with it so far.
We've gotten to secure MVC and ASP.NET Web API applications very easily with the help of both MS and Thinktecture OWIN middlewares.
我们为之工作的客户端仍然有很多 SOAP WCF 服务,而这正是我们陷入困境的地方.
The client we're working for still has a lot of SOAP WCF services, and this is where we're getting stuck.
我不会撒谎,我对 WCF 的经验还很遥远,我只将它用于非常基本的场景 - 了解 basicHttpBinding,没有传输或消息安全性.
I'm not gonna lie, I'm far from being experienced with WCF, I've only used it for very basic scenarios - understand basicHttpBinding, no transport nor message security.
这就是我想要实现的目标:
This is what I want to achieve:
- 客户端从 IdentityServer 获取 JWT 访问令牌
- 令牌最终出现在 SOAP 消息头中
- WCF 读取并验证令牌
- WCF 检查声明并根据某些标准执行授权
我无法进行第三步.
- 我正在使用具有
TransportWithMessageCredential
安全模式的ws2007FederationHttpBinding
.该消息包含一个BearerKey
并且令牌的类型为urn:ietf:params:oauth:token-type:jwt
- 该服务使用 WIF 身份管道,我在其中添加了
System.IdentityModel.Tokens.Jwt
NuGet 包中的JwtSecurityTokenHandler
- I'm using a
ws2007FederationHttpBinding
withTransportWithMessageCredential
security mode. The message contains aBearerKey
and the token is of typeurn:ietf:params:oauth:token-type:jwt
- The service uses the WIF identity pipeline, in which I added the
JwtSecurityTokenHandler
from theSystem.IdentityModel.Tokens.Jwt
NuGet package
- STS 发出的 JWT 令牌被包装在
BinarySecurityToken
XML 元素中,它本身被包装在GenericXmlSecurityElement
- 此令牌用作
ChannelFactory
的
CreateChannelWithIssuedToken
的参数- The JWT token issued by the STS is wrapped in a
BinarySecurityToken
XML element, itself wrapped in aGenericXmlSecurityElement
- This token is used as a parameter of the
CreateChannelWithIssuedToken
of theChannelFactory
令牌在 SOAP 标头中找到并传递给 JwtSecurityTokenHandler
.
但随后抛出异常:
The token is found in the SOAP header and passed on to the JwtSecurityTokenHandler
.
But then an exception is thrown:
System.ServiceModel.Security.MessageSecurityException: Message security verification failed. ---> System.IndexOutOfRangeException: Index was outside the bounds of the array.
at System.Xml.XmlBufferReader.GetChars(Int32 offset, Int32 length, Char[] chars)
at System.Xml.XmlBufferReader.GetString(Int32 offset, Int32 length)
at System.Xml.StringHandle.GetString()
at System.Xml.XmlBaseReader.ReadEndElement()
at System.ServiceModel.Security.ReceiveSecurityHeader.ExecuteFullPass(XmlDictionaryReader reader)
at System.ServiceModel.Security.ReceiveSecurityHeader.Process(TimeSpan timeout, ChannelBinding channelBinding, ExtendedProtectionPolicy extendedProtectionPolicy)
at System.ServiceModel.Security.TransportSecurityProtocol.VerifyIncomingMessageCore(Message& message, TimeSpan timeout)
at System.ServiceModel.Security.TransportSecurityProtocol.VerifyIncomingMessage(Message& message, TimeSpan timeout)
--- End of inner exception stack trace ---
JustDecompile 之后,在进一步读取 SOAP 标头中的 XML 元素时,似乎出现了错误.奇怪的是令牌是最后一个元素.整个消息如下所示:
After JustDecompiling, it looks like there's an error when further reading the XML elements in the SOAP header. What's strange is that the token is the last element. Here's what the whole message looks like:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<s:Header>
<a:Action s:mustUnderstand="1">http://tempuri.org/IService/GetListOfStrings</a:Action>
<a:MessageID>urn:uuid:5c22d4e2-f9b8-451a-b4ca-a844f41f7231</a:MessageID>
<ActivityId CorrelationId="554fc496-7c47-4063-9539-d25606f186b0" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">1213dcd7-55b7-4153-8a6d-92e0922f76dd</ActivityId>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPo90CpMlUwLBOmEPkZ5C8fRQAAAAAVWkkf2rJS0qImBv+Yx1recUXdbBLjThDkAMkwfW3/2AACQAA</VsDebuggerCausalityData>
<a:To s:mustUnderstand="1">https://localhost.fiddler:44322/Service.svc</a:To>
<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<u:Timestamp u:Id="_0">
<u:Created>2015-05-21T06:41:45.362Z</u:Created>
<u:Expires>2015-05-21T06:46:45.362Z</u:Expires>
</u:Timestamp>
<wsse:BinarySecurityToken ValueType="urn:ietf:params:oauth:token-type:jwt" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><!-- Removed --></wsse:BinarySecurityToken>
</o:Security>
</s:Header>
<s:Body>
<GetListOfStrings xmlns="http://tempuri.org/" />
</s:Body>
</s:Envelope>
看起来没有什么畸形或任何东西.从堆栈跟踪来看,在读取 </o:Security>
结束元素时必须抛出异常,因为令牌已正确读取和处理.
Doesn't look like there's something malformed or anything. From the stack trace, the exception must be thrown when reading the </o:Security>
end element since the token was properly read and handled.
我分叉了 samples repo,如果您愿意,可以看看.以下是相关项目:
I forked the samples repo so you can have a look if you feel like it. Here are the relevant projets:
SelfHost (Minimal)
在sources
文件夹中.这是 STS- 在
Clients
解决方案中,WCF 服务位于APIs
文件夹中 - 在
Clients
解决方案中,WCF 客户端是Console Client Credentials With Wcf
项目
SelfHost (Minimal)
in thesources
folder. This is the STS- In the
Clients
solution, the WCF service is in theAPIs
folder - In the
Clients
solution, the WCF client is theConsole Client Credentials With Wcf
project
最好的启动方式是先启动STS,然后右键->;调试->在 WCF 服务上启动新实例
,然后在 WCF 客户端上启动新实例.
Best way to fire it up is to start the STS first, then Right click -> Debug -> Start new instance
on the WCF service, then the same on the WCF client.
提前致谢!
推荐答案
我没能解决这个问题,但 IdentityServer 的开发人员之一 Dominick Baier 找到了解决方法.
他认为异常来自 WCF 中的错误或 WCF 与 JwtSecurityTokenHandler
之间的不兼容.由于他认为 WCF 完成,他不希望有人来看看它.
I didn't get to solve this problem but Dominick Baier, one of the developers of IdentityServer, found a workaround.
He thinks the exception comes from a bug in WCF or an incompatibility between WCF and the JwtSecurityTokenHandler
. Since he considers WCF done, he doesn't expect someone to take a look at it.
他的解决方案是将 JWT 令牌包装在 SAML 令牌中.然后,通过继承 SamlSecurityTokenHandler
,将其取回并针对 JwtSecurityTokenHandler
的实例进行验证.
His solution is to wrap the JWT token in a SAML token. Then, by subclassing SamlSecurityTokenHandler
, get it back and validate it against an instance of JwtSecurityTokenHandler
.
以下是链接:
现在大家玩得开心:-)
Everybody have fun, now :-)
这篇关于如何将 JWT 令牌与 WCF 和 WIF 一起使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!