ASP.NET MVC - 角色提供程序的替代方案?

2024-05-02

我试图避免使用角色提供程序和成员资格提供程序,因为在我看来它太笨拙了,因此我试图制作自己的“版本”,它不那么笨拙并且更易于管理/灵活。现在我的问题是……除了角色提供者之外,还有其他不错的选择吗? (我知道我可以自定义角色提供者、会员提供者等。)

通过更易于管理/灵活,我的意思是我仅限于使用 Roles 静态类,而不是直接实现到与数据库上下文交互的服务层中,而是必须使用具有自己的数据库上下文的 Roles 静态类等等,表名也很糟糕..

提前致谢。


我和你的情况一样——我一直讨厌 RoleProviders。是的,如果您想花很少的钱就可以启动并运行它们,它们就很棒website,但它们不太现实。我一直发现的主要缺点是它们将您直接与 ASP.NET 联系在一起。

我最近的一个项目的方式是定义几个属于服务层一部分的接口(注意:我简化了这些接口 - 但您可以轻松添加到它们):

public interface IAuthenticationService
{
    bool Login(string username, string password);
    void Logout(User user);
}

public interface IAuthorizationService
{
    bool Authorize(User user, Roles requiredRoles);
}

那么您的用户就可以拥有Roles enum:

public enum Roles
{
    Accounting = 1,
    Scheduling = 2,
    Prescriptions = 4
    // What ever else you need to define here.
    // Notice all powers of 2 so we can OR them to combine role permissions.
}

public class User
{
    bool IsAdministrator { get; set; }
    Roles Permissions { get; set; }
}

为您IAuthenticationService,您可以有一个执行标准密码检查的基本实现,然后您可以有一个FormsAuthenticationService这会做更多的事情,例如设置 cookie 等。AuthorizationService,你需要这样的东西:

public class AuthorizationService : IAuthorizationService
{
    public bool Authorize(User userSession, Roles requiredRoles)
    {
        if (userSession.IsAdministrator)
        {
            return true;
        }
        else
        {
            // Check if the roles enum has the specific role bit set.
            return (requiredRoles & user.Roles) == requiredRoles;
        }
    }
}

在这些基本服务之上,您可以轻松添加重置密码等服务。

由于您使用的是 MVC,因此您可以使用ActionFilter:

public class RequirePermissionFilter : IAuthorizationFilter
{
    private readonly IAuthorizationService authorizationService;
    private readonly Roles permissions;

    public RequirePermissionFilter(IAuthorizationService authorizationService, Roles requiredRoles)
    {
        this.authorizationService = authorizationService;
        this.permissions = requiredRoles;
        this.isAdministrator = isAdministrator;
    }

    private IAuthorizationService CreateAuthorizationService(HttpContextBase httpContext)
    {
        return this.authorizationService ?? new FormsAuthorizationService(httpContext);
    }

    public void OnAuthorization(AuthorizationContext filterContext)
    {
        var authSvc = this.CreateAuthorizationService(filterContext.HttpContext);
        // Get the current user... you could store in session or the HttpContext if you want too. It would be set inside the FormsAuthenticationService.
        var userSession = (User)filterContext.HttpContext.Session["CurrentUser"];

        var success = authSvc.Authorize(userSession, this.permissions);

        if (success)
        {
            // Since authorization is performed at the action level, the authorization code runs
            // after the output caching module. In the worst case this could allow an authorized user
            // to cause the page to be cached, then an unauthorized user would later be served the
            // cached page. We work around this by telling proxies not to cache the sensitive page,
            // then we hook our custom authorization code into the caching mechanism so that we have
            // the final say on whether or not a page should be served from the cache.
            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 HttpUnauthorizedResult();
        }
    }

    public HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext)
    {
        var authSvc = this.CreateAuthorizationService(httpContext);
        var userSession = (User)httpContext.Session["CurrentUser"];

        var success = authSvc.Authorize(userSession, this.permissions);

        if (success)
        {
            return HttpValidationStatus.Valid;
        }
        else
        {
            return HttpValidationStatus.IgnoreThisRequest;
        }
    }
}

然后您可以在控制器操作上进行装饰:

[RequirePermission(Roles.Accounting)]
public ViewResult Index()
{
   // ...
}

这种方法的优点是您还可以使用依赖项注入和 IoC 容器来连接事物。此外,您还可以在多个应用程序(不仅仅是 ASP.NET 应用程序)中使用它。您将使用 ORM 来定义适当的模式。

如果您需要有关的更多详细信息FormsAuthorization/Authentication服务或从这里去哪里,请告诉我。

编辑:要添加“安全修剪”,您可以使用 HtmlHelper 来完成。这可能需要更多……但你明白了。

public static bool SecurityTrim<TModel>(this HtmlHelper<TModel> source, Roles requiredRoles)
{
    var authorizationService = new FormsAuthorizationService();
    var user = (User)HttpContext.Current.Session["CurrentUser"];
    return authorizationService.Authorize(user, requiredRoles);
}

然后在您的视图中(此处使用 Razor 语法):

@if(Html.SecurityTrim(Roles.Accounting))
{
    <span>Only for accounting</span>
}

编辑:UserSession看起来像这样:

public class UserSession
{
    public int UserId { get; set; }
    public string UserName { get; set; }
    public bool IsAdministrator { get; set; }
    public Roles GetRoles()
    {
         // make the call to the database or whatever here.
         // or just turn this into a property.
    }
}

这样,我们就不会暴露当前用户会话中的密码哈希和所有其他详细信息,因为它们是really用户会话生命周期不需要。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ASP.NET MVC - 角色提供程序的替代方案? 的相关文章

随机推荐

  • 存储应用程序配置设置

    在 AngularJS 中存储应用程序配置设置的最佳位置是什么 这可能是应用程序常量 查找等 可以从控制器和服务或工厂使用 我可以创建一个单独的服务来存储和检索这些东西 但我想知道是否有另一个合适的地方来存储和检索这些东西 您可以使用持续的
  • 如何检测 iPhone 中按下的键盘按键?

    我想检测用户何时按下任何键盘键 仅在键入任何字符时调用的任何方法 而不是在显示键盘时调用的方法 Thanks 您可以在用户每次按键时直接处理键盘事件 Swift 对于文本字段 请使用以下委托方法 func textField textFie
  • 为什么我的 Visual Studio .obj 文件比输出的 .exe 文件大?

    作为背景 我是一个开源项目的开发人员 一个名为开放框架 http www openframeworks cc 这是不同库的包装器 例如 opengl quicktime freeImage 等 在下一个版本中 我们添加了一个名为 POCO
  • 在内核 OpenCL 中实现 FIFO 的最佳方法

    目标 在 OpenCL 中实现下图所示 OpenCl 内核所需的主要内容是将系数数组和临时数组相乘 然后最后将所有这些值累加为 1 这可能是最耗时的操作 并行性在这里非常有帮助 我正在为内核使用一个辅助函数来执行乘法和加法 我希望这个函数也
  • 限制文本框中每行的最大字符数

    假设我有以下内容
  • 如何创建“抽象字段”?

    我知道java中不存在抽象字段 我也读过这个问题 https stackoverflow com questions 2211002 why not abstract fields但提出的解决方案并不能解决我的问题 也许没有解决方案 但值得
  • 确定性时的虚函数开销 (c++)

    我知道虚拟函数本质上是包含在 vtable 中的函数指针 这使得多态调用由于间接等原因而变慢 但我想知道当调用是确定性时编译器的优化 我所说的确定性是指以下情况 该对象是一个值而不是引用 因此不可能存在多态性 struct Foo virt
  • Tensorflow:np数组的next_batch函数

    我的火车数据为 xTrain numpy asarray 100 1 5 6 yTrain numpy asarray 200 2 10 12 如何定义 next batch size 方法以从训练数据中获取随机元素的 size 个数 您可
  • 在 numpy 中索引多个不相邻的范围

    我想从一维 numpy 数组 或向量 中选择多个不相邻的范围 Suppose gt gt gt idx np random randint 100 size 10 array 82 9 11 94 31 87 43 77 49 50 当然
  • 自动订阅应用内购买:恢复后续续订

    根据 Apple 应用内购买编程指南 App Store 每次续订订阅时都会创建一个单独的交易 当您的应用程序恢复以前的购买时 Store Kit 会将每笔交易传送到您的应用程序 假设我的应用程序订阅仅限客户端 无服务器组件 验证后续续订是
  • { [FacebookTokenError:此授权码已被使用。]

    我有一个航行应用程序 我正在尝试实现 Facebook 登录 当我单击 使用 facebook 登录 按钮时 出现此错误 error A server error occurred in a request error FacebookTo
  • PHP cURL:CURLOPT_CONNECTTIMEOUT 与 CURLOPT_TIMEOUT

    PHP 有以下两个与超时相关的选项 CURLOPT CONNECTTIMEOUT and CURLOPT TIMEOUT PHP 网站上的描述有点模糊 有什么不同 使用现实世界的示例 假设您通过 cURL 将 GET 变量发送到 URL 并
  • 有没有办法理解安装错误代码的实际含义?

    我正在尝试应用内更新功能 但收到 FAILED 安装状态和 100 安装错误代码 有什么办法让我知道可能是什么原因造成的吗 我实现了灵活的应用内更新 并记录了每个步骤 遵循 Android 开发者教程here https developer
  • jQuery 自动完成标记插件,如 StackOverflow 的输入标记? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 哪些解决方案可以实现与 SO 用于输入标签相同的自动完成功能 有可以处理一个单词的插件 但我还没有看到
  • 需要从表单生成的工作表中移动行

    我有一个调查表 我需要我的团队查看一次 但之后我希望我的团队将其设置为 已关闭 的行保存到存档表中 过去 我在其他工作表中使用过此脚本 但它似乎不适用于表单链接工作表 经过研究 我发现您无法从表单链接表中剪切 但可以删除行 我的理论是脚本正
  • 当implicitly_wait不起作用时使用find_element_by_link_text出现NoSuchElement异常?

    python 和 Selenium 以及相关编程的新手 我正在尝试自动化硒以点击特定链接 在本例中 我希望它点击与链接文本 B 关联的链接 li a href B a 在这个网站上 http www lw com http www lw c
  • Azure 中的 ASP.NET MVC 4 和 Web API - 未找到 HTTP 资源

    使用 Visual Studio 2012 我创建了一个简单的 Windows Azure 项目 云项目 其中包含 ASP NET MVC 4 网站 我没有对模板进行任何更改 我只是尝试使用Azure 网站 https www window
  • 在 Laravel 5.1 中将模型保存到数据库之前执行一些操作

    在 Laravel 5 1 模型中 在将数据写入数据库之前 我该如何做一些事情 例如修改某些数据字段或进行更多验证 关于该问题的文档很难在实际应用中使用 http laravel com docs 5 1 eloquent events h
  • SwiftUI 双向绑定到枚举案例中 ObservableObject 内的值

    我正在尝试观察 a 的变化bool包含在一个值ObservableObject这是一个值enum案件 这是我想要实现的目标的示例 但使用当前的方法我收到错误Use of unresolved identifier type1Value im
  • ASP.NET MVC - 角色提供程序的替代方案?

    我试图避免使用角色提供程序和成员资格提供程序 因为在我看来它太笨拙了 因此我试图制作自己的 版本 它不那么笨拙并且更易于管理 灵活 现在我的问题是 除了角色提供者之外 还有其他不错的选择吗 我知道我可以自定义角色提供者 会员提供者等 通过更