2013-07-24 3 views
5

Имея информацию о пользователе на сеансе, насколько возможно проверить сеанс и разрешить доступ к методу, украшенному настраиваемым атрибутом, на основе одного из предоставленных значений.Проверка доступа пользователей с помощью настраиваемых атрибутов

Так что я пытаюсь сделать, это:

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" по проверке значения сеанса. Кроме того, можно ли это сделать проверку в реализации пользовательского атрибута?

ответ

17

Так что другие ребята правы, что атрибуты ничего не делают сами по себе. Это всего лишь метаданные, которые вы должны намеренно получить в какой-то момент в течение срока службы вызова службы.

Лучший способ сделать это, чтобы сделать это автоматически, а не всегда непосредственно в каждой операции - добавлять инспекторов и поведение службы. Вначале больше работать над настройкой, но он получает это из вашего прямого кода операции и может заставить его применить любую операцию для проверки этого настраиваемого атрибута.

В основном у вас есть атрибут как так:

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

Затем вы создаете y наше поведение раздела:

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

Для получения дополнительной информации см MSDN http://msdn.microsoft.com/en-us/library/ms730137.aspx

также для инспекторов: http://cgeers.com/2008/11/09/wcf-extensibility-parameter-inspectors/

+0

Вау .. Очень много кода .. Спасибо – user1791567

+1

Благословит вас Бог за такой всеобъемлющий ответ. – Jeremy

0

Нет, вы не можете этого сделать (не сам по себе), атрибуты - это не что иное, как метаданные, скомпилированные в ваш код, сами по себе они ничего не делают. После того, как вы украшаете метод или класс с некоторыми метаданными атрибутов, вы можете использовать отражение, как GetCustomAttributes(typeof(UserAccess)), для получения метаданных и действовать на него, это SO answer иллюстрирует это довольно хорошо

Что вы можете сделать, это, создать специальный метод который будет использовать отражение для извлечения метаданных и выполнить оценку для вас, а затем внутри public Response Get(Request r), прежде чем вы сделаете все, что вы можете вызвать этот метод, но это не совсем такая автоматическая оценка, которую вы задаете

+0

согласен .. Я думаю, что лучше получить объект из сессии и оценить его ... – user1791567

1

Атрибуты простые метаданные, такие как флаги, описание, Дополнительная информация. Вам нужно обработать эту информацию самостоятельно. Вы можете сделать это в самом методе или иметь некоторый вспомогательный класс для его обработки с помощью отражения.

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

* Я также предлагаю суффикс слова Атрибут к классу UserAccess как конвенции. например, UserAccessAttribute

+0

Это стоит рассмотреть .. спасибо – user1791567

Смежные вопросы