为什么Thread.CurrentPrincipal.Identity.IsAuthenticated总是假的?

时间:2014-11-12 08:30:54

标签: c# wcf authentication current-principal

我有这个WCF服务,我试图在其中应用身份验证和授权机制 这是我第一次这样做,我所拥有的是这个服务的web.config serviceModel标签:

  <system.serviceModel>
<services>
  <service name="RoleBasedServices.SecureServiceExternal" behaviorConfiguration="externalServiceBehavior">
    <endpoint contract="AuthService.IService1" binding="wsHttpBinding" bindingConfiguration="wsHttpUsername" />
  </service>
</services>
<bindings>
  <wsHttpBinding>
    <binding name="wsHttpUsername">
      <security mode="Message">
        <message clientCredentialType="UserName" negotiateServiceCredential="false" establishSecurityContext="false" />
      </security>
    </binding>
  </wsHttpBinding>
</bindings>
<behaviors>
  <serviceBehaviors>
    <behavior>
       <!--To avoid disclosing metadata information, set the values below to false before deployment--> 
      <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
       <!--To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information--> 
      <serviceDebug includeExceptionDetailInFaults="false"/>
    </behavior>
    <behavior name="externalServiceBehavior">
      <serviceAuthorization principalPermissionMode="UseAspNetRoles" />
      <serviceCredentials>
        <userNameAuthentication userNamePasswordValidationMode="MembershipProvider" />
        <serviceCertificate findValue="RPKey" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My"/>
      </serviceCredentials>
    </behavior>
  </serviceBehaviors>
</behaviors>
<protocolMapping>
    <add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>    
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />

我想要做的很简单,我不知道我是否需要所有这些标签我只是在尝试。 我想要做的是从客户端添加服务的参考,并首先调用MyLogin

    AuthService.Service1Client s = new AuthService.Service1Client();
    s.Login();

然后调用另一个受限制的方法,让它为GetData

s.GetData()  

Login方法的服务方面,仅用于测试目的,我这样做:

public void Login()
{
    Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity("Bob"), new[] { "Admin" });
    FormsAuthentication.SetAuthCookie("BobUserName", false);
}

受限制的方法是:

[PrincipalPermission(SecurityAction.Demand, Role = "Admin")]
public void GetData()
{
    return "Hello";
}

我在服务和客户方面都有,我缺少什么? 每次在调试中,我都会在Thread.CurrentPrincipal方法中检查Login我发现Thread.CurrentPrincipal.Identity.IsAuthenticated等于true,但即使客户端调用GetData()方法,它也会#39} ; Access Denied PS:我使用控制台应用程序进行测试是否有任何区别? 感谢

2 个答案:

答案 0 :(得分:2)

这是一个可能导致解决方案的very nice article
一般的想法是你有两个Principal对象。 HttpContext.Current.UserThread.CurrentPrincipal。您在Thread.CurrentPrincipal已经实例化时设置HttpContext.Current.User,并将其角色保留为默认值。
你可能想尝试类似的东西:

HttpContext.Current.User = new GenericPrincipal(new GenericIdentity("Bob"), new[] { "Admin" });

答案 1 :(得分:0)

拒绝调用GetData()的原因是因为WCF对Login()期间设置的表单身份验证cookie一无所知。

使用控制台应用程序并没有什么不同。您可以尝试以下方法。

Login()中设置Cookie:

var cookie = FormsAuthentication.GetAuthCookie(username, true);
var ticket = FormsAuthentication.Decrypt(cookie.Value);

HttpContext.Current.User = new GenericPrincipal(new FormsIdentity(ticket), null);
FormsAuthentication.SetAuthCookie(HttpContext.Current.User.Identity.Name, true);

然后在您的控制台应用中:

public static void TestLoginAndGetData()
{
    var sharedCookie = string.Empty;

    using (var client = new YourClient())
    using (new OperationContextScope(client.InnerChannel))
    {
        client.Login("username", "password");

        // get the cookie from the response
        HttpResponseMessageProperty response = (HttpResponseMessageProperty)
            OperationContext.Current.IncomingMessageProperties[
            HttpResponseMessageProperty.Name];
        sharedCookie = response.Headers["Set-Cookie"];

        // add it to the request
        HttpRequestMessageProperty request = new HttpRequestMessageProperty();
        request.Headers["Cookie"] = sharedCookie;
        OperationContext.Current.OutgoingMessageProperties[
            HttpRequestMessageProperty.Name] = request;

        var result = client.GetData();

        Console.WriteLine(result);
    }
}

您也可以考虑将GetData()的返回类型更改为string