简体   繁体   中英

Smart caching for custom AuthorizeAttribute in ASP.NET

in my app I'd like to add functionality for admins to go to the specific screen and make certain controllers/methods available for certain roles. Right now I'm using a build-in role check like

[Authorize(Roles = "APUL_Admin")]

So I changed that to be [AuthorizeExtended()] and I'm implementing it like that:

public class AuthorizeExtended : AuthorizeAttribute
    {
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            var isAuthorized = base.AuthorizeCore(httpContext);
            if (!isAuthorized)
            {
                return false;
            }
            // Point of interest **HERE**

            return true;
        }
    }

which is all pretty standard.

At this moment ( HERE see above) from HttpContextBase I know user's roles, and controller and method. And I can go to the DB and make sure those roles has access to this controller/action.

Here is my problem: I don't want to go to the database for every request since it is slow and it is a lot of overhead for DB. What's the best way to deal with that? Cache it? I'm looking for implementation details.

Any help is appreciated. Thank you!

Yes, the cache is what you need to avoid duplicated requests to the DB. Here is the basic implementation:

internal class CacheKey
{
    public string Role { get; set; }

    public string Controller { get; set; }

    public string Method { get; set; }

    public override bool Equals(Object obj)
    {
        CacheKey cmp = obj as CacheKey;
        if (cmp == null)
        {
            return false;
        }

        return Role == cmp.Role && Controller == cmp.Controller && Method == cmp.Method;
    }

    public override int GetHashCode()
    {
        // Overflow is fine, just wrap
        unchecked
        {
            int hash = 17;
            hash = hash * 23 + Role.GetHashCode();
            hash = hash * 23 + Controller.GetHashCode();
            hash = hash * 23 + Method.GetHashCode();
            return hash;
        }
    }
}

public class AuthorizeExtended : AuthorizeAttribute
{
    private static ConcurrentDictionary<CacheKey, bool> cache = new ConcurrentDictionary<CacheKey, bool>();

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var isAuthorized = base.AuthorizeCore(httpContext);
        if (!isAuthorized)
        {
            return false;
        }
        // Point of interest **HERE**

        //  Looking up in the cache
        var cacheKey = new CacheKey
        {
            Role = role,
            Controller = controller,
            Method = method,
        };

        bool authorized;
        if (cache.TryGetValue(cacheKey, out authorized))
        {
            return authorized;
        }

        //  Make DB call and get value for authorized
        //  ...

        //  Store 'authorized' value in the cache
        cache.TryAdd(cacheKey, authorized);

        return authorized;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM