예제 #1
0
 private void LogMessage(CachingEntityAccessControlCheckerResult result)
 {
     // Force an indent by using two message contexts
     using (MessageContext outermessageContext = new MessageContext(EntityAccessControlService.MessageName))
     {
         outermessageContext.Append(() => string.Format("Cache '{0}' results:", CacheName));
         using (MessageContext innerMessageContext = new MessageContext(EntityAccessControlService.MessageName))
         {
             if (result.CacheResult.Count > 0)
             {
                 innerMessageContext.Append(() => string.Format(
                                                "Allowed: {0}",
                                                string.Join(", ",
                                                            result.CacheResult.Where(kvp => kvp.Value)
                                                            .Select(kvp => kvp.Key))));
                 innerMessageContext.Append(() => string.Format(
                                                "Denied: {0}",
                                                string.Join(", ",
                                                            result.CacheResult.Where(kvp => !kvp.Value)
                                                            .Select(kvp => kvp.Key))));
             }
             else
             {
                 innerMessageContext.Append(() => "No results found in the cache.");
             }
         }
     }
 }
예제 #2
0
        /// <summary>
        /// Re-used cache checking logic that can be used for caching eithe instances lookups or type lookups.
        /// </summary>
        /// <param name="entities">The entities/types to check. This cannot be null or contain null.</param>
        /// <param name="permissions">The permissions or operations to check. This cannot be null or contain null.</param>
        /// <param name="user">The user requesting access. This cannot be null.</param>
        /// <param name="entityIdCallback">Callback used to determine how to get the ID of TEntity.</param>
        /// <param name="innerCheckAccessCallback">Callback used to perform the uncached check.</param>
        /// <returns>A mapping of each entity ID to whether the user has access (true) or not (false).</returns>
        private IDictionary <long, bool> CachedCheckImpl <TEntity>(IList <TEntity> entities, IList <EntityRef> permissions, EntityRef user,
                                                                   Func <TEntity, long> entityIdCallback,
                                                                   Func <IList <TEntity>, IList <EntityRef>, EntityRef, IDictionary <long, bool> > innerCheckAccessCallback)
        {
            TKey cacheKey;
            CachingEntityAccessControlCheckerResult result;
            IList <TEntity> toCheckEntities;

            long[] permissionIdArray;
            IDictionary <long, bool> innerResult;

            // If SecurityBypassContext is active, avoid the cache. Otherwise,
            // the cache will remember the user had access to entities that
            // they may not have.
            if (EntityAccessControlChecker.SkipCheck(user))
            {
                innerResult = innerCheckAccessCallback(entities, permissions, user);
                return(innerResult);
            }

            result            = new CachingEntityAccessControlCheckerResult();
            toCheckEntities   = null;
            permissionIdArray = permissions.Select(x => x.Id).ToArray();


            // Determine uncached entities
            using (CacheContext cacheContext = CacheContext.IsSet( ) ? CacheContext.GetContext( ) : null)
            {
                foreach (TEntity entity in entities)
                {
                    long entityId = entityIdCallback(entity);

                    cacheKey = CreateKey(user.Id, entityId, permissionIdArray);
                    bool cacheEntry;

                    if (Cache.TryGetValue(cacheKey, out cacheEntry))
                    {
                        result.CacheResult[entityId] = cacheEntry;

                        // Add the already stored changes that should invalidate this cache
                        // entry to any outer or containing cache contexts.
                        if (cacheContext != null)
                        {
                            cacheContext.AddInvalidationsFor(_cacheInvalidator, cacheKey);
                        }
                    }
                    else
                    {
                        if (toCheckEntities == null)
                        {
                            toCheckEntities = new List <TEntity>();
                        }
                        toCheckEntities.Add(entity);
                    }
                }
            }

            LogMessage(result);

            if (toCheckEntities != null)
            {
                using (CacheContext cacheContext = new CacheContext( ))
                {
                    innerResult = innerCheckAccessCallback(toCheckEntities, permissions, user);

                    foreach (KeyValuePair <long, bool> entry in innerResult)
                    {
                        long entityId      = entry.Key;
                        bool accessGranted = entry.Value;

                        result.Add(entityId, accessGranted);

                        // Cache the results
                        cacheKey         = CreateKey(user.Id, entry.Key, permissionIdArray);
                        Cache [cacheKey] = accessGranted;

                        // Add the cache context entries to the appropriate CacheInvalidator
                        _cacheInvalidator.AddInvalidations(cacheContext, cacheKey);
                    }
                }
            }

            // Add the results from the originally cached entities
            foreach (KeyValuePair <long, bool> entry in result.CacheResult)
            {
                result[entry.Key] = entry.Value;
            }

            return(result);
        }