我在IIS中托管了一个使用Windows身份验证并公开WCF Web服务的网站。
我使用端点行为配置此服务:
<serviceAuthorization principalPermissionMode ="UseAspNetRoles"
roleProviderName="MyRoleProvider"/>
和绑定:
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm" />
</security>
调用服务时,Thread.CurrentPrincipal
设置为RolePrincipal
,其中包含客户端的Windows身份和角色,由配置的提供商提供。
一切都与世隔绝。
现在我添加了REST-ful Ajax调用所使用的一些其他WCF服务:svc文件中的Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory"
,服务合同中的WebGet
属性以及AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)
关于服务实现的属性。
我还按照MSDN中的建议将以下咒语添加到web.config中:
<system.serviceModel>
...
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
...
</system.serviceModel>
我的Ajax服务几乎以我想要的方式工作。当它被调用时,HttpContext.Current.User
被设置为具有我期望的角色的RolePrincipal
。但Thread.CurrentPrincipal
仍设置为未经身份验证的GenericPrincipal
。
所以我需要为每个服务方法添加一行代码:
Thread.CurrentPrincipal = HttpContext.Current.User
我可以使用配置文件中的任何咒语来自动设置Thread.CurrentPrincipal
,就像普通的SOAP服务一样吗?
更新 Here's来自有同样问题的人的博客,并通过实施自定义行为解决了这个问题。当然有办法开箱即用吗?
更新2 回来为此添加一个赏金,因为它在一个新项目中再次使我烦恼,在.NET 3.5上使用支持WCF WebGet的服务。
我已经尝试了很多选项,包括设置principalPermissionMode =“None”,但没有任何效果。这是发生的事情:
我导航到调用我的服务的WebGet网址:http://myserver/MyService.svc/...
我在Global.asax“Application_AuthorizeRequest”中放了一个断点。当命中此断点时,“HttpContext.Current.User”和“Thread.CurrentPrincipal”都已设置为使用我配置的ASP.NET RoleProvider的“RolePrincipal”。这是我想要的行为。
当调用我的服务的OperationContract方法时,我有第二个断点。当遇到此断点时,HttpContext.Current.User仍然引用我的RolePrincipal,但Thread.CurrentPrincipal已更改为GenericPrincipal。 Aaargh。
我已经看到implement a custom IAuthorizationPolicy的建议,如果我找不到更好的解决方案,我会调查一下,但为什么我需要实现自定义策略来利用现有的ASP.NET授权功能?如果我有principalPermissionMode =“UseAspNetRoles”,肯定WCF应该知道我想要什么?
答案 0 :(得分:6)
这是一个有趣的问题。我没有与您相同的设置,因此很难测试我的建议是否完全适用于您的用例,但我可以与类似项目分享对我们有用的内容。
Thread.CurrentPrincipal
和HttpContext.Current.User
保持在同步我们编写了一个名为“AuthenticationModule”的HttpModule,它继承自IHtppModule
。
然后我们附加到请求生命周期中很早发生的HttpApplication.AuthenticateRequest
事件。
在我们的AuthenticateRequest事件处理程序中,我们实现了特定于应用程序的要求,包括设置Thread.CurrentPrincipal
,如果需要,还设置当前上下文用户。这样,您只需为整个应用程序实现一次此代码,如果它发生更改(如果您实现了自定义Principal IIDentity),则只有一个地方可以更改它。 (不要在每个服务方法中复制此代码。)
public class AuthenticationModule : IHttpModule
{
public void Dispose() { return; }
public void Init(HttpApplication app)
{
app.AuthenticateRequest += new EventHandler(app_AuthenticateRequest);
}
void app_AuthenticateRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
// This is what you were asking for, but hey you
// could change this behavior easily.
Thread.CurrentPrincipal = app.Context.User;
}
}
我们实施自定义IIdentity
时实际上有点复杂,创建GenericPrincipal
的实例,然后将其分配给app.Context.User
和Thread.CurrentPrincipal
;但是,以上就是你所要求的。
不要忘记在web.config
中注册新的HttpModule!
对于集成的应用程序池:
<system.webServer>
<modules>
<add name="AuthenticationModule" type="YourNameSpace.AuthenticationModule" preCondition="integratedMode" />
</modules>
</system.webServer>
对于旧的经典应用程序池,您必须将其放在<system.web><httpModules></httpModules></system.web>
您可能需要使用AuthenticationRequest事件处理程序内部的内容和/或注册处理程序的顺序。因为我们的完全是定制的,它可能与您需要的不同。我们实际上抓取了Forms Authentication cookie,解密它等等......你可能需要ping一些内置的WindowsAuthentication方法。
我认为这是处理应用程序身份验证内容的一种更通用的方式,因为它适用于所有HttpRequests
,无论是页面请求,IHttpHandler
,某些第三方组件等等......这将使整个应用程序保持一致。
答案 1 :(得分:1)
我不确定。也许这会有所帮助
<configuration>
<system.web>
<identity impersonate="true" />
</system.web>
</configuration>
http://msdn.microsoft.com/en-us/library/134ec8tc(v=vs.80).aspx