代码改变世界

WCF 第八章 安全 确定替代身份(上)

2011-01-23 22:33  DanielWise  阅读(720)  评论(0编辑  收藏  举报

生成的WCF代理支持一个确定调用服务的替代身份架构。这对很多场景都很有用。例如,如果一个客户端应用支持多个用户身份,这些身份可以通过客户端代理在运行时应用,所以服务可以确定当前用户应该执行哪个动作。

  使用Samples.SamplesClient 代理,我们为我们之前创建的"peter"帐户提供用户名和密码,就像在列表8.21中显示的那样。

列表8.21 通过客户端生成的代理提供替代凭据

        static void Main(string[] args)
        {
            Console.WriteLine("Press ENTER to make service calls.");
            //Console.ReadLine();
            SamplesClient client = new SamplesClient("netTcp");
            client.ClientCredentials.Windows.ClientCredential = new NetworkCredential("localhost\\jessica", "p@ssw0rd");
            try
            {
                Console.WriteLine(client.GetPublicCode());
                Console.WriteLine(client.GetMemberCode());
                Console.WriteLine(client.GetSecretCode());
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception = " + ex.Message);
            }

            Console.ReadLine();
        }

  现在运行应用程序结果会在所有的服务中调用成功,但是DisplaySecurityDetails控制台方法显示宿主身份(WindowsInentity.GetCurrent().Name)仍然是系统用户,其他的显示的身份是MACHINENAME\peter.WCF已经自动将我们在客户端提供的凭据映射到安全上下文和线程身份中。

提示 非Windows用户名和密码

也可能提供对Windows来说并不特别的基本用户名和密码。特定的绑定,比如WsHttpBinding,支持这个选项(看表8.1中显示的绑定选项)。为了使能这个,使用clientCredentialType="UserName".

在这些情况中,然而,WCF将要求传输安全(例如,一个证书)来在线上确保保密性和那些证书的安全。证书已经在这一章的之前部分描述过。

使用Windows证书授权用户

我们已经显示我们可以通过Windows证书确定用户;现在让我们关注在同样的场景下如何确定访问权限(授权)。首先,我们加你个使用标准的PrincipalPermissionAttribute安全属性。这个属性可以用来修饰成员并限制或者允许对调用者访问。

  现在,让我们使用属性来修饰方法来限制其只能被Peter(GetSecretCode)以及同时被Peter和Jessica(GetMemberCode)访问。添加下面的GetSecretCode(MACHINENAME应该使用你自己系统的名字代替):

        [PrincipalPermission(SecurityAction.Demand, Name="peter")]

现在向GetMemberCode中添加下面内容:

        [PrincipalPermission(SecurityAction.Demand, Name = "peter")]
        [PrincipalPermission(SecurityAction.Demand, Name = "jessica")]

运行服务和客户端应用程序,确保Peter仍然在代理的ClientCredentials属性中确定。结果应该是所有的三个服务操作被成功调用。现在在客户端代码中将"peter"改为"jessica",如果必须的话更细密码。这一次运行客户端时GetSecretCode方法会抛出一个访问被拒绝异常。

  当然,这种方法可以工作,并能为具体服务帐户提供身份验证和授权机制已知的Windows帐户。然而,对几乎所有的生产系统,你将需要一个更早的方式来为一系列用户配置并维护访问列表。

  PrincipalPermissionAttribute也支持一个允许我们确定一个特殊的Windows组而不是一个命名用户的角色参数。在继续操作之前,使用计算机管理控制台来创建临时的Sample Admins和Sample Members 本地Windows 组,添加Peter 到前者,添加Peter和Jessica到后者。现在,像列表8.22显示的那样修改属性。

列表8.22 通过安全角色确定访问权限

    public class Samples : ISamples
    {
        [PrincipalPermission(SecurityAction.Demand, Role="Sample Admins")]
        public string GetSecretCode()
        {
            DisplaySecurityDetails();
            return "The Secret Code";
        }
        [PrincipalPermission(SecurityAction.Demand, Role = "Sample Admins")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Sample Members")]
        public string GetMemberCode()
        {
            DisplaySecurityDetails();
            return "The Member-Only Code";
        }

        public string GetPublicCode()
        {
            DisplaySecurityDetails();
            return "The Public Code";
        }

        private static void DisplaySecurityDetails()
        {
            Console.WriteLine("Windows Identity = " + WindowsIdentity.GetCurrent().Name);
            Console.WriteLine("Thread CurrentPrincipal Identity = " + Thread.CurrentPrincipal.Identity.Name);
            Console.WriteLine("ServiceSecurityContext Primary Identity = " + ServiceSecurityContext.Current.PrimaryIdentity.Name);
            Console.WriteLine("ServiceSecurityContext Windows Identity = " + ServiceSecurityContext.Current.WindowsIdentity.Name);
        }
    }

  再次运行客户端应该产生类似结果,但是现在你可以依赖Windows组中的成员关系来确定哪个用户被授权来调用WCF操作。

注意 使用本机Windows组

为了使用PrincipalPermissionAttribute来将标准Windows组作为角色,在组名前前置BUILTIN作为一个机器名。例如,管理员组被引用为@"BUILTIN\Administrators"用户组引用为@"BUILTIN\Users".也要注意在C#中,你将需要@符号来对反斜杠转义,或者你需要使用两个双斜杠来避免编译错误。