2

我编写了一个自定义的 PrincipalPermissionAttribute,它使用 AuthenticationService 而不是 Thread.CurrentPrincipal,就像 PrincipalPermissionAttribute 一样。

它按我喜欢的方式工作,但是如果用户注销并重新登录,或者如果用户的角色发生变化,则永远不会再次调用属性代码。我怀疑我没有通知它需要重新检查权限的属性?CreatePermission 方法上设置的断点只命中一次。

属性代码是否只评估一次?该属性当前正在为单击我的视图代码隐藏的按钮装饰一个事件处理程序。

如果我将方法改回使用 PrincipalPermissionAttribute,那么它会按我预期的那样工作,作为没有正确角色的用户注销并重新登录会引发我期望的 SecurityException。我是否错过了覆盖属性?

[Serializable]
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
public sealed class RolePermissionAttribute : CodeAccessSecurityAttribute
{
    private readonly PrincipalPermission _revoke = new PrincipalPermission(PermissionState.None);
    private readonly PrincipalPermission _allow = new PrincipalPermission(PermissionState.Unrestricted);
    private IList<string> _roles;

    private readonly IAuthenticationService _authorisationService;

    public RolePermissionAttribute(SecurityAction action)
        : this(action, ServiceLocator.Current.GetInstance<IAuthenticationService>())
    {
    }

    public RolePermissionAttribute(SecurityAction action, IAuthenticationService authorisationService)
        : base(action)
    {
        _authorisationService = authorisationService;
    }

    public string Roles { get; set; }

    public bool Authenticated { get; set; }

    public override IPermission CreatePermission()
    {
        _roles = (this.Roles ?? string.Empty).Split(',', ';')
                                .Select(s => s.Trim())
                                .Where(s => s.Length > 0)
                                .Distinct()
                                .ToList();

        bool result = false;

        if (_authorisationService != null)
        {
            var principal = _authorisationService.ClientSecurityPrincipal;
            if (principal == null)
            {
                throw new SecurityException("Access Denied. You are not logged in");
            }

            // If Authenticated is enforced then revoke if user is not authenticated
            if (Authenticated && !_authorisationService.IsAuthenticated)
            {
                throw new SecurityException("Access Denied. You are not authenticated");
            }

            // Allow if the principal is in any of the roles
            result = _roles.Any(principal.IsInRole);
            if (!result)
            {
                throw new SecurityException("Access Denied. You are not in an allowed Role");
            }
        }

        return result ? _allow : _revoke;
    }
}

}

这是具有属性的方法

[RolePermission(SecurityAction.Demand, Authenticated = true, Roles = "Admin")]
private void barButtonItemConfig_ItemClick(object sender, ItemClickEventArgs e)
{
   // Do stuff
}
4

1 回答 1

1

好的,我已经弄清楚它是如何工作的。CreatePermission 实际上只调用一次。返回的 IPermission 是检查用户是否处于所需角色的类。

因为我正在为用户 A 返回一个不受限制的允许,所以用户 B 无论其角色如何都获得了相同的访问权限。

我需要创建自己的实现 IPermission 的类并将我的逻辑移动到 Demand 方法中。或者(更简单的选项)将我的服务中的 Principal 分配给 Thread.CurrentPrincipal 并使用开箱即用的 PrincipalPermissionAttribute。

于 2013-03-05T02:34:25.373 回答