使用 System.ServiceModel.ServiceAuthenticationManager 自定义 WCF 身份验证?

Posted

技术标签:

【中文标题】使用 System.ServiceModel.ServiceAuthenticationManager 自定义 WCF 身份验证?【英文标题】:Custom WCF authentication with System.ServiceModel.ServiceAuthenticationManager? 【发布时间】:2011-04-12 13:27:56 【问题描述】:

我正在研究自定义 WCF 身份验证和授权,发现一些关于 UserNamePasswordValidatorServiceAuthorizationManager 的文章。

我还发现了有关使用自定义 System.ServiceModel.ServiceAuthenticationManager死链接)的线索,但 msdn 并没有提供很多关于它(http://msdn.microsoft.com/en-us/library/system.servicemodel.serviceauthenticationmanager.aspx)。

所以我在这里:有人知道更多关于 ServiceAuthenticationManager 的信息吗?

一般来说,您将如何设置自定义 WCF 身份验证?

【问题讨论】:

这很奇怪,但似乎仍然有很多关于 ServiceAuthorizationManager 的信息和示例,但几乎没有关于 ServiceAuthenticationManager 的任何东西 【参考方案1】:

你是对的,这方面的文档根本没有帮助。

我使用这个类的方式如下。将 Authenticate() 方法重写为:

    从传入消息中提取身份验证令牌(例如用户名/密码) 验证令牌并使用它们创建 IPrincipal 对象。这将是调用服务操作期间使用的主体。 将 IPrincipal 对象添加到 message.Properties 集合,以便稍后在 WCF 处理管道中使用它

此时您不能只设置线程主体,因为它稍后会被 WCF 更改。

ServiceAuthenticationManager.Authenticate() 方法中的代码如下所示:

public override ReadOnlyCollection<IAuthorizationPolicy> Authenticate(ReadOnlyCollection<IAuthorizationPolicy> authPolicy, Uri listenUri, ref Message message)

   int tokenPosition = message.Headers.FindHeader("Token", "http://customnamespace.org");
   string token = message.Headers.GetHeader<string>(tokenPosition);

   IPrincipal user = new CustomPrincipal(token);

   message.Properties["Principal"] = user;

   return authPolicy;

然后你添加一个自定义的授权策略,

    从消息中检索 IPrincipal(使用 System.ServiceModel.EvaluationContext.Current.IncomingMessageProperties 集合)。 将 IPrincipal 推送到 EvaluationContext.Properties 集合中 根据 IPrincipal.IsInRole() 方法进行声明

IAuthorizationPolicy() 方法中的代码如下所示

public bool Evaluate(EvaluationContext evaluationContext, ref object state)

    IPrincipal user = OperationContext.Current.IncomingMessageProperties["Principal"] as IPrincipal;
    evaluationContext.Properties["Principal"] = user;
    evaluationContext.Properties["Identities"] = new List<IIdentity>  user.Identity ;

    IList<Claim> roleClaims = this.GetRoleClaims(user);

    evaluationContext.AddClaimSet(this, new DefaultClaimSet(this.Issuer, roleClaims));

    return true;

在服务行为配置中,您需要设置 principalPermissionMode="Custom",以便 WCF 将 IPrincipal 设置为执行线程上的主体,以进行实际的服务操作调用。

<serviceAuthorization principalPermissionMode="Custom"...

【讨论】:

谢谢,这真的很有帮助。干杯:-) 是否可以在 ServiceAuthenticationManager.Authenticate() 中的 ClaimSet 中添加身份声明,而不是将 Principal 放入 Properties 中? 有可能。我认为的预期流程是 AuthenticationManager 验证凭据并使用直接来自身份提供者的声明(身份声明将是其中之一)创建主体,AuthorizationPolicy 转换声明并且 AuthorizationManager 做出授权决定。虽然这方面的文档很少,所以很难说。无论如何,现在 WIF 可用,模型更简单:o) 非常感谢 Mike 提供的示例,但我仍在为此苦苦挣扎。我发现的 ServiceAuthenticationManager 示例都掩盖了“从标题中提取用户名和密码”。看来我不必担心解析 XML,但不知道如何避免它。可以设置自定义UserNamePasswordValidator 并覆盖Validate(username, password),但这会在之前 ServiceAuthenticationManager 被调用。我只是希望来电者能够设置ClientCredentials;这可能吗?还是您的 GetHeader 仅调用自定义标头逻辑? @TobyJ:如果您只想使用通过 ClientCredentials 设置的用户名和密码,您确实应该使用自定义 UserNamePasswordValidator。正如你所说,我描述的解决方案是针对自定义标题的。在我的例子中,我正在使用一个遗留服务,该服务将用户名和密码作为自定义消息头,而不是作为 HTTP 或 SOAP 标准头的一部分。抱歉没有说清楚...

以上是关于使用 System.ServiceModel.ServiceAuthenticationManager 自定义 WCF 身份验证?的主要内容,如果未能解决你的问题,请参考以下文章

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)