通过浏览器实现 WCF REST 服务的 Windows 身份验证

5

所提供的是一个使用HttpClientCredentialType.Windows运行,并强制用户通过Kerberos进行身份验证的WCF REST服务。

        private static void Main(string[] args)
    {
        Type serviceType = typeof (AuthService);
        ServiceHost serviceHost = new ServiceHost(serviceType);

        WebHttpBinding binding = new WebHttpBinding();
        binding.Security.Mode = WebHttpSecurityMode.TransportCredentialOnly;
        binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;

        ServiceEndpoint basicServiceEndPoint = serviceHost.AddServiceEndpoint(typeof(IAuthService), binding,  "http://notebook50:87");
        basicServiceEndPoint.Behaviors.Add(new WebHttpBehavior());

        Console.WriteLine("wcf service started");
        serviceHost.Open();
        Console.ReadLine();
    }

    public class AuthService : IAuthService
{
    public List<string> GetUserInformation()
    {
        List<string> userInfo = new List<string>();
        userInfo.Add("Environment.User = " + Environment.UserName);
        userInfo.Add("Environment.UserDomain = " + Environment.UserDomainName);
        if (OperationContext.Current != null && OperationContext.Current.ServiceSecurityContext != null)
        {
            userInfo.Add("WindowsIdentity = " + OperationContext.Current.ServiceSecurityContext.WindowsIdentity.Name);
            userInfo.Add("Auth protocol = " + OperationContext.Current.ServiceSecurityContext.WindowsIdentity.AuthenticationType);
        }
        else
        {
            userInfo.Add("WindowsIdentity = empty");
        }
        WebOperationContext.Current.OutgoingResponse.ContentType = "text/plain";
        return userInfo;
    }
}

[ServiceContract]
public interface IAuthService
{
    [OperationContract]
    [WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, UriTemplate = "test/")]
    List<string> GetUserInformation();
}

当我将此作为控制台应用程序运行,并从另一台计算机的Internet Explorer中打开http://notebook50:87/test/网站时,会收到“坏请求”的响应。 我确实启用了kerberos日志记录,并显示了KDC_ERR_PREAUTH_REQUIRED。
我可以通过创建一个Windows服务并在“Local System”帐户下运行它来解决这个问题。 在这种情况下,客户端能够进行身份验证。
问题:一个用户(运行此wcf服务的用户)需要什么权限/设置才能获得与应用程序在本地系统下作为Windows服务运行时相同的行为? 这是否与服务原则名称有关?

如果您在notebook50上创建了一个共享文件夹,并尝试从另一台计算机访问它,会发生什么?它会提示登录吗?如果您使用登录表单登录,然后尝试访问http://notebook50:87/test/,那么会起作用吗? - Magic-Mouse
这可能与服务主体名称有关。我的第一个问题是,为什么要使用Kerberos?我曾经花费了两周时间来调试Kerberos,但最终毫无结果(您确定不能使用NTLM吗?)。其次,Kerberos需要正确配置许多内容才能正常工作,其中之一就是客户端需要对服务器进行身份验证...这就是SPN的作用。SPN必须与您用于访问服务器的DNS条目匹配(在本例中为notebook50,几乎肯定不匹配,因为默认情况下,如果发生这种情况,它将设置为服务器的FQDN)。 - Aron
1
@Magic-Mouse 抱歉伙计,你的评论没有帮助。这显然是Kerberos认证的问题。 - Aron
你的应用程序正在运行哪个应用程序池? - Peter Kiss
没有应用程序池参与。它是一个独立的 Windows 服务,运行 WCF REST 服务。 - Manuel
关于为什么要使用Kerberos:我们的一个客户有多个域森林,并通过信任连接它们,我被告知在这种情况下使用Kerberos比NTLM更容易。 - Manuel
2个回答

3
现在它正在工作。 它确实是SPN的问题。 一开始,我像这样设置了SPN:setpn -A HTTP/notebook50.foo.com,但是这样做,Kerberos身份验证就无法正常工作。
现在,我已经将其设置为setspn -A HTTP/notebook50.foo.com用户名,其中用户名是服务运行的用户。
从我阅读的SPN文档中,我不清楚我必须以这种方式设置用户帐户。
如果有人能解释一下这里发生了什么,并可能提供此场景的文档链接,那就太棒了。

0
您可以通过在Active Directory用户和计算机中的用户帐户的属性->帐户中启用“不要求Kerberos预身份验证”选项来停止此错误弹出。

我已经为运行Windows服务的用户帐户启用了此属性,但仍然无法正常工作。现在系统日志中的错误是:KRB_AP_ERR_MODIFIED。但只要我将用户切换到“本地系统”,一切就正常了。 - Manuel
根据 MSDN 规范,KRB_AP_ERR_MODIFIED 可能会在以下情况下发生:
  1. DNS 名称解析不匹配 - 在使用多个 IP 或/和多个网络适配器的 NLB 环境中,此问题非常常见。
  2. 用户没有本地 NTFS 访问权限。
  3. Web 站点正在使用权限设置不佳的应用程序池。
- Frix33

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接