如何使用 asp.net MVC 在挖空组件中隐藏基于角色的部分

How to hide role based section in knockout component using asp.net MVC

防止用户在 knockout 组件中看到类似 admin 链接 的最佳方法是什么?

如果用户有权查看这些链接,我不想发出客户端请求,因为这会在客户端公开此部分。

我能弄清楚的唯一方法是使用视图来表示组件模板,然后在呈现 HTML[ 之前检查用户是否在服务器端正确=23=].

但是有没有比这更干净的另一种方法,或者这是正确的方法吗?

我在 AngularJS 应用程序方面遇到过类似的挑战。

与其执行额外的服务请求,我更喜欢在模型或 ViewBag 中传递登录状态和角色。

为简单起见,假设我们使用 ViewBag

1)动作方法中,设置

ViewBag.loggedIn = User.Identity.IsAuthenticated;
ViewBag.userId = User.Identity.GetUserId();

var identity = (System.Security.Claims.ClaimsIdentity)User.Identity;
ViewBag.roles = identity.Claims
                .Where(c => c.Type == ClaimTypes.Role)
                .Select(c => c.Value);

2)JS 文件 中,全局定义 UserModel 绑定和函数以检查用户是否具有正确的角色-姓名:

var UserModel = function () {
    var self = this;
    self.isLoggedIn = ko.observable("");
    self.userId = ko.observable("");
    self.roles = ko.observableArray([]);


    // function to check if role passed is in array
    self.hasRole = function (roleName) {

      for (i = 0; 1 < self.roles.length ; i++ ) {
          if (self.roles[i] == roleName)
             return true
      }
      return false;
    }

};

var UserData = new UserModel();

在 .cshtml 视图中:

3)绑定角色和登录数据

<script type="text/javascript">
   UserData.isLoggedIn("@ViewBag.isLoggedIn");
   UserData.userId("@ViewBag.userId");
   UserData.roles(@Html.Raw(Json.Encode(ViewBag.roles));
</script>

4) 如果 Role 正确则显示部分:

<div data-bind="visible: UserData.hasRole("Admin")>
          ....
</div>

隐藏管理组件的方法:

剃刀之道:

除了使用 Knockout 隐藏组件外,还有 C#/Razor 方法

->嵌套if子句

@((List<String>) ViewBag.roles.contains("Admin")) 
{

...

}

Razor Conditions 相对于 Knockout 的优势是组件不会在服务器创建页面时呈现,客户端不会看到任何痕迹

-> _Layout

中的条件部分
@if ((List<String>) ViewBag.roles.contains("Admin"))
{
    @RenderSection("Admin Section")
}

比简单的 Razor Condition 更清洁并在整个应用程序中自动应用

-> 部分带有子操作

被称为(Action, Controller, Parameter)

@Html.Action("AdminConsole", "Admin", new { Role = "Admin"})

public ActionResult AdminComponent(string Role)
        {

            If (List<String>) ViewBag.roles.contains("Admin")
                  return PartialView(
            return View(products);
        }

所有方法中最干净的。可以合并到一个部分中以更加方便。


关于如何隐藏管理组件的结论:

您选择如何隐藏管理组件取决于您的需要。 Razor/C#方式更方便也更有安全感。

另一方面,如果您有兴趣为用户提供 SPA 体验,C# 和服务器方法则达不到要求。您是否允许用户在不刷新页面的情况下进行身份验证?如果是这样,管理员可以进行身份​​验证并将匿名用户更改为管理员。

如果您愿意刷新屏幕以显示更改的内容,C#/Razor 是您的方法。如果您的首要任务是为用户提供 "responsive experience",您将需要实施 Knockout 解决方案。

如果您无法将标记公开给客户端,那么唯一的方法是在标记生成之前在服务器上公开。正如您所指出的,这将在视图渲染中完成。

在您的情况下,使用分部视图来保存 KO 组件是合适的,并提供您需要的功能,同时允许您重用组件标记。

这是我以前用过的方法,效果非常好:

查看

<script type="text/javascript">
    ko.components.register("foo", {
        viewModel: FooComponentViewModel,
        template: { element: "component-foo" }
    });
</script>

...

<foo params="IsAdmin: @(User.IsInRole("Admin") ? 'true' : 'false')"></foo>

...

@Html.Partial("Components/_Foo")

如有必要,甚至可以通过 MVC 视图模型将其他上下文传递给分部视图。

组件局部视图

<template id="component-foo">
    @if(@User.IsInRole("Admin"))
    {
        // something you DO care about the client seeing
    }

    ...
</template>

@if(@User.IsInRole("Admin"))
{
    <script type="text/javascript">
        // Some JS code to hide from non admins for this component
    </script>
}

组件视图模型

function FooComponentViewModel(params) {
    var self = this;

    self.AdminDoSomething = function () {
        if (!params.IsAdmin) {
            return;
        }

        // something you DO NOT care about the client seeing...
    };
}

我知道在提供您寻求的要求的同时没有更简洁的方法来做到这一点。