Asp.net MVC权限设计思考 (二)逻辑部分实现

在我的项目中,我还是使用的LINQ TO SQL ,因为我的项目不会涉及太多很太复杂的数据库操作业务。当然如果设计,我相信LINQ TO SQL的自定义扩展也能满足需求。

使用Repository模式是最近MVC很多项目采用的解决方案,能把原来我们杂乱的LINQ TO SQL统一封装起来。让我们的架构更清晰。

现在来看看具体实现。

IRepository接口:

代码
interface IRepository<TEntity> where TEntity : class
    {
        IQueryable
<TEntity> FindAll(Expression<Func<TEntity, bool>> exp);
        TEntity Find(Expression
<Func<TEntity, bool>> exp);
        
void Add(TEntity entity);
        
void Delete(TEntity entity);
        
void Save();
    }

 

Repository实现:

代码
 public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        
protected DAL.CourseCenterData db;
        
public Repository()
        {
            db 
= new DAL.CourseCenterData();            
        }


        
/// <summary>
        
/// 查找所有数据
        
/// </summary>
        
/// <returns></returns>
        public IQueryable<TEntity> FindAll()
        {
            
return db.GetTable<TEntity>().Where(p => 1==1);
        }

        
/// <summary>
        
/// 查找所有数据
        
/// </summary>
        
/// <param name="exp">条件表达式</param>
        
/// <returns></returns>
        public IQueryable<TEntity> FindAll(Expression<Func<TEntity, bool>> exp)
        {
            
return db.GetTable<TEntity>().Where(exp);
        }

        
/// <summary>
        
/// 查找一个数据
        
/// </summary>
        
/// <param name="exp">条件表达式</param>
        
/// <returns></returns>
        public TEntity Find(Expression<Func<TEntity, bool>> exp)
        {
            
return db.GetTable<TEntity>().FirstOrDefault(exp);
        }

        
/// <summary>
        
/// 添加数据
        
/// </summary>
        
/// <param name="entity">实体</param>
        public void Add(TEntity entity)
        {
            db.GetTable
<TEntity>().InsertOnSubmit(entity);
        }

        
/// <summary>
        
/// 删除数据
        
/// </summary>
        
/// <param name="entity">实体</param>
        public void Delete(TEntity entity)
        {
            db.GetTable
<TEntity>().DeleteOnSubmit(entity);
        }

        
/// <summary>
        
/// 批量添加数据
        
/// </summary>
        
/// <param name="entity">实体列表</param>
        public void AddAll(IEnumerable<TEntity> entity)
        {
            db.GetTable
<TEntity>().InsertAllOnSubmit(entity);
        }

        
/// <summary>
        
/// 批量删除数据
        
/// </summary>
        
/// <param name="entity">实体列表</param>
        public void DeleteAll(IEnumerable<TEntity> entity)
        {
            db.GetTable
<TEntity>().DeleteAllOnSubmit(entity);
        }

        
/// <summary>
        
/// 对数据做插入,更新,删除操作
        
/// </summary>
        public void Save()
        {
            db.SubmitChanges();
        }

 

网上已经有很多Repository的例子,但是请注意Find中的条件必须是Expression Tree的扩展,否则在数据查询的SQL语句中,你会发现捕获到的将是select一个表之后再来做数据的查询,这在我们海量数据查询时不允许的。

 

现在我们已经有了自己的Repository,下面来建立一个数据库视图把我们上一讲需要的数据拿出来。

 

新建视图ViewRoleGroup,选定一下表和字段

我们通过VS2008新建一个LINQ TO SQL类,拖入这个视图。

然后我们需要思考,这个权限分组视图是系统频繁读取的,需要为他创建一个缓存。

新建一个缓存类Caches:

 

代码
/// <summary>
    
/// 缓存操作基类
    
/// </summary>
    public class Caches
    {
        
/// <summary>
        
/// 建立缓存
        
/// </summary>
        public static object TryAddCache(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, 
            TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback onRemovedCallback)
        {
            
if (HttpRuntime.Cache[key] == null && value != null)
                
return HttpRuntime.Cache.Add(key, value, dependencies, absoluteExpiration, slidingExpiration, priority, onRemovedCallback);
            
else
                
return null;
        }

        
/// <summary>
        
/// 移除缓存
        
/// </summary>
        public static object TryRemoveCache(string key)
        {
            
if (HttpRuntime.Cache[key] != null)
                
return HttpRuntime.Cache.Remove(key);
            
else
                
return null;
        }

        
/// <summary>
        
/// 移除键中带某关键字的缓存
        
/// </summary>
        public static void RemoveMultiCache(string keyInclude)
        {
            IDictionaryEnumerator CacheEnum 
= HttpRuntime.Cache.GetEnumerator();
            
while (CacheEnum.MoveNext())
            {
                
if (CacheEnum.Key.ToString().IndexOf(keyInclude.ToString()) >= 0)
                    HttpRuntime.Cache.Remove(CacheEnum.Key.ToString());
            }
        }

        
/// <summary>
        
/// 移除所有缓存
        
/// </summary>
        public static void RemoveAllCache()
        {
            IDictionaryEnumerator CacheEnum 
= HttpRuntime.Cache.GetEnumerator();
            
while (CacheEnum.MoveNext())
            {
                HttpRuntime.Cache.Remove(CacheEnum.Key.ToString());
            }
        }
   }

 

 

来看看我们的ViewRoleGroupRepository怎么写。

新建类:ViewRoleGroupRepository

 

代码
public class ViewRoleGroupRepository:Repository<Models.Database.ViewRoleGroup>
    {

        
/// <summary>
        
/// 获取权限视图缓存列表,Key:ViewGroupList
        
/// </summary>
        
/// <returns></returns>
        public List<Models.Database.ViewRoleGroup> GetCacheAll()
        {
            List
<Models.Database.ViewRoleGroup> viewRoleGroup;
            
string key = "ViewGroupList";

            
if (HttpRuntime.Cache[key] != null)
                viewRoleGroup 
= (List<Models.Database.ViewRoleGroup>)HttpRuntime.Cache[key];
            
else
            {

                viewRoleGroup 
= FindAll().ToList();
                Caches.TryAddCache(key, viewRoleGroup, 
null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(20), System.Web.Caching.CacheItemPriority.Normal, null);
            }

            
return viewRoleGroup;
        }
    }

 

 

接下来我们将自定义自己的AuthorizeAttribute,

新建类CenterAuthorizeAttribute

 

代码
public class CenterAuthorizeAttribute : AuthorizeAttribute
    {

        
public override void OnAuthorization(AuthorizationContext filterContext)
        {

            
string action = (string)filterContext.RouteData.Values["Action"];
            
string controller = (string)filterContext.RouteData.Values["Controller"];
            
string fullName = filterContext.HttpContext.User.Identity.Name;

            
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
                filterContext.HttpContext.Response.Redirect(
string.Format("~/Account/LogOn?returnUrl={0}", filterContext.HttpContext.Request.Url.PathAndQuery));
            
else
            {
                
if (new Login().IsLock(fullName))
                    
throw new Exception(string.Format("【用户:{0}】对不起,该用户已被锁定。", fullName));

                var r 
= new BLL.RoleGroupRepository().GetUserRoleGroup(fullName);
                var q 
= new BLL.ViewRoleGroupRepository().GetCacheAll().FindAll(c =>
                    c.RoleID 
== r.RoleID && c.SysAppController == controller && c.SysAppAction == action &&
                    (c.StartTime.Equals(
"Anytime", StringComparison.CurrentCultureIgnoreCase) ? true : (DateTime.Parse(c.StartTime) <= DateTime.Now)) &&
                    (c.EndTime.Equals(
"Anytime", StringComparison.CurrentCultureIgnoreCase) ? true : (DateTime.Parse(c.EndTime) >= DateTime.Now)));
                
if (q.Count == 0)
                    
throw new Exception(string.Format("【用户:{0}】对不起,您没有访问该页面的权限。", fullName));
            }
        }
    }

 

 

 

请注意var r = new BLL.RoleGroupRepository().GetUserRoleGroup(fullName);这个是我项目中通过用户名获得用户权限分组的实现,大家参考自己项目修改。

大功告成,那怎么用呢,很简单。创建了需要的权限组,例如

超级管理员  然后把对应的Controller和Action权限加入到组后,在需要的Action上进行标注,例如

 

[CenterAuthorize]
        
public ActionResult Index()
        {
            ViewData[
"Message"= "Welcome to ASP.NET MVC!";
            
return View();
        }

 

 

是不是很简单就通过数据库控制到每个需要权限控制的Action咯?当然很多朋友可能还很迷糊,第一次写这类文章。部分代码也没调试。因为从项目剥离出来,所以大家见谅。

UI部分和数据库的操作这里想滤过啦。这些比较简单的东西,大家应该很容易就能实现咯。

posted @ 2010-03-05 13:57  Leejor.  阅读(3875)  评论(10编辑  收藏  举报