PrincipalPermission на метод не работает, если применяется к классу
У меня есть код, который выглядит примерно так:
[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 ответ
Множественные требования PrincipalPermissionAttribute объединяются с использованием ИЛИ, поэтому в вашем случае:
- 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);
}
}