tiny custom role management for asp.net mvc 3
Asked Answered
S

1

0

I chose to do a school project with asp.net mvc3 and there is a need of a user/role management. I think the membership that ships with asp.net is way too big for a school projec. SO my thought is this. if i could find an equivalent of Zend predispatch method for asp or even a better one i could store the urls accessible as privilege for a role and load it in session and check if a particular user have access to it and redirect if not.

my question are this:

Is there any equivalent of PreDispatch method in asp?
Is there any better approach for my problem ? if yes please post resources

Thanks for reading this

EDIT i generate sublinks from databse using this:

 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());
    }
}
Swum answered 28/2, 2012 at 9:1 Comment(0)
S
4

You can implement like this.

  1. Enum for roles
  2. FilterAttribute
  3. Create Web.sitemap for menu
  4. Add Menu creator action
  5. Add Menu to _Layout.cshtml
  6. Add FilterAttribute to controller or action

----1 Enum------

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 Menu Creator Action----

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 Add helper to _Layout.cshtml

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

----6 Controller----

[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;
    }
}
Stenson answered 28/2, 2012 at 9:31 Comment(4)
wow that was fast, i think i like this way, but where the authentication happens? and where to pass the role to the filter also i use a helper to generate submenu for discipline from databse. the roles are from database too.will update the post to include how i generate the submenu thanks.Swum
authentication happens in RequirePermissionFilter filter. You have to pass minimum require role like this; [RequirePermissionFilter(Roles.Student)] . You have to add the user role to session on authentication. And then check the session object if user have minimum required role.Stenson
What i mean is the scenario that happens after login from the database. Assuming i implemented everything how does it work in the bigger picture 1 i find a user corresponding to the passed username/password 2 i store that user object in a session 3 i instantiate the RequirePermission by passing the role it 4 the filter start checking roles for each annotated controller then am good to go ?Swum
Hello again, i'm trying to implement your suggestion, i seem not to know where the _authManager in Filter comes from. thanks for shedding some light.Swum

© 2022 - 2024 — McMap. All rights reserved.