0

我有一个运行 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;
    }

网络配置:

  <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 传递给返回熟悉的用户 ID 的 SQL 查询(可以使它也返回名称,但 ID 在我的情况)。如果我使此解决方案起作用,我将更新答案。

4

3 回答 3

1

如果要从浏览器调用您的 Web 服务(如在 jQuery AJAX 调用中),那么您只需将 WCF 服务与 ASP.Net 应用程序并排托管,并在 WCF 服务中启用 ASP.Net 兼容模式. 在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 服务。

于 2013-05-26T19:37:03.393 回答
1

这不会像这样轻松地工作。

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

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

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

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

这具有在网站和 wcf(即表单身份验证)中重用相同身份验证方案的优势,因此您的 wcf 对于内部和外部请求都是安全的。

编辑:因为你有问题,这是怎么做的:

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

(假设SetCokie如博客条目中所述在 WCF 端实现)

于 2013-05-26T19:45:28.510 回答
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>
于 2013-05-28T22:00:47.140 回答