Silverlight 4 MVVM: сквозная защита с использованием шаблона декоратора

#silverlight #security #mvvm #permissions #decorator

#silverlight #Безопасность #mvvm #разрешения #декоратор

Вопрос:

мы разработали приложение для внутренней сети с Silverlight 4, используя MVVM с PRISM. До сих пор у нас была только базовая схема безопасности, которая сводилась к «доступ предоставлен» или «доступ запрещен» на основе членства в группе active Directory. Теперь мы должны подробнее остановиться на этом.

Мы определили более детализированные роли и разрешения, которые загружаются при запуске приложения и которые предоставляются одноэлементным экземпляром ISecurityContext. Этот контекст безопасности знает о ролях и разрешениях, предоставленных текущему пользователю, вошедшему в систему. Теперь я хотел бы элегантным способом включить этот контекст в мои модели просмотра. Наивный пример того, что я хотел бы сделать, это:

 public class NavigationBarViewModel
{
    //...

    [Secured(RequiredPermission="EditLocation")]
    public void NavigateToEditLocations(IRegionManager rManager)
    {
        var editLocView = new Uri("EditLocationsView", UriKind.Relative);
        rManager.RequestNavigate("WorkspaceRegion", editLocView);

    }

    //...
}
  

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

Ответ №1:

Итак, после некоторых исследований я думаю, что нашел чистый способ сквозной безопасности с использованием перехвата Unity. Я поделюсь своим кодом:

 public class MyCallHandler: ICallHandler
{

    private readonly string[] roles;

    public MyCallHandler(params string[] roles)
    {
        this.roles = roles;
    }

    public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
        IPrincipal principal = Thread.CurrentPrincipal;
        bool allowed = roles.Any(principal.IsInRole);
        if (!allowed)
            return input.CreateExceptionMethodReturn(new
                                         Exception("Security exception!"));
        return getNext()(input, getNext);

    }

    public int Order
    {
        get;
        set;
    }
}

public class MethodAccessAttribute : HandlerAttribute
{
    private readonly string[] roles;

    public MethodAccessAttribute(params string[] roles)
    {
        this.roles = roles;
    }

    public override ICallHandler CreateHandler(IUnityContainer container)
    {
        return new MyCallHandler(roles);
    }
}

public interface IConsoleThingie
{
    [MethodAccess("admin")]
    void SomeMethod();
}

public class MyConsoleThing : IConsoleThingie
{
    public void SomeMethod()
    {
        Console.WriteLine("test");
    }
}

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();
        container.AddNewExtension<Interception>();
        container.RegisterType<IConsoleThingie, MyConsoleThing>().Configure<Interception>().SetInterceptorFor<IConsoleThingie>(new InterfaceInterceptor());

        IConsoleThingie thing = container.Resolve<IConsoleThingie>();
        try
        {
            thing.SomeMethod();
        }
        catch
        {
            Console.WriteLine("More granular exception handling here");
            Console.ReadLine();
        }

    }

}
  

Как вы можете видеть, все дело в создании пользовательского атрибута HandlerAttribute, который, в свою очередь, вызывает пользовательский ICallHandler. В обработчике вызовов вы можете поместить свою логику, связанную с безопасностью, которая будет решать, будет ли выполняться оформленный метод. Вам следует создать несколько пользовательских исключений, которые вы можете перехватить из слоя, используя свои методы. Благодаря такой инфраструктуре вы можете легко интегрировать любые сквозные модули. Вот конфигурация для приложения, поскольку это может быть немного затруднительно в Unity. Не забудьте добавить Microsoft.Практика.Единство.Кстати, пространство имен InterceptionExtension в ваших классах.

 <configuration>
 <configSections>
<section name="unity"
    type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
            Microsoft.Practices.Unity.Configuration" />
 </configSections>
  <unity>
   <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration"/>
<containers>

  <container>
    <extension type="Interception" />
    <register type="IConsoleThingie" mapTo="MyConsoleThing">
      <interceptor type="InterfaceInterceptor" />
      <policyInjection />
    </register>

    <types>
    </types>

  </container>
</containers>
 </unity>
  </configuration>
  

Комментарии:

1. Я должен добавить, что обычно вы не стали бы украшать методы viewmodel этими атрибутами перехватчика, поскольку viewmodels не должны разрешаться контейнером DI, это должны делать сервисы.