问题
I have a WCF service method that calls a SQL stored proc. I'm developing using IIS 5 (can't do much about that, II6/7 not available)
To get some gains, I'm doing a number of async calls to this stored proc by putting the call into a c# TPL Task.
When run as a Task, I'm getting an SQL Exception... "Login failed. The login is from an untrusted domain and cannot be used with Windows authentication"
However, If I run the exact same process without using a Task, I have no problems with SQL connection
It would appear to me that the credentials for the IIS Virtual folder (WCF) are not being delegated to the Task? Any ideas how I can specificy credentials for the TPL Task thread, ie to use the same as the parent etc ?
I am using Windows Authentication (sspi), and impersonation to be able to connect to the seperate SQL box.
Your help appreciated.
回答1:
You have two choices.
1) Opt your entire application into always flowing the identity using:
<runtime>
<alwaysFlowImpersonationPolicy enabled="true"/>
</runtime>
This has a side effect of overhead and the danger of accidentally executing some unintended code with the priviledges of the currently calling user rather than the application identity. I would personally avoid this and go with #2 where you explicitly opt-in.
2) Capture the WindowsIdentity before setting up your TPL tasks and explicitly impersonate where you need to make the calls using Impersonate + WindowsImpersonationContext:
public void SomeWCFOperation()
{
WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent();
Task.Factory.StartNew(() =>
{
// some unpriviledged code here
using(WindowsImpersonationContext impersonationContext = currentIdentity.Impersonate())
{
// this code will execute with the priviledges of the caller
}
// some more unpriviledged code here
});
}
回答2:
As another workaround, you can create extensions to the TPL as follows:
public static class TaskFactoryExtensions
{
public static Task StartNewImpersonated(this TaskFactory taskFactory, Action action)
{
var identity = WindowsIdentity.GetCurrent();
return taskFactory.StartNew(() =>
{
using (identity.Impersonate())
{
action();
}
});
}
public static Task<TResult> StartNewImpersonated<TResult>(this TaskFactory taskFactory, Func<TResult> function)
{
var identity = WindowsIdentity.GetCurrent();
return taskFactory.StartNew<TResult>(() =>
{
using (identity.Impersonate())
{
return function();
}
});
}
}
You would then call these new methods in place of the standard StartNew methods.
The downside to this is that there are a lot of methods to override.
来源:https://stackoverflow.com/questions/10007535/tpl-task-in-wcf-service-fails-to-use-correct-iis-security-credentials-sql-conne