WCF数据契约授权

发布于 2024-10-18 02:36:07 字数 177 浏览 2 评论 0原文

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

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

how to use [PrincipalPermission(SecurityAction.Demand, Role = "Administrators")] attribute on a class?

I am looking for some way to restrict the access on my object
i.e
if some object is being accessed in a service method and if the user has rights for accessing the service method but does not have rights accessing the object an exception should be thrown

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

转身以后 2024-10-25 02:36:07

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

  1. 配置选定的服务和客户端绑定以使用安全性。指定 Windows 作为客户端凭据类型。
  2. 配置服务以使用 Windows 组进行授权。
  3. 将包含带有 PrincipalPermission 属性的机密信息的装饰类。

如果需要将单例实例传递给 ServiceHost 构造函数,请执行以下操作:

  1. 创建服务单例实例。 Thread.CurrentPrincipal 必须具有访问机密对象所需的权限。
  2. 通过传递服务单例实例来创建 ServiceHost 实例。 ServiceBehavior 属性的 InstanceContextMode 必须设置为 InstanceContextMode.Single

否则:

  1. 通过传递服务类型创建 ServiceHost 实例。

(可选)使用 FaultContract 属性修饰服务方法并从中抛出 FaultException 以避免客户端通道出现故障。

下面是一个示例:

服务配置文件

<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>

机密信息类

[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 );
        }
    }
}

PrincipalPermission attribute can adorn method or class. Therefore it is possible to restrict access to an instance of an object. Several things need to be done:

  1. Configure selected service and client binding to use security. Specify Windows as client credential type.
  2. Configure service to use Windows groups for authorization.
  3. Adorn class that will contain confidential information with PrincipalPermission attribute.

If singleton instance needs to be passed to ServiceHost constructor, do following:

  1. Create service singleton instance. Thread.CurrentPrincipal must have permissions necessary to access the confidential object.
  2. Create ServiceHost instance by passing service singleton instance. Property InstanceContextMode of ServiceBehavior attribute must be set to InstanceContextMode.Single.

Otherwise:

  1. Create ServiceHost instance by passing the service type.

Optionally, adorn the service method with FaultContract attribute and throw FaultException from it in order to avoid faulting the client channel.

Here is an example:

Service configuration file:

<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>

Client configuration file:

<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>

Confidential information class:

[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 );
    }
}

Service contract and its implementation:

[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 );
        }
    }
}
哆兒滾 2024-10-25 02:36:07

如果您熟悉 .NET 权限编码(命令式或声明式),则该模式完全相同。在声明性形式中,PrincipalPermissionAttribute 应用于实现服务契约的类中的方法:

[PrincipalPermission(SecurityAction.Demand, Role = "Updaters")]
public bool Update()
{
return true;
}

在此示例中,将检查当前主体以查看它是否属于名为 Updaters 的角色。在属性的实际实现中,调用主体上的 IsInRole 方法。

为了命令式确定PrincipalPermissionAttribute,将创建PrincipalPermission 类的实例。 PrimaryPermission 的构造函数将用户名和角色作为参数。实例化后,可以调用 Demand 方法来确定当前主体是否具有必要的权限。以下代码提供了一个示例:

PrincipalPermission p = new PrincipalPermission(null, "Updaters");
p.Demand();

配置应如下所示:

<behaviors>
  <serviceBehaviors>
    <behavior>
      ...
      <serviceAuthorization principalPermissionMode="UseWindowsGroups" />
    </behavior>
  </serviceBehaviors>
</behaviors>

有关工作示例,请查看:授权访问服务操作

If you are familiar with .NET permission coding (either imperative or declarative), the pattern is exactly the same. In the declarative form, the PrincipalPermissionAttribute is applied to the method in the class that implements the service’s contract:

[PrincipalPermission(SecurityAction.Demand, Role = "Updaters")]
public bool Update()
{
return true;
}

In this example, the current principal is checked to see whether it belongs to a role called Updaters. In the actual implementation of the attribute, the IsInRole method on the principal is called.

For imperative determination of the PrincipalPermissionAttribute, an instance of the PrincipalPermission class is created. The constructor for PrincipalPermission takes the username and role as a parameter. When instantiated, the Demand method can be called to determine whether the current principal has the necessary permissions. The following code provides an example:

PrincipalPermission p = new PrincipalPermission(null, "Updaters");
p.Demand();

the configuration should look like this:

<behaviors>
  <serviceBehaviors>
    <behavior>
      ...
      <serviceAuthorization principalPermissionMode="UseWindowsGroups" />
    </behavior>
  </serviceBehaviors>
</behaviors>

for a working sample please look at: Authorizing Access to Service Operations

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文