我需要通过一系列单独的授权规则来保护我的业务对象属性。我希望在转换为DTO和执行验证规则(验证当前用户无权查看的属性值)等各种操作期间挂起我的授权规则。
我正在研究的方法将调用包装在一个scope对象中,该对象使用ThreadStatic属性来确定是否应该运行授权规则:
public class SuspendedAuthorizationScope : IDisposable
{
[ThreadStatic]
public static bool AuthorizationRulesAreSuspended;
public SuspendedAuthorizationScope()
{
AuthorizationRulesAreSuspended = true;
}
public void Dispose()
{
AuthorizationRulesAreSuspended = false;
}
}下面是IsAuthorized检查(来自基类):
public bool IsAuthorized(string memberName, AuthorizedAction authorizationAction)
{
if (SuspendedAuthorizationScope.AuthorizationRulesAreSuspended)
return true;
var context = new RulesContext();
_rules.OfType<IAuthorizationRule>()
.Where(r => r.PropertyName == memberName)
.Where(r => r.AuthorizedAction == authorizationAction)
.ToList().ForEach(r => r.Execute(context));
return context.HasNoErrors();
}下面是演示用法的ValidateProperty方法(来自基类):
private void ValidateProperty(string propertyName, IEnumerable<IValidationRule> rules)
{
using (new SuspendedAuthorizationScope())
{
var context = new RulesContext();
rules.ToList().ForEach(rule => rule.Execute(context));
if (HasNoErrors(context))
RemoveErrorsForProperty(propertyName);
else
AddErrorsForProperty(propertyName, context.Results);
}
NotifyErrorsChanged(propertyName);
}我有一些关于作用域对象的测试,这些测试表明,只要在using语句的作用域中解析到SuspendedAuthorizationScope.AuthorizationRulesAreSuspended,就会使用预期/正确的值。
这个设计有什么明显的缺陷吗?就线程而言,ASP.NET中有什么是我应该关注的吗?
发布于 2014-03-16 10:49:50
我认为您提出的方法有两个问题:
SuspendedAuthorizationScope时未使用using将导致保留超出预期范围的开放访问。换句话说,一个容易出错的错误会导致安全漏洞(特别是当一个新员工开始挖掘未知代码并错过这个微妙的case).ThreadStatic的这个神奇标志现在放大了前一个项目,因为它有可能保留对另一个页面的开放访问,因为线程将在当前页面完成后用于处理另一个请求,而它的授权标志以前没有被重置。因此,现在授权范围的持续时间超过了其应有的范围,不仅会错过对.Dispose()的调用,而且实际上可能会泄露给另一个请求/页面和完全不同的用户。也就是说,我看到的解决这个问题的方法实际上涉及到检查授权和标记允许绕过的魔术标志,然后重新设置它。
建议: 1.为了至少解决最糟糕的变体(上面的#2),你是否可以将magic cookie移动到你的基页类的一个成员,并让它成为一个只对该页面的作用域有效而不是对其他实例有效的实例字段? 2.为了解决所有的情况,是否可以使用函数器或类似的方法传递给授权函数,一旦授权成功,它将启动运行所有逻辑的函数器,然后保证清理?请参考下面的伪代码示例:
void myBizLogicFunction()
{
DoActionThatRequiresAuthorization1();
DoActionThatRequiresAuthorization2();
DoActionThatRequiresAuthorization3();
}
void AuthorizeAndRun(string memberName, AuthorizedAction authorizationAction, Func privilegedFunction)
{
if (IsAuthorized(memberName, authorizationAction))
{
try
{
AuthorizationRulesAreSuspended = true;
privilegedFunction();
}
finally
{
AuthorizationRulesAreSuspended = true;
}
}
}有了上面的内容,我认为它可以是线程静态的,因为finally是保证运行的,因此授权不会泄漏到privilegedFunction调用之外。我认为这将会起作用,尽管可以使用验证和其他人的验证。
发布于 2014-03-16 11:37:04
如果你完全控制了你的代码,并且不关心隐藏的依赖关系,那么你的方法是可行的。请注意,你给你/任何支持你的代码的人带来了很大的负担,以确保在你的using块中永远不会有异步处理,并且每次使用魔术值都用适当的using block包装。
一般来说,这不是一个好主意,因为:
存储与请求相关的信息应该在HttpContext.Items或Session中完成(此外,会话将持续更长时间,需要更仔细地管理清理状态)。
发布于 2014-03-16 10:51:42
我担心的是离开using块的时间和垃圾收集器处理对象所花费的时间之间的潜在延迟。您可能处于虚假的“已授权”状态的时间比您预期的时间更长。
https://stackoverflow.com/questions/22432253
复制相似问题