【问题标题】:tiny custom role management for asp.net mvc 3asp.net mvc 3 的微型自定义角色管理
【发布时间】:2012-03-17 18:02:13
【问题描述】:

我选择用 asp.net mvc3 做一个学校项目,需要一个用户/角色管理。我认为 asp.net 附带的成员对于学校项目来说太大了。 所以我的想法是这样的。如果我能找到一个等效于 Zend predispatch 方法的 asp 甚至更好的方法,我可以将可访问的 url 存储为一个角色的权限并将其加载到会话中并检查特定用户是否有权访问它,如果没有则重定向。

我的问题是这样的:

在 asp 中是否有任何等效的 PreDispatch 方法?
有没有更好的方法来解决我的问题?如果是,请发布资源

感谢阅读本文

编辑 我使用这个从数据库生成子链接:

 public static class SubMenuHelper
{


    public static MvcHtmlString GetSubMenu()
    {
        var db = new SchoolContextExpress();
        var submenu = from s in db.Disciplines select s;
        var sbuilder = new StringBuilder();
        foreach (var discipline in submenu)
        {
            sbuilder.AppendFormat("<li><a class='sublink' href='/Discipline/Details/{0}'>{1}</a></li>", discipline.DisciplineID, discipline.Name);
        }
        return new MvcHtmlString(sbuilder.ToString());
    }
}

【问题讨论】:

    标签: asp.net asp.net-mvc-3 entity-framework-4 user-management


    【解决方案1】:

    你可以这样实现。

    1. 角色枚举
    2. 过滤器属性
    3. 为菜单创建 Web.sitemap
    4. 添加菜单创建者操作
    5. 将菜单添加到 _Layout.cshtml
    6. 将 FilterAttribute 添加到控制器或操作

    ----1 枚举------

    public enum Roles{
         Common=1,
         Student = 2,
         Teacher=4
         Administration=8
    }
    

    ----2 RequirePermissionFilter----

    public class RequirePermissionFilter : ActionFilterAttribute, IAuthorizationFilter
    {
    
          private readonly Roles[] _requiredRoles;
           public RequirePermissionFilter(Roles requiredRoles)
        {
            _requiredRoles = new Roles[] { requiredRoles };
        }
    
        public RequirePermissionFilter(Roles[] requiredRoles)
        {
            _requiredRoles = requiredRoles;
        }
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            var success = false;
    
            foreach (Roles role in _requiredRoles)
            {
                 success |= _authManager.HasPermission(role);
            }
    
            if (success)
            {
                var cache = filterContext.HttpContext.Response.Cache;
                cache.SetProxyMaxAge(new TimeSpan(0));
                cache.AddValidationCallback((HttpContext context, object data, ref HttpValidationStatus validationStatus) =>
                {
                    validationStatus = this.OnCacheAuthorization(new HttpContextWrapper(context));
                }, null);
            }
            else
            {
                this.HandleUnauthorizedRequest(filterContext);
            }
        }
        private void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            // Ajax requests will return status code 500 because we don't want to return the result of the
            // redirect to the login page.
            if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
            {
                filterContext.Result = new HttpStatusCodeResult(500);
            }
            else
            {
                filterContext.Result = new RedirectToRouteResult("Error - 401", null);
            }
        }
        public HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext)
        {
            var success = false;
    
            foreach (Roles role in _requiredRoles)
            {
                success |= _authManager.HasPermission(role);
            }
    
            if (success)
            {
                return HttpValidationStatus.Valid;
            }
            else
            {
                return HttpValidationStatus.IgnoreThisRequest;
            }
        }
    }
    

    ----3 Web.sitemap-----

    <?xml version="1.0" encoding="utf-8" ?>
    <siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
        <siteMapNode url="" roleName="" title="" menuVisible="True">
            <siteMapNode url="~/Home/Index" roleName="-1" title="Home" menuVisible="True"/>
            <siteMapNode url="~/Student/Index" roleName="2 title="Student" menuVisible="True">
                 <siteMapNode url="~/MyLessons/Index" roleName="2 title="My Lessons" menuVisible="True"/>
            </siteMapNode>
            <siteMapNode url="~/Teacher/Index" roleName="4 title="Teacher" menuVisible="True"/>
            <siteMapNode url="~/Administration/Index" roleName="8 title="Administration" menuVisible="True"/>
        </siteMapNode>
    </siteMap>
    

    ----4 菜单创建者操作----

    public class CommonController : Controller{
    
        public ActionResult NavigationMenu()
            {
                return Content(SiteMapMenu());
            }
            public string SiteMapMenu()
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("<div class='menu'><ul>");
                var topLevelNodes = SiteMap.RootNode.ChildNodes;
    
    
                foreach (SiteMapNode node in topLevelNodes)
                {
                    if (HasPermission(node) && IsVisible(node))
                    {
                        if (SiteMap.CurrentNode == node)
                            sb.Append("<li class='selectedMenuItem'>");
                        else
                            sb.Append("<li>");
    
                        if (!string.IsNullOrEmpty(node.Url))
                            sb.AppendFormat("<a href='{0}'>{1}</a>", Url.Content(node.Url), node.Title);
                        else
                            sb.AppendFormat("<a href='javascript:void(0)'>{0}</a>", node.Title);
                        if (node.HasChildNodes && AnyOfChildIsVisible(node))
                        {
    
                            foreach (SiteMapNode childNode in node.ChildNodes)
                            {
                                if (HasPermission(childNode) && IsVisible(childNode))
                                {
                                    sb.Append("<li>");
                                    sb.AppendFormat("<a href='{0}'>{1}</a>", Url.Content(childNode.Url), childNode.Title);
                                    sb.Append("</li>");
                                }
                            }
    
                            sb.Append("</ul></div>");
                        }
    
                        sb.AppendLine("</li>");
                    }
                }
                sb.AppendLine("</ul></div>");
                return sb.ToString();
            }
            private bool HasPermission(SiteMapNode node)
            {
                int roleName = int.Parse(node["roleName"].ToString());
                if ((roleName == -1) || (_authManager.HasPermission((Roles)roleName)))
                    return true;
                return false;
            }
            private bool IsVisible(SiteMapNode node)
            {
                return bool.Parse(node["menuVisible"]);
            }
    
            private bool AnyOfChildIsVisible(SiteMapNode node)
            {
                foreach (SiteMapNode item in node.ChildNodes)
                {
                    if (IsVisible(item))
                        return true;
                }
                return false;
            }
    }
    

    ----5 为_Layout.cshtml添加助手

      @Html.Action("NavigationMenu", "Common")
    

    ----6 控制器----

    [RequirePermissionFilter(Roles.Student)]
    public class StudentController : Controller{
       /*
        *
        *
        *
        *
        */
    
    }
    

    ----AuthManager---

    public interface IAuthManager
    {
    
    
        bool HasPermission(Roles requiredRole);
    }
    
    public class AuthManager : IAuthManager
    {
        private ISessionManager _sessionManager;
        private ISuggestionConfig _config;
    
        public bool HasPermission(Roles requiredRoles)
        {
            if (HttpContext.Current.Session["USER"] != null)
                return (requiredRoles & ((User)HttpContext.Current.Session["USER"]).Roles) == requiredRoles;
            else
                return false;
        }
    }
    

    【讨论】:

    • 哇,真快,我想我喜欢这种方式,但身份验证发生在哪里?以及将角色传递给过滤器的位置,我还使用帮助程序从数据库生成纪律子菜单。角色也来自数据库。将更新帖子以包括我如何生成子菜单谢谢。
    • 身份验证发生在RequirePermissionFilter 过滤器中。你必须通过像这样的最低要求角色; [RequirePermissionFilter(Roles.Student)] 。您必须在身份验证时将用户角色添加到会话中。如果用户具有最低要求的角色,然后检查会话对象。
    • 我的意思是从数据库登录后发生的场景。假设我实现了一切,它在更大的图景中是如何工作的1 我找到了一个与传递的用户名/密码对应的用户2 我将该用户对象存储在会话中3 我通过传递角色来实例化 RequirePermission @ 987654333@ 过滤器开始检查每个带注释的控制器的角色,然后可以开始了吗?
    • 您好,我正在尝试执行您的建议,我似乎不知道过滤器中的_authManager 来自哪里。感谢您提供一些启示。
    猜你喜欢
    • 2011-02-13
    • 2012-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多