通过WCF查找登录网站的某人的身份

时间:2013-05-26 18:57:58

标签: c# asp.net wcf

我有一个运行ASP.Net会员数据库的网站,它运行正常。我还运行了一个WCF服务,它应该作为在网站上实现的应用程序的API(在我的案例中是游戏)。现在我的问题是我希望我的应用程序能够通过我的数据库解决方案调用WCF并返回当前登录到网站的用户,而且我找不到在我的生活中这样做的方法。我尝试过使用:

OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name;

但是当它被登录在网站上的会话调用时,它似乎没有值(null)。我希望我的WCF能够根据在运行应用程序时登录的人来更新诸如高分等的内容,据我所知,如果我无法获取登录的人的身份,这是不可能的。这就是我试图测试它的方法:

protected void Page_Load(object sender, EventArgs e)
{
    APIHostClient client = new APIHostClient();
    client.Open();
    String name = client.GetUserName();
    Label.Text = name;
    client.Close();
}

// on the wcf side 
public String GetUserName()
    {
        String userName = OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name;
        return userName;
    }

的web.config:

  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IAPIHost" >
          <security mode ="TransportWithMessageCredential">
            <transport clientCredentialType="None"/>
            <message clientCredentialType="UserName"/>
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="https://localhost:2105/APIHost.svc" binding="basicHttpBinding"
        bindingConfiguration="BasicHttpBinding_IAPIHost" contract="ServiceReference1.IAPIHost"
        name="BasicHttpBinding_IAPIHost" />
    </client>
    <services>
      <service behaviorConfiguration="behavior" name="ICanHasGamez.APIHost">
        <endpoint address="" binding="basicHttpBinding" contract="ICanHasGamez.IAPIHost">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>

    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="behavior">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
          <serviceCredentials>
            <serviceCertificate findValue="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName"/>
            <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WcfService.SecurityValidator, WcfService"/>
          </serviceCredentials>
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
      multipleSiteBindingsEnabled="true" />
  </system.serviceModel>

我似乎在该主题上找到的所有信息都与您提供凭据的用户的标准身份验证有关,而我的问题是找到登录到我网站的用户的凭据。

编辑:

我从错误的角度看问题。这就是我目前正在尝试解决的问题:当用户访问持有应用程序的页面时,我正在生成SessionId,该应用程序包含有关应用程序ID,访问页面的用户ID以及会话的到期日期的信息(当前日期+时间)。您可以直接将信息直接转发到您托管的.swf文件(即:http://helpx.adobe.com/flash/kb/pass-variables-swfs-flashvars.html),因此我将用户的sessionId传递给应用程序,然后应用程序开发人员可以使用该文件访问该用户的名称。数据库通过将sessionId传递给SQL查询,该查询返回熟悉的用户ID(也可以使其返回名称,但ID在我的情况下更有用)。如果我使这个解决方案有效,我会更新答案。

3 个答案:

答案 0 :(得分:1)

如果要从浏览器调用您的Web服务(如在jQuery AJAX调用中),那么您只需要与ASP.Net应用程序并排托管WCF服务并启用WCF服务中的ASP.Net兼容模式。在article in the msdn

中对此进行了描述

通过添加

,我可以看到你已经在web.config中启用了asp.net兼容模式
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" 
     multipleSiteBindingsEnabled="true" />

到web.config的元素<service.serviceModel>

您还应该将[AspNetCompatibilityRequirements]属性设置为服务实现,如下所示:

namespace ICanHasGamez
{
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    public class APIHost: IAPIHost
    {
        ...

允许访问HttpContext.Current,以便您现在可以获取用户名,如下所示:

public String GetUserName()
{
    return HttpContext.Current.User.Identity.Name;
}

但是,如果要从.Net Web应用程序的服务器端代码调用WCF服务,则还需要一种方法在调用时在客户端浏览器中模拟登录用户服务。 Wiktor的回答提供了一种方法,通过将ASP.Net Web应用程序中收到的身份验证cookie发送到WCF服务。

答案 1 :(得分:1)

这不会那样容易。

您尝试执行的操作是尝试从服务器调用WCF。这意味着服务器必须以某种方式IMPERSONATE请求,以将调用者的身份传递给被调用的WCF请求。

至少有几种方法可以做到。

最简单的方法是将身份验证cookie从请求(可通过Request.Cookies访问)复制到wcf客户端。我在博客上写了如何做到这一点

http://netpl.blogspot.com/2011/11/managing-cookies-in-wcf-client.html

这样做的好处是可以在网站和wcf(即Forms身份验证)中重复使用相同的身份验证方案,因此您的wcf对内部和外部请求都是安全的。

编辑:由于你遇到问题,这是怎么做的:

APIHostClient client = new APIHostClient();
client.SetCookie( FormsAuthentication.FormsCookieName, this.Reuqest.Cookies[FormsAuthentication.FormsCookieName].Value );
client.Open();

(假设SetCokie在WCF方面实施,如博客条目中所述)

答案 2 :(得分:0)

我的编辑解决方案已经解决了。将sessionId作为FlashVars传递给flashfile,flash程序可以访问唯一的sessionId字符串。从这里可以很容易地通过SQL查询访问各种信息。我必须在脚本中编写保存flash对象的asp.net代码才能操作参数,因为相同的.aspx页面将用于保存不同用户连接的不同应用程序(查询字符串)。

hfSessionId =隐藏字段,已在后面的代码中设置为SessionId的值。

      <script lang="javascript">

            function writeObjectTag() {

                var sessionId = document.getElementById('<%=hfSessionId.ClientID%>').value;

                document.writeln('<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="550" height="400" id="myFlashGame" align="middle">');
                document.writeln('<param name="movie" value="sessionIdDisplayer.swf" />');
                document.writeln(buildParamTag(sessionId));
                document.writeln('<object type="application/x-shockwave-flash" data="sessionIdDisplayer.swf" width="550" height="400">');
                document.writeln('<param name="movie" value="sessionIdDisplayer.swf" />');
                document.writeln(buildParamTag(sessionId));
                document.writeln('<a href="http://www.adobe.com/go/getflash">');
                document.writeln('<img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash player" />');
                document.writeln('</a>');
                document.writeln('</object>');
                document.writeln('</object>');
            }

            function buildParamTag(value) {
                return '<param name="FlashVars" value="' + value + '" />';
            }

      </script>