Я реализовал решение, которое использует Rhino.Security для управления пользователями / ролями / разрешениями.
Поскольку я хочу проверить, авторизован ли пользователь для доступа к действию контроллера, я реализовал фильтр пользовательских действий:
public class AuthorizationAttribute : ActionFilterAttribute
{
CustomPrincipal currentPrincipal = (CustomPrincipal)filterContext.HttpContext.User;
var actionName = filterContext.ActionDescriptor.ActionName;
var controllerName = filterContext.Controller.GetType().Name;
var operation = string.Format("/{0}/{1}", controllerName, actionName);
if (!securityService.CheckAuthorizationOnOperation(currentPrincipal.Code, operation))
{
filterContext.Controller.TempData["ErrorMessage"] = string.Format("You are not authorized to perform operation: {0}", operation);
filterContext.Result = new HttpUnauthorizedResult();
}
}
CheckAuthorizationOnOperation вызывает Rhino.Security, чтобы проверить, разрешен ли пользователь для указанной операции:
AuthorizationService.IsAllowed(user, operation);
Все работает правильно, но я заметил, что кэш второго уровня никогда не срабатывает при выполнении запроса, вызванного IsAllowed .
Я исследовал и видел, что фреймворк ( Rhino.Security ) использует DetachedCriteria . Это 2 процедуры, которые называются:
public Permission[] GetGlobalPermissionsFor(IUser user, string operationName)
{
string[] operationNames = Strings.GetHierarchicalOperationNames(operationName);
DetachedCriteria criteria = DetachedCriteria.For<Permission>()
.Add(Expression.Eq("User", user)
|| Subqueries.PropertyIn("UsersGroup.Id",
SecurityCriterions.AllGroups(user).SetProjection(Projections.Id())))
.Add(Expression.IsNull("EntitiesGroup"))
.Add(Expression.IsNull("EntitySecurityKey"))
.CreateAlias("Operation", "op")
.Add(Expression.In("op.Name", operationNames));
return FindResults(criteria);
}
private Permission[] FindResults(DetachedCriteria criteria)
{
ICollection<Permission> permissions = criteria.GetExecutableCriteria(session)
.AddOrder(Order.Desc("Level"))
.AddOrder(Order.Asc("Allow"))
.SetCacheable(true)
.List<Permission>();
return permissions.ToArray();
}
Как вы видите FindResults использует SetCacheable .
Каждый раз, когда я обновляю страницу, мой фильтр действий выполняет процедуры, и запрос выполняется снова, игнорируя кэш (второй уровень).
Поскольку я интенсивно использую кеш и все остальные вызовы работают должным образом, я хотел бы понять, почему этот вызов не работает должным образом.
Проводя некоторые исследования, я заметил, что кэш второго уровня используется, только если я вызываю функцию дважды:
SecurityService.CheckAuthorizationOnOperation(currentPrincipal.Code, "/Users/Edit");
SecurityService.CheckAuthorizationOnOperation(currentPrincipal.Code, "/Users/Edit");
Кажется, что кеш для этой конкретной ситуации работает, только если я использую тот же сеанс (nHibernate).
Есть ли кто-нибудь, кто может помочь мне выяснить, что происходит?
UPDATE: