这是我正在做的事情的基本大纲。
我使用“用户名”来获取 IPrincipal。
我使用 MemoryCache/ObjectCache 来访问数据库,每 60 分钟一次。如果您需要“每次登录”而不是“每个用户”..(如果您的主体定义经常更改或者您需要为可能性编码,只需将缓存键更改为基于用户名和会话的内容。
请注意,我不能忍受在任何不是您孩子的足球俱乐部的应用程序中使用“IsInRole”。(我没有孩子,这是一个比喻)。
namespace MyProduct.MyApplication.WebServices.Controllers
{
/// <summary>
/// Performs operations with "Item" list
/// </summary>
public class MyItemController : BaseApiController
{
[Authorize]
public IEnumerable<Item> Get()
{
string username = User.Identity.Name;
IPrincipalCache cache = new PrincipalCache(); /* use injection - Unity, this hard coding for demo purposes */
MyCustomPrincipal princ = cache.GetMyCustomPrincipal(username);
if ( ! princ.HasRight("USER_CAN_GET_ITEMS")) /* Note my MyCustomPrincipal has this method...out of the "box" you'll have "IsInRole('MyRoleName') */
{
return null;
}
return itemsService.GetItems(); }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Caching;
using System.Web;
using MyProduct.MyApplication.Infrastructure.Security;
namespace MyProduct.MyApplication.WebServices.Security.Caching
{
public interface IPrincipalCache
{
MyCustomPrincipal GetMyCustomPrincipal(string userName);
}
public class PrincipalCache : IPrincipalCache
{
public MyCustomPrincipal GetMyCustomPrincipal(string userName)
{
string cacheKey = "MyCustomPrincipalCacheKey" + userName;
MyCustomPrincipal cachedOrFreshPrincipal = GetFromCache<MyCustomPrincipal>(cacheKey, () =>
{
return new MyCustomPrincipal(); /* Go to the method/datalayer/ and hydrate a MyCustomPrincipal */
});
return cachedOrFreshPrincipal;
}
private TEntity GetFromCache<TEntity>(string key, Func<TEntity> valueFactory) where TEntity : class
{
ObjectCache cache = MemoryCache.Default;
var newValue = new Lazy<TEntity>(valueFactory);
CacheItemPolicy policy = new CacheItemPolicy { AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(60) }; /* Most people will do stuff for less than one hour I guess */
//The line below returns existing item or adds the new value if it doesn't exist
var value = cache.AddOrGetExisting(key, newValue, policy) as Lazy<TEntity>;
return (value ?? newValue).Value; // Lazy<T> handles the locking itself
}
}
}