PrincipalPermission on Method не работает, если применяется к классу

Wayne спросил: 12 мая 2018 в 05:17 в: c#

У меня есть код, который выглядит примерно так:

[PrincipalPermission(SecurityAction.Demand, Role = "RoleA")]
class Foo
{
    [PrincipalPermission(SecurityAction.Demand, Role = "RoleB")]
    public static bool Bar()
    {
        return true;
    }
}

Если я попытаюсь запустить Foo.Bar();, он не сработает, если у меня нет RoleA, но никогда не проверяет RoleB. Он работает независимо от того, есть ли у меня RoleB, если у меня есть RoleA.

Если я удалю [PrincipalPermission(SecurityAction.Demand, Role = "RoleA")] из определения класса, тогда он проверяет RoleB как ожидалось.

Я обыскал и нашел эту точную проблему, упомянутую в двух разных SO-вопросах ( здесь и здесь ) с нет ответа в любом случае. У одного есть комментарий, который указывает на старую ссылку Microsoft Connect, которая якобы содержит ответ, но нет комментариев или ответов, которые действительно говорят, в чем проблема.

Я действительно очень благодарен за любую помощь в этом .

1 ответ

Есть решение
Joe ответил: 12 мая 2018 в 06:18

Несколько запросов PrincipalPermissionAttribute Объединяются с использованием OR, поэтому в вашем случае:

  • RoleA может построить экземпляр класса и вызвать любой метод.
  • RoleB может вызывать метод Bar, но не может вызвать конструктор.

Из-за этого ваш код эквивалентен:

[PrincipalPermission(SecurityAction.Demand, Role = "RoleA")]
class Foo
{
    [PrincipalPermission(SecurityAction.Demand, Role = "RoleA")]
    public Foo()
    {
    }    [PrincipalPermission(SecurityAction.Demand, Role = "RoleA")]
    [PrincipalPermission(SecurityAction.Demand, Role = "RoleB")]
    public static bool Bar()
    {
        return true;
    }
}

Если вы хотите Комбинация Задачи с использованием AND, вы должны указать Role = как список, разделенный запятыми, например"RoleA, RoleB". Или используйте SecurityAction.Deny соответствующим образом.

Пример ниже иллюстрирует это:

class Program
{
    static void Main(string[] args)
    {
        var aPrincipal = new GenericPrincipal(new GenericIdentity("AUser", ""), new[] {"RoleA"});
        var bPrincipal = new GenericPrincipal(new GenericIdentity("BUser", ""), new[] { "RoleB" });
        var abPrincipal = new GenericPrincipal(new GenericIdentity("ABUser", ""), new[] { "RoleB", "RoleA" });        // AB can do anything
        Thread.CurrentPrincipal = abPrincipal;
        var sc = new SecureClass();
        TryConstruct();
        TryBMethod(sc);
        TryABMethod(sc);        // What can A do?
        Thread.CurrentPrincipal = aPrincipal;
        TryConstruct();
        TryBMethod(sc);
        TryABMethod(sc);        // What can B do?
        Thread.CurrentPrincipal = bPrincipal;
        TryConstruct();
        TryBMethod(sc);
        TryABMethod(sc);        Console.WriteLine("Press ENTER to exit");
        Console.ReadLine();
    }    static void TryConstruct()
    {
        try
        {
            var sc = new SecureClass();
        }
        catch(SecurityException)
        {
            Console.WriteLine("Constructor SecurityException for " + Thread.CurrentPrincipal.Identity.Name);
        }
    }
    static void TryBMethod(SecureClass sc)
    {
        try
        {
            sc.RoleBMethod();
        }
        catch (SecurityException)
        {
            Console.WriteLine("RoleBMethod SecurityException for " + Thread.CurrentPrincipal.Identity.Name);
        }
    }
    static void TryABMethod(SecureClass sc)
    {
        try
        {
            sc.RoleABMethod();
        }
        catch (SecurityException)
        {
            Console.WriteLine("RoleABMethod SecurityException for " + Thread.CurrentPrincipal.Identity.Name);
        }
    }}[PrincipalPermission(SecurityAction.Demand, Role ="RoleA")]
class SecureClass
{
    public SecureClass()
    {
        Console.WriteLine("In constructor using " + Thread.CurrentPrincipal.Identity.Name);
    }    [PrincipalPermission(SecurityAction.Demand, Role = "RoleB")]
    public void RoleBMethod()
    {
        Console.WriteLine("In RoleBMethod using " + Thread.CurrentPrincipal.Identity.Name);
    }    [PrincipalPermission(SecurityAction.Demand, Role = "RoleA,RoleB")]
    public void RoleABMethod()
    {
        Console.WriteLine("In RoleBMethod using " + Thread.CurrentPrincipal.Identity.Name);
    }}
Wayne ответил: 13 мая 2018 в 11:36
Я проходил через исходный источник для PrincipalPermissionAttribute, но не мог найти, где он ORs. Мне интересно, если, используя пользовательский атрибут, я могу переопределить что-то где-то, чтобы заставить И.
Joe ответил: 13 мая 2018 в 01:03
@Wayne, атрибут сам по себе ничего не делает, поэтому вы не найдете ничего в исходном источнике PrincipalPermissionAttribute. В основном CAS в CLR должен, по-видимому, оценивать все активные PrincipalPermissionAttribute 'перед выполнением метода и делать свои вещи. Я лично не буду пытаться настраивать атрибут; почему бы просто не использовать роли, разделенные запятыми?
Wayne ответил: 13 мая 2018 в 05:13
Я закончил решение своей проблемы с пользовательской версией PrincipalPermissionAttribute и PrincipalPermission и принудительным требованием к разрешению метода независимо от того, есть ли у него класс. Спасибо, что направили мой мозг в правильном направлении.