MVC使用窗体身份验证及角色权限管理

MVC使用窗体身份验证及角色权限管理

本文仅使用 ASP.NET 的窗体身份验证,不会使用它的 成员资格(Membership)角色管理 (RoleManager),原因有二:一是不灵活,二是和 MVC 关系不太.


用户模型

User 模型类:

public class User
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Password { get; set; }    
    public string[] Roles { get; set; }
}

UserRepository 为数据存取类,为了演示方便,并没有连接数据库,而是使用一个数组来作为数据源:

public class UserRepository
{
    private static User[] usersForTest = new[]
    {
        new User{ ID = 1, Name = "bob", Password = "bob", Roles = new []{"employee"}},
        new User{ ID = 2, Name = "tom", Password = "tom", Roles = new []{"manager"}},
        new User{ ID = 3, Name = "admin", Password = "admin", Roles = new[]{"admin"}},
    };

    public bool ValidateUser(string userName, string password)
    {
        return usersForTest
            .Any(u => u.Name == userName && u.Password == password);
    }

    public string[] GetRoles(string userName)
    {
        return usersForTest
            .Where(u => u.Name == userName)
            .Select(u => u.Roles)
            .FirstOrDefault();
    }

    public User GetByNameAndPassword(string name, string password)
    {
        return usersForTest
            .FirstOrDefault(u => u.Name == name && u.Password == password);
    }
}

用户登录及身份验证

用户登录

方式一

登录处理

[HttpPost]
public ActionResult Login(string name,string password)
{
    if(repository.ValidateUser(name,password))
    {
        FormsAuthentication.SetAuthCookie(name, true);
    }
    return RedirectToAction("index", "home");
}

修改 Global.asax

public class MvcApplication : System.Web.HttpApplication
{
    public MvcApplication()
    {
        AuthorizeRequest += new EventHandler(MvcApplication_AuthorizeRequest);
    }

    void MvcApplication_AuthorizeRequest(object sender, EventArgs e)
    {
        IIdentity id = Context.User.Identity;
        if (id.IsAuthenticated)
        {
            var roles = new UserRepository().GetRoles(id.Name);
            Context.User = new GenericPrincipal(id, roles);
        }
    }
    //...
}

方式二

登录处理

[HttpPost]
public ActionResult Login2(string name,string password)
{
    User user = repository.GetByNameAndPassword(name, password);
    if(user!=null)
    {
        FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
            user.Name,
            DateTime.Now,
            DateTime.Now.Add(FormsAuthentication.Timeout),
            true,
            user.Roles.Aggregate((i, j) => i + "," + j)
            );
        HttpCookie cookie = new HttpCookie(
            FormsAuthentication.FormsCookieName,
            FormsAuthentication.Encrypt(ticket)
            );
        Response.Cookies.Add(cookie);
    }
    return RedirectToAction("index", "home");
}

修改 Global.asax

public class MvcApplication : System.Web.HttpApplication
{
    public MvcApplication()
    {
        AuthorizeRequest += new EventHandler(MvcApplication_AuthorizeRequest);
    }

    void MvcApplication_AuthorizeRequest(object sender, EventArgs e)
    {
        var id = Context.User.Identity as FormsIdentity;
        if (id != null && id.IsAuthenticated)
        {
            var roles = id.Ticket.UserData.Split(',');
            Context.User = new GenericPrincipal(id, roles);
        }
    }
    //...
} 

登出

public ActionResult LogOff()
{
    FormsAuthentication.SignOut();
    return RedirectToAction("Index", "Home");
}

角色权限

默认方式

在默认方式下,我们可以这样来使用AuthorizeAttribute实现基于角色的权限管理了:

[Authorize(Roles ="admin")]
public ActionResult Contact()
{
    ViewBag.Message = "Your contact page.";

    return View();
}

自定义方式

不过我们可以通过自定义实现CustomAuthorizeAttribute来实现更加灵活的角色权限管理,如下:

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    public CustomAuthorizeAttribute(params string[] roleKeys)
    {
        var roles = new List<string>();
        var allRoles = (NameValueCollection)ConfigurationManager.GetSection("CustomRoles");
        foreach (var roleKey in roleKeys)
        {
            roles.AddRange(allRoles[roleKey].Split(new[] { ',' }));
        }
        Roles = string.Join(",", roles);
    }
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);
        if(filterContext.Result is HttpUnauthorizedResult)
        {
            filterContext.Result = new RedirectResult("~/Error/AcessDenied");
        }
    }
}

之后在web.config中添加如下配置:

<section name="CustomRoles" type="System.Configuration.NameValueFileSectionHandler,System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />  

...
<CustomRoles>
    <add key="UsersPagePermission" value="admin,manager,employee" />
</CustomRoles>

这样的话就可以这样来使用:

[CustomAuthorize("UsersPagePermission")]
public ActionResult About()
{
    ViewBag.Message = "Your application description page.";

    return View();
}

简要说明

MVC 使用 HttpContext.User 属性进行来进行实现身份验证及角色管理,同样 AuthorizeAttribute 也根据 HttpContext.User 进行角色权限验证。

因些不要在用户登录后,将相关用户信息保存在 Session 中(网上经常看到这种做法),将用户保存在 Session 中是一种非常不好的做法。

也不要在 Action 中进行角色权限判断,应该使用 AuthorizeAttribute 或它的子类

发表评论

电子邮件地址不会被公开。 必填项已用*标注