角色提供程序是否每个请求都缓存?

9

我的MVC应用程序在单个页面请求期间多次使用用户的角色。我的问题是默认的SqlRoleProvider是否会缓存当前用户在页面请求的生命周期内的角色?

例如,我在控制器方法的属性中使用角色:

[Authorize(Roles = "Admin")]

和自定义代码

if (user.IsInRole(MembershipRole.Admin))
{
     // Do something
}
else if (user.IsInRole(MembershipRole.Printer))
{
     // Do something else
}

如果Role Provider不缓存角色,最好的解决方案是编写一个自定义的Role Provider,继承默认的Role Provider,并重写方法以获取角色并将其缓存到请求持续时间。这样做能否使Authorize属性和您自己的代码都使用缓存的角色?(注:我不想使用cacheRolesInCookie web.config选项将角色缓存在cookie中。)
感谢您提供任何建议。
(如有疑问,我不想使用cacheRolesInCookie web.config选项将角色缓存在cookie中。)
在Joe的答案中,我反编译了System.Web.Mvc.AuthorizeAttribute并发现AuthorizeCore方法调用以下方法来检查每个角色:
httpContext.User.IsInRole

然后查看System.Web.Security.RolePrincipal(上面的“User”就是这个)两种方法确实都使用了用户角色的缓存副本(如果缓存为空,则填充缓存):

public string[] GetRoles()
public bool IsInRole(string role)

缓存是作为用户字段存储的,因此它的生命周期与请求持续时间一样长。

这些方法使用以下方式查找角色:

Roles.Providers[this._ProviderName].GetRolesForUser(this.Identity.Name)

所以将使用您选择的应用程序角色提供程序(默认或自定义)。

1个回答

7
如果您在ASP.NET或ASP.NET MVC应用程序中使用RoleProvider,那么HttpContext.User将引用一个RolePrincipal,该角色会缓存请求的生命周期内的角色信息。
然而,在使用ASP.NET角色的WCF服务中:
<behavior ...>
    <serviceAuthorization principalPermissionMode ="UseAspNetRoles"
                     roleProviderName ="MyRoleProvider" />
</behavior>

这是不正确的:相反,HttpContext.User将引用内部类System.ServiceModel.Security.RoleProviderPrincipal,它不会缓存角色,而总是调用RoleProvider.IsUserInRole。开箱即用的RoleProvider不进行任何缓存,因此这可能导致与底层数据存储的重复连接。我认为这似乎有些不足:在第一次访问时缓存角色很容易。

编写自定义RoleProvider是最好的解决方案吗?从默认RoleProvider继承并覆盖方法以获取角色一次并将其缓存到请求持续时间中?

对于ASP.NET或ASP.NET MVC来说并不是必要的,但可以考虑用于WCF。在请求持续时间中进行缓存可能会使用HttpContext.Items,因此将引入对HttpContext存在的依赖性,但这并不一定是问题,除了使单元测试更加困难之外。

是否有一种既能让Authorize属性又能让我的代码使用缓存角色的方法?

如果在web.config中配置了自定义RoleProvider,则无需执行其他操作,Authorize属性将使用它。

2
感谢您的想法。关于RolePrincipal的MSDN文档指出:“如果CacheRolesInCookie为false,则RolePrincipal对象始终使用角色提供程序查找角色成员资格。”当您说RolePrincipal“在请求的生命周期内缓存角色”时,我可以问一下您是如何知道这一点的(反射、SQL分析、文档等),因为它似乎与MSDN相矛盾? - Appetere
@Steve,我是通过查看实现(Lutz Reflector或ILSpy)以及实现自定义提供程序的经验来了解这一点的。这并不与MSDN相矛盾:RolePrincipal确实使用角色提供程序查找角色成员资格-它调用RoleProvider.GetRolesForUser,但每个请求仅调用一次,并将结果缓存到HybridDictionary字段中。WCF的RoleProviderPrincipal不调用RoleProvider.GetRolesForUser,而是始终调用RoleProvider.IsInRole,并且不实现任何角色缓存。 - Joe
谢谢。我按照你的方法,反编译了相关的程序集,以查看实际发生的情况。我在原来的问题中添加了一些细节,以补充你的答案。 - Appetere

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接