2009-01-23 86 views
0

我使用ASP.NET Ajax从ASP.NET页面调用WCF。我正在使用表单身份验证来保护网站。使用ASP.NET Ajax通过SSL调用WCF

一切都如预期一样工作,直到它被部署到生产服务器上,然后我开始收到JavaScript错误,因为找不到服务。生产服务器使用SSL,所以我说下面我的web.config

<webHttpBinding> 
    <binding name="webBinding"> 
    <security mode="Transport" /> 
    </binding> 
</webHttpBinding> 

该停止了JavaScript错误的发生,但现在WCF服务不表现为用它来。

将安全设置为从ASP.NET Ajax传输到WCF服务的调用将执行我的Global.asax中的Application_AuthenticateRequest。这将基于Forms Authentication票据在HttpContext.Current.User上设置自定义IPrinciple。我的WCF服务的构造函数设置为Thread.CurrentPrinciple = HttpContext.Current.User,因此我的服务可以访问在Application_AuthenticateRequest期间设置的IPrinciple

将安全更改为传输后,它似乎不会通过Application_AuthenticateRequest运行,因为我的Thread.CurrentPrinciple不是我的自定义IPrinciple

有谁知道我可以像使用Transport之后使用Transport一样获得相同的行为吗?

我的网页上使用以下引用WCF服务:

<asp:ScriptManagerProxy ID="ScriptManagerProxy1" runat=" 
    <Services> 
     <asp:ServiceReference Path="~/Services/MyService.svc" /> 
    </Services> 
</asp:ScriptManagerProxy> 

代码在我Application_AuthenticateRequest使用:

protected void Application_AuthenticateRequest(object sender, EventArgs e) 
{ 
    String cookieName = FormsAuthentication.FormsCookieName; 
    HttpCookie authCookie = Context.Request.Cookies[cookieName]; 

    if (authCookie == null) 
    { 
     return; 
    } 

    FormsAuthenticationTicket authTicket = null; 
    try 
    { 
     authTicket = FormsAuthentication.Decrypt(authCookie.Value); 
    } 
    catch 
    { 
     return; 
    } 

    if (authTicket == null) 
    { 
     return; 
    } 

    HttpContext.Current.User = new CustomPrinciple(authTicket.Name); 
} 

回答

1

只需从没有改变安全运输应该不会影响应用程序运行Authenticate_Request。您应该将调试器附加到服务实现并查看HttpContext.Current.User是什么。它是您的自定义校长还是未设置?你也可以在那里添加一些Debug.Write消息,看看操作的顺序是什么。 Authenticate_Request事件是否在您期待之后发生?

如果您在配置中使用<serviceAuthorization principalPermissionMode="UseAspNetRoles" />,那么您可能会遇到this issue from MS Connect - 看起来此设置与安全传输不兼容,WCF将覆盖主体。如果你设置了委托人,看来你需要使用principalPermissionMode="None"

确保您仍然通过配置(<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />)或通过服务上的属性([AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)])在服务上启用了ASP.NET Compatibility Mode。没有这一点,该服务将无法访问HttpContext.Current。

此外,不是在服务实现构造函数中获取HttpContext.Current.User,而是尝试将其移至附加到服务的行为。实施处理AfterReceiveRequest事件的IDispatchMessageInspector,并将主体从Web上下文传输到线程。它会是这个样子:

public class HttpContextPrincipalInspector : IDispatchMessageInspector 
{ 
    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) 
    { 
    if (HttpContext.Current != null) 
    { 
     IPrincipal principal = HttpContext.Current.User; 
     Thread.CurrentPrincipal = principal; 
    } 
    return null; 
    } 

    public void BeforeSendReply(ref Message reply, object correlationState) { } 
} 

,当然,实施IEndpointBehavior附加调度...

public class HttpContextPrincipalBehavior : IEndpointBehavior 
{ 
    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) 
    { 
    ChannelDispatcher channelDispatcher = endpointDispatcher.ChannelDispatcher; 
    foreach (EndpointDispatcher endpointDispatch in channelDispatcher.Endpoints) 
    { 
     endpointDispatch.DispatchRuntime.MessageInspectors.Add(new HttpContextPrincipalInspector()); 
    } 
    } 

    // AddBindingParameters, ApplyClientBehavior, and Validate implementations 
    // can be empty - they don't do anything. 
} 

...和一个自定义BehaviorExtensionElement这样你就可以在WCF配置中使用它:

public class HttpContextPrincipalElement : BehaviorExtensionElement 
{ 
    public override Type BehaviorType 
    { 
    get { return typeof(HttpContextPrincipalBehavior); } 
    } 

    protected override object CreateBehavior() 
    { 
    return new HttpContextPrincipalBehavior(); 
    } 
} 

然后,您可以配置您的任何服务,以此为端点的行为,使服务实现ISN不直接与网络上下文交谈。使测试更容易一些,并且可以完全解决问题 - 只要服务发出消息,它就会自动将委托人转移到服务器上,而不是依赖于服务的构建。