使用自定义属性检查用户访问权限

本文关键字:访问 访问权 权限 用户 检查 自定义属性 | 更新日期: 2023-09-27 18:24:41

如果会话中有用户信息,如何检查会话并允许访问根据提供的值之一使用自定义属性装饰的方法。

所以我想做的是:

public class UserAccess: System.Attribute
{
    private string userRole;   
    public UserAccess(string userRole)
    {
        this.userRole = userRole;
    }
}

然后当我像这样装饰一个端点时:

[UserAccess(userRole = "Residents")]
public Response Get(Request r){
    ///-- Implementation
}

不知何故,当调用端点时,只有userRole = "Residents"才能根据会话值检查来实际执行它。此外,这种验证可以在自定义属性实现中完成吗?

使用自定义属性检查用户访问权限

所以其他人是对的,属性本身什么都不做。它只是在服务调用生命周期中的某个时刻您必须有意获取的元数据。

要做到这一点,最好的方法是添加检查员和服务行为,这样它就可以神奇地自动完成,而不是总是直接在每个操作中完成。初始设置需要更多的工作,但它从直接操作代码中获得了这一点,并可以使其应用于任何检查自定义属性的操作。

基本上你有这样的属性:

namespace MyCustomExtensionService
{
    public class UserAccessAttribute : System.Attribute
    {
        private string _userRole;
        public UserAccessAttribute(string userRole)
        {
            _userRole = userRole;
            
            //you could also put your role validation code in here
            
        }
        public string GetUserRole()
        {
            return _userRole;
        }
    }
}

然后你设置你的参数检查器(注意还有其他检查器你可以使用):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Web;
namespace MyCustomExtensionService
{
    public class MyParameterInspector : IParameterInspector
    {
        public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
        {
            //throw new NotImplementedException();
        }
        public object BeforeCall(string operationName, object[] inputs)
        {
            MethodInfo method = typeof(Service1).GetMethod(operationName);
            Attribute[] attributes = Attribute.GetCustomAttributes(method, typeof(UserAccessAttribute), true);
            var attr = (UserAccessAttribute)attributes.First();
            if (attributes.Any())
            {
                var userHasProperAuthorization = true;
                if (attr.GetUserRole() == "Residents" && userHasProperAuthorization)
                {
                    //everything is good, continue to operation
                }
                else
                {
                    throw new FaultException("You do not have the right security role!");
                }
            }
            
            return null;
        }
    }
}

然后设置端点行为(还有其他可以使用的行为):

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Web;
namespace MyCustomExtensionService
{
    public class MyCustomAttributeBehavior : IEndpointBehavior
    {
        public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
            //throw new NotImplementedException();
        }
        public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
        {
            foreach (ClientOperation clientOperation in clientRuntime.Operations)
            {
                clientOperation.ParameterInspectors.Add(
                    new MyParameterInspector());
            }
        }
        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
        {
            foreach (DispatchOperation dispatchOperation in endpointDispatcher.DispatchRuntime.Operations)
            {
                dispatchOperation.ParameterInspectors.Add(
                    new MyParameterInspector());
            }
        }
        public void Validate(ServiceEndpoint endpoint)
        {
            //throw new NotImplementedException();
        }
    }
}

然后你创建你的行为部分:

using System.Linq;
using System.ServiceModel.Configuration;
using System.Web;
namespace MyCustomExtensionService
{
    public class MyBehaviorSection : BehaviorExtensionElement
    {
        protected override object CreateBehavior()
        {
            return new MyCustomAttributeBehavior();
        }
        public override Type BehaviorType
        {
            get { return typeof(MyCustomAttributeBehavior); }

        }
    }
}

然后设置配置以使用新行为:

<system.serviceModel>
    <services>
      <service name ="MyCustomExtensionService.Service1">
        <endpoint address="" behaviorConfiguration="MyCustomAttributeBehavior"
          binding="basicHttpBinding" contract="MyCustomExtensionService.IService1">
        </endpoint>
      </service>
    </services>
    <extensions>
      <behaviorExtensions>
        <add name="Validator" type="MyCustomExtensionService.MyBehaviorSection, MyCustomExtensionService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      </behaviorExtensions>
    </extensions>
    <behaviors>
      <endpointBehaviors>
        <behavior name="MyCustomAttributeBehavior">
          <Validator />
        </behavior>
      </endpointBehaviors>

这是服务接口,其中一个操作可以工作,另一个操作由于用户访问错误而失败

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace MyCustomExtensionService
{
    
    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        string GetData(int value);
        [OperationContract]
        string GetDataUsingWrongUserAccess(int value);
    }

   
}

以及服务操作:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace MyCustomExtensionService
{
   
    public class Service1 : IService1
    {
        [UserAccess("Residents")]
        public string GetData(int value)
        {
            return string.Format("You entered: {0}", value);
        }
        [UserAccess("Admin")]
        public string GetDataUsingWrongUserAccess(int value)
        {
            return string.Format("You entered: {0}", value);
        }
    }
}

有关更多信息,请参阅MSDNhttp://msdn.microsoft.com/en-us/library/ms730137.aspx

也适用于检查员:https://github.com/geersch/WcfParameterInspectors

属性只是元数据,如标志、描述、附加信息。你需要自己处理这些信息。您可以在方法本身中执行此操作,或者让一些辅助类通过使用反射来处理它。

    // Using reflection.
    MethodInfo method = typeof(ClassName).GetMethod("Get");
    Attribute[] attributes = Attribute.GetCustomAttributes(method, typeof(UserAccess), true);

    // Displaying output. 
    foreach (var attr in attributes)
    {
        if (attr is UserAccess)
        {
            var ua = (UserAccess)attr;
            System.Console.WriteLine("{0}",a.userRole);
        }
    }

*我还建议将单词Attribute作为惯例后缀到UserAccess类中。例如,UserAccessAttribute

不,你不能这样做(不是靠它本身),属性只不过是编译到代码中的元数据,它们本身什么都不做。一旦你用一些属性元数据装饰了一个方法或类,你就可以使用反射,比如GetCustomAttributes(typeof(UserAccess)),来检索元数据并对其采取行动,这个SO的答案很好地说明了

您可以做的是,创建一个自定义方法,该方法将使用反射来检索元数据并为您进行评估,然后在public Response Get(Request r)中,在执行任何操作之前,您可以调用该方法,但这并不完全是您要求进行的自动魔术评估