如何在类上使用 [PrincipalPermission(SecurityAction.Demand, Role = "Administrators")] 属性?

我正在寻找某种方法来限制对我的对象的访问
IE
如果在服务方法中正在访问某个对象,并且用户有权访问该服务方法但没有访问该对象的权限,则应抛出异常

最佳答案

PrincipalPermission 属性可以修饰方法或类。因此,可以限制对对象实例的访问。需要做几件事:

  • 配置选定的服务和客户端绑定(bind)以使用安全性。将 Windows 指定为客户端凭据类型。
  • 配置服务以使用 Windows 组进行授权。
  • Adorn 类将包含具有 PrincipalPermission 属性的 secret 信息。

  • 如果需要将单例实例传递给 ServiceHost 构造函数,请执行以下操作:
  • 创建服务单例实例。 Thread.CurrentPrincipal 必须具有访问 secret 对象所需的权限。
  • 通过传递服务单例实例来创建 ServiceHost 实例。 InstanceContextMode 属性的属性 ServiceBehavior 必须设置为 InstanceContextMode.Single

  • 除此以外:
  • 通过传递服务类型创建 ServiceHost 实例。

  • 可选地,使用 FaultContract 属性装饰服务方法并从中抛出 FaultException 以避免客户端 channel 出错。

    下面是一个例子:

    服务配置文件 :
    <system.serviceModel>
        <services>
            <service name="Server.Service" behaviorConfiguration="Authorization">
                <endpoint address=""
                          binding="netTcpBinding" bindingConfiguration="TCP"
                          contract="Common.IService" />
                <host>
                    <baseAddresses>
                        <add baseAddress="net.tcp://localhost:13031/Service"/>
                    </baseAddresses>
                </host>
            </service>
        </services>
        <bindings>
            <netTcpBinding>
                <binding name="TCP" openTimeout="00:30:00" closeTimeout="00:00:10" maxReceivedMessageSize="2147483647">
                    <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
                    <security mode="Message">
                        <message clientCredentialType="Windows" />
                    </security>
                </binding>
            </netTcpBinding>
        </bindings>
        <behaviors>
            <serviceBehaviors>
                <behavior name="Authorization">
                    <serviceAuthorization principalPermissionMode="UseWindowsGroups" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
    </system.serviceModel>
    

    客户端配置文件 :
    <system.serviceModel>
        <client>
            <endpoint name="NetTcpBinding_IService"
                      address="net.tcp://localhost:13031/Service"
                      binding="netTcpBinding" bindingConfiguration="TCP"
                      contract="Common.IService" />
        </client>
        <bindings>
            <netTcpBinding>
                <binding name="TCP" openTimeout="00:30:00" closeTimeout="00:00:10" sendTimeout="00:30:00" receiveTimeout="00:30:00" maxReceivedMessageSize="2147483647">
                    <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
                    <security mode="Message">
                        <message clientCredentialType="Windows" />
                    </security>
                </binding>
            </netTcpBinding>
        </bindings>
    </system.serviceModel>
    

    secret 信息类 :
    [PrincipalPermission(SecurityAction.Demand, Role = "Administrators" ) ]
    public class ContactInfo
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public ContactInfo()
        {
            FirstName = "John";
            LastName = "Doe";
        }
        public override string ToString()
        {
            return string.Format( "{0} {1}", FirstName, LastName );
        }
    }
    

    服务合约及其实现 :
    [ServiceContract]
    public interface IService
    {
        [OperationContract]
        [FaultContract( typeof( string ) )]
        string GetName( int id );
    }
    
    [ServiceBehavior]
    // Use following if singleton instance needs to be passed to `ServiceHost` constructor
    //[ServiceBehavior( InstanceContextMode = InstanceContextMode.Single )]
    public class Service : IService
    {
        private Dictionary<int, ContactInfo> Contacts { get; set; }
        public Service()
        {
            Contacts = new Dictionary<int, ContactInfo>();
            IPrincipal originalPrincipal = Thread.CurrentPrincipal;
            try
            {
                Thread.CurrentPrincipal = new WindowsPrincipal( WindowsIdentity.GetCurrent() );
                Contacts.Add( 1, new ContactInfo() );
            }
            finally
            {
                Thread.CurrentPrincipal = originalPrincipal;
            }
        }
        public string GetName( int id )
        {
            if ( Contacts.Count < id )
                return null;
            try
            {
                return Contacts[ id ].ToString();
            }
            catch ( Exception ex )
            {
                throw new FaultException<string>( ex.Message );
            }
        }
    }
    

    关于wcf 数据契约(Contract)授权,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/5051095/

    10-13 06:53