1

我有一个 WCF 服务,它托管在 ASP.NET MVC 应用程序中(如http://msdn.microsoft.com/en-us/library/aa702682.aspx中所述)。部分 MVC 操作和 WCF 服务操作受到保护,我对两者都使用 ASP.NET 表单身份验证:

// protected MVC action
[Authorize]
public ActionResult ProtectedMvcAction(string args)

// protected WCF operation
[PrincipalPermission(SecurityAction.Demand, Role = "User")]
public void ProtectedWcfOperation(string args)

我的 WCF 客户端确保表单身份验证.ASPXAUTHcookie 在每次 WCF 调用时传输到服务器。

这在很长一段时间内都非常有效。现在我正在HTTPS使用SSL证书向我的服务器添加加密。这需要我对 Web.config` 进行以下更改:

<basicHttpBinding>
  <binding name="ApiServiceBinding">
    <security mode="Transport">
      <transport clientCredentialType="None" />
    </security>
  </binding>
</basicHttpBinding>

服务被激活,客户端可以调用服务器操作。但是,[PrincipalPermission]受保护的服务器操作前面的属性突然阻止了所有服务调用。我发现了以下内容:

  • 在 HTTP 情况下(没有<security mode="Transport">),两者Thread.CurrentPrincipalHttpContext.Current.User都设置为一个RolePrincipal实例,属性中有一个FormsIdentity实例RolePrincipal.Identity。在这种情况下,一切正常。
  • 在 HTTPS 情况下(<security mode="Transport">在 web.config 中),该属性HttpContext.Current.User仍设置为RolePrincipal/FormsIdentity组合。但是,属性Thread.CurrentPrincipal突然设置为WindowsPrincipal/WindowsIdentity实例,这使得[PrincipalPermission]属性抛出异常。

我尝试了以下方法:

  • 将 更改AppDomain.CurrentDomain.SetPrincipalPolicy为每个可能的值(在Global.asax's中Application_Start),但这并没有改变任何东西。
  • Thread.CurrentPrincipal在 中设置属性Application_PostAuthenticate,但在Application_PostAuthenticate实际服务调用之间,Thread'再次CurrentPrincipal更改为 a WindowsPrincipal

有什么提示吗?我究竟做错了什么?

4

2 回答 2

3

这解决了它:

http://www.codeproject.com/Articles/304877/WCF-REST-4-0-Authorization-with-From-Based-authent

我修改了这段代码以涵盖 Windows 和 Forms 端点以及相同的服务 - 这也有效 -

public bool Evaluate( EvaluationContext evaluationContext, ref object state )
{
    bool ret = false;
    // get the authenticated client identity
    HttpCookie formsAuth = HttpContext.Current.Request.Cookies[ ".MyFormsCookie" ];
    if( null != formsAuth )
    {
        FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt( formsAuth.Value );
        if( null != ticket )
        {
            GenericIdentity client = new GenericIdentity( ticket.Name, "Forms" );

            // set the custom principal
            CustomPrincipal p = new CustomPrincipal( client );
            p.RoleManagerProvider = "Internet";
            evaluationContext.Properties[ "Principal" ] = p;

            ret = true;
        }
    }
    else
    {
        CustomPrincipal p = new CustomPrincipal( HttpContext.Current.User.Identity );
        p.RoleManagerProvider = "Intranet";
        evaluationContext.Properties[ "Principal" ] = p;

        // assume windows auth
        ret = true;

    }
    return ret;
}

它会查找表单身份验证 cookie,如果不存在则尝试使用 Windows 身份验证。我还“翻转”了内部和外部的角色提供者

这允许我将用户凭据从 Internet(通过转发 cookie)和 Intranet(使用 Windows 约束委派)传播到相同的内部服务。

我在 config 中进行了配置(而不是按照示例的代码),看起来不错。

对于行为,它类似于:

 <behavior name="FormsPaymentsBehavior">
          <serviceAuthorization principalPermissionMode="Custom" >
            <authorizationPolicies>
              <add policyType="FormsPolicy.AuthorizationPolicy,FormsPolicy" />
            </authorizationPolicies> 
          </serviceAuthorization>

这用于两个端点,因为 FormsPolicy(上图)处理这两个端点,您不能为不同的端点指定不同的行为。

绑定在适当的端点上强制执行 Windows 凭据握手:

<basicHttpBinding>
        <binding name="WindowsHttpBinding">
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows" />
          </security>
        </binding>
        <binding name="FormsHttpBinding" allowCookies="true">          
          <security mode="None">
            <transport clientCredentialType="None" />            
          </security>
        </binding>
      </basicHttpBinding>

运输方式可以更改为

<security mode="Transport">
            <transport clientCredentialType="None" />
          </security>

对于https,它工作正常。

对于您的自定义主体,我发现我必须明确调用角色管理器

...


public bool IsInRole( string role )
        {
            RoleProvider p = Roles.Providers[ RoleManagerProvider ];
            return p.IsUserInRole( Identity.Name, role );
        }

        public String RoleManagerProvider { get; set; }

...

我猜这是因为我不再使用任何 aspnet 兼容的东西。因为我根据我的身份验证类型来翻转角色管理器,所以嗡嗡声。

于 2012-09-26T14:57:19.210 回答
1

我也遇到过这个问题,这里有另一个报告(和我的)。http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/8f424d4f-2f47-4f85-a6b0-00f7e58871f1/

此线程指向正确的解决方案是创建自定义授权策略 (http://msdn.microsoft.com/en-us/library/ms729794.aspx) 和此代码项目文章 (http://www.codeproject. com/Articles/304877/WCF-REST-4-0-Authorization-with-From-Based-authent) 似乎准确地解释了如何为 FormsAuth 执行此操作 - 设置 evaluationContext.Properties["Principal"] = new CustomPrincipal(client ) 根据 MS 评论。

我还没有实现这个——我的“快速修复”是简单地恢复到一个普通的旧 asmx 服务——但我会“试一试”一段时间!

如果您找到其他解决方案 - 请告诉我。

于 2012-07-18T11:19:24.253 回答