【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目(8) 权限管理,自定义权限,扩展权限

在Web应用程序开发中,权限管理是至关重要的一环。它确保只有授权的用户能够访问特定的资源和执行特定的操作。ASP.NET MVC提供了一些基础的权限管理机制,但在实际项目中,我们往往需要更灵活的自定义权限和扩展权限功能。本文将深入探讨如何在ASP.NET MVC中实现这些功能。

二、目录#

  1. ASP.NET MVC权限管理基础
    • 身份验证与授权概念
    • 内置的AuthorizeAttribute
  2. 自定义权限
    • 创建自定义权限特性
    • 与数据库集成存储权限信息
    • 在控制器和操作方法上应用自定义权限
  3. 扩展权限
    • 基于角色的扩展
    • 基于资源的扩展
    • 动态权限分配
  4. 最佳实践
    • 权限粒度控制
    • 日志记录与审计
    • 性能优化
  5. 示例代码
    • 自定义权限特性代码示例
    • 权限验证逻辑示例
  6. **参考

三、ASP.NET MVC权限管理基础#

3.1 身份验证与授权概念#

  • 身份验证:确认用户的身份,常见方式有表单验证(Forms Authentication)、Windows身份验证等。例如,用户输入用户名和密码,系统验证其正确性来完成身份验证。
  • 授权:在身份验证通过后,确定用户是否有权限访问特定资源或执行特定操作。

3.2 内置的AuthorizeAttribute#

ASP.NET MVC提供了AuthorizeAttribute。可以简单地在控制器或操作方法上使用它来限制访问。

[Authorize]
public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}

上述代码表示HomeController下的所有操作方法都需要用户经过身份验证才能访问。如果只想特定角色的用户访问,可以这样:

[Authorize(Roles = "Admin")]
public ActionResult AdminOnlyAction()
{
    return View();
}

四、自定义权限#

4.1 创建自定义权限特性#

创建一个继承自AuthorizeAttribute的类,例如CustomAuthorizeAttribute

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    public string RequiredPermission { get; set; }
 
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        // 这里可以根据RequiredPermission去数据库查询当前用户是否有该权限
        // 假设从数据库获取用户权限的方法是GetUserPermissions
        var userPermissions = GetUserPermissions(httpContext.User.Identity.Name);
        return userPermissions.Contains(RequiredPermission);
    }
}

4.2 与数据库集成存储权限信息#

可以设计两张表,Users表存储用户信息,Permissions表存储权限名称等信息,UserPermissions表建立用户与权限的多对多关系。 当用户登录时,查询该用户拥有的权限列表并缓存(例如使用MemoryCache),以提高性能。

4.3 在控制器和操作方法上应用自定义权限#

[CustomAuthorize(RequiredPermission = "ViewProduct")]
public ActionResult ViewProductDetails(int id)
{
    // 操作逻辑
    return View();
}

五、扩展权限#

5.1 基于角色的扩展#

可以在CustomAuthorizeAttribute中同时考虑角色。

protected override bool AuthorizeCore(HttpContextBase httpContext)
{
    var userPermissions = GetUserPermissions(httpContext.User.Identity.Name);
    var userRoles = GetUserRoles(httpContext.User.Identity.Name);
    return userPermissions.Contains(RequiredPermission) || userRoles.Contains(RequiredRole);
}

然后在特性上添加RequiredRole属性。

5.2 基于资源的扩展#

有时候权限不仅与操作有关,还与具体资源相关。例如,用户对某个特定产品的编辑权限。可以在权限验证时,传入资源ID。

[CustomAuthorize(RequiredPermission = "EditProduct", ResourceId = 10)]
public ActionResult EditProduct(int id)
{
    // 操作逻辑
    return View();
}

AuthorizeCore方法中,根据ResourceId进一步验证。

5.3 动态权限分配#

可以提供一个后台管理界面,管理员能够动态地为用户分配权限。当权限分配发生变化时,及时更新用户的权限缓存。

六、最佳实践#

6.1 权限粒度控制#

权限定义要细粒度,例如“查看产品列表”、“查看产品详情”等分开定义,而不是一个笼统的“产品相关权限”。这样可以更精确地控制用户操作。

6.2 日志记录与审计#

记录用户的权限访问情况,例如每次权限验证失败或成功的记录。可以使用Log4Net等日志框架。

protected override bool AuthorizeCore(HttpContextBase httpContext)
{
    var result = base.AuthorizeCore(httpContext);
    if (!result)
    {
        LogManager.GetLogger(typeof(CustomAuthorizeAttribute)).Error($"User {httpContext.User.Identity.Name} failed permission {RequiredPermission}");
    }
    return result;
}

6.3 性能优化#

对于频繁访问的权限验证,合理使用缓存。例如,用户的权限列表在登录时获取并缓存一段时间。

七、示例代码#

7.1 自定义权限特性代码示例(完整)#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
 
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    public string RequiredPermission { get; set; }
    public string RequiredRole { get; set; }
 
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (!httpContext.User.Identity.IsAuthenticated)
        {
            return false;
        }
 
        var userPermissions = GetUserPermissions(httpContext.User.Identity.Name);
        var userRoles = GetUserRoles(httpContext.User.Identity.Name);
 
        bool hasPermission = userPermissions.Contains(RequiredPermission);
        bool hasRole = userRoles.Contains(RequiredRole);
 
        return hasPermission || hasRole;
    }
 
    private List<string> GetUserPermissions(string username)
    {
        // 这里模拟从数据库获取,实际应查询数据库
        return new List<string> { "ViewProduct", "EditProduct" };
    }
 
    private List<string> GetUserRoles(string username)
    {
        // 这里模拟从数据库获取,实际应查询数据库
        return new List<string> { "Admin" };
    }
 
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        filterContext.Result = new HttpUnauthorizedResult();
    }
}

7.2 权限验证逻辑示例(在控制器中)#

public class ProductController : Controller
{
    [CustomAuthorize(RequiredPermission = "ViewProduct")]
    public ActionResult Index()
    {
        return View();
    }
 
    [CustomAuthorize(RequiredPermission = "EditProduct", RequiredRole = "Admin")]
    public ActionResult Edit(int id)
    {
        return View();
    }
}

八、参考#

  • ASP.NET MVC官方文档
  • 《Pro ASP.NET MVC 5》书籍
  • 一些开源的ASP.NET MVC权限管理项目(如Abp,可参考其权限管理实现)