【问题标题】:Serializing / Deserializing GenericXmlSecurityToken and security - CRM Auth序列化/反序列化 GenericXmlSecurityToken 和安全性 - CRM Auth
【发布时间】:2014-01-15 09:21:12
【问题描述】:

我正在使用来自Microsoft.Xrm.Sdk.Client.IServiceManagementAuthenticate 方法对 CRM 用户进行身份验证。
该方法返回 System.IdentityModel.Tokens.GenericXmlSecurityToken 我需要作为 WebService 响应(JSON 或 XML 格式)返回。

计划是让 WebService 客户端在后续请求中传递此令牌。
我的问题是我无法构造回令牌...

我的理解是,我需要TokenXmlProofTokenInternalTokenReference来构造有效的GenericXmlSecurityToken,可以用于身份验证。

我的问题:

  • 我可以将ProofTokenInternalTokenReference 发送回WebService 客户端,它是否安全?我可以轻松返回 TokenXML、ProofToken 和 InternalTokenReference,但我不确定它是否安全...
  • 如果上面的答案是,是否还有其他方法可以序列化/反序列化此类令牌,​​以便将其传递回客户端?

提前感谢所有帮助!
问候

【问题讨论】:

    标签: .net security authentication dynamics-crm-2011


    【解决方案1】:

    不保证以下代码不会过时,但适用于当前使用的 Dynamics CRM 版本(2011、2013 和 2015)。从 2015 年开始,支持 OAuth,这似乎是通过网络传递令牌的更好方式。

    SecurityTokenResponse 转换为Base64 编码字符串:

        public static string Serialize(SecurityTokenResponse securityTokenResponse)
        {
            XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
            xmlWriterSettings.Encoding = Encoding.UTF8;
    
            using (MemoryStream memoryStream = new MemoryStream())
            using (XmlWriter xmlWriter = XmlWriter.Create(memoryStream, xmlWriterSettings))
            {
                WSTrust13ResponseSerializer serializer = new WSTrust13ResponseSerializer();
                WSTrustSerializationContext context = new WSTrustSerializationContext();
                serializer.WriteXml(securityTokenResponse.Response, xmlWriter, context);
                xmlWriter.Flush();
    
                return Convert.ToBase64String(memoryStream.ToArray());
            }
        }
    

    将 Base64 编码的字符串转换回SecurityTokenResponse

        public static SecurityTokenResponse ParseToken(string serializedToken)
        {
            RequestSecurityTokenResponse response;
            using (MemoryStream memoryStream = new MemoryStream(Convert.FromBase64String(serializedToken)))
            using (XmlReader xmlReader = XmlReader.Create(memoryStream))
            {
                WSTrust13ResponseSerializer serializer = new WSTrust13ResponseSerializer();
                WSTrustSerializationContext serializationContext = new WSTrustSerializationContext();
                response = serializer.ReadXml(xmlReader, serializationContext);
            }
    
            SecurityToken proofKey = new BinarySecretSecurityToken(response.RequestedProofToken.ProtectedKey.GetKeyBytes());
            DateTime? created = null;
            DateTime? expires = null;
            if (response.Lifetime != null)
            {
                created = response.Lifetime.Created;
                expires = response.Lifetime.Expires;
            }
            if (!created.HasValue)
            {
                throw new Exception("Created unspecified");
            }
            if (!expires.HasValue)
            {
                throw new Exception("Expires unspecified");
            }
    
            SecurityToken securityToken = new GenericXmlSecurityToken(
                    response.RequestedSecurityToken.SecurityTokenXml,
                    proofKey,
                    created.Value,
                    expires.Value,
                    response.RequestedAttachedReference,
                    response.RequestedUnattachedReference,
                    new ReadOnlyCollection<IAuthorizationPolicy>(new List<IAuthorizationPolicy>())
                );
    
            return new SecurityTokenResponse()
            {
                Response = response,
                Token = securityToken
            };
        }
    

    选择 Base64 作为编码的原因是因为我通过 XML Web 服务发送令牌。这消除了对 XML 字符串进行 XML 转义的需要。这可能会导致大量转义:&amp;gt;&amp;lt;&amp;amp; 等。如果您没有通过 XML Web 服务发送序列化令牌,您可能希望使用更易读的编码,例如 @ 987654328@.

    【讨论】:

      【解决方案2】:

      我已经解决了我的问题 - 任何对解决方案感兴趣的人的信息:
      我最初的方法是不正确的并且过于复杂。其实很简单。

      Authenticate 方法返回AuthenticationCredentials,从中我们可以得到SecurityTokenResponse.Response,它是Microsoft.IdentityModel.Protocols.WSTrust.RequestSecurityTokenResponse 的类型。

      可以分别使用WSTrust13ResponseSerializerWriteXml / ReadXml 方法轻松地序列化/反序列化该对象。

      这解决了我的问题,我现在可以序列化令牌,将它们传递给客户端并在每个请求上回读。

      【讨论】:

        猜你喜欢
        • 2019-08-20
        • 2016-12-15
        • 1970-01-01
        • 2017-04-03
        • 2012-12-08
        • 2012-03-25
        • 1970-01-01
        • 2012-03-17
        相关资源
        最近更新 更多