I implemented a solution that includes Rhino.Security for managing users / roles / permissions.
Since I want to check if the user is allowed access to the controllerβs action, I implemented a custom action filter:
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 calls Rhino.Security to check if the user is allowed the specified operation:
AuthorizationService.IsAllowed(user, operation);
Everything works correctly, but I noticed that the second level cache never gets when the request called IsAllowed is executed .
I researched and I saw that the environment ( Rhino.Security ) uses DetachedCriteria . These are two procedures:
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(); }
As you can see, FindResults uses SetCacheable .
Each time I refresh the page, my action filter executes the procedures, and the request is executed again, ignoring the cache (second level). Since I make extensive use of the cache and all other calls work correctly, I would like to understand why this one does not work properly.
After doing some research, I noticed that the second level cache is used only if I call the function twice:
SecurityService.CheckAuthorizationOnOperation(currentPrincipal.Code, "/Users/Edit"); SecurityService.CheckAuthorizationOnOperation(currentPrincipal.Code, "/Users/Edit");
It seems that the cache for this particular situation only works if I use the same session (nHibernate). Is there anyone who can help me figure out what's going on?
UPDATE: 