安全修剪菜单作为局部视图
Posted
技术标签:
【中文标题】安全修剪菜单作为局部视图【英文标题】:Security Trimmed Menu as Partial View 【发布时间】:2021-02-22 20:57:55 【问题描述】:我正在 _Layout.cshtml 文件中呈现一个菜单。仅当用户处于管理员角色时才应呈现菜单的一部分。我们在数据库中使用自定义角色。 Admin 字段以单个字符“Y”或“N”返回。这最初是一个遗留应用程序,正在迁移到 MVC 5。未使用 LINQ 或实体框架。
我将菜单创建为部分视图,Menu.cshtml:
<ul class="nav" ui-nav>
...
@if ((bool)ViewData["Admin"] == true)
<li>
<a href="#"><span>Users and Roles</span></a>
</li>
</ul>
我的 _Layout.cshtml 文件:
...
<aside id="aside" class="ui-aside">
@Html.Action("Menu")
</aside>
...
控制器的操作方法是我遇到问题的地方。我的意图是返回一个布尔值,并根据部分视图中的该值简单地切换菜单受保护部分的呈现。现在它在应该显示菜单的浏览器中呈现 True 或 False,因为该布尔值作为 HTML 字符串从 action 方法返回。
我知道我可以将菜单的那部分作为字符串从操作方法返回,但我想避免这种情况,因为菜单的其他部分会根据角色值呈现。我不想以一连串的片面观点告终。如果可能的话,我还想避免使用标签助手。我只是想根据 action 方法中的布尔值来切换部分视图中 HTML 菜单部分的呈现。
动作方法:
[ChildActionOnly]
public bool Menu()
using (connection...)
...
object adminObject = command.ExecuteScalar();
if (adminObject != null)
string admin = adminObject.ToString();
if (admin == "Y")
ViewData["Admin"] = true;
else
ViewData["Admin"] = false;
return (bool)ViewData["Admin"];
【问题讨论】:
【参考方案1】:您的局部视图可以声明一个与之配套的模型。您可以使用@Html.RenderAction()
来代替使用@Html.Action()
将结果作为HTML 字符串返回
-
运行逻辑以获取当前登录用户的角色状态
为局部视图构建视图模型
将部分视图连同视图模型直接返回给响应
这样,你如何获取用户角色状态的逻辑就被“封装”在了子action方法中,菜单部分是显示还是隐藏的逻辑被“封装”在了局部视图中。
菜单.cshtml
在您想要呈现仅供管理员使用的部分的菜单中,您使用@Html.RenderAction()
在menu
控制器中执行buildUsersAndRoles
操作(我只是编造的):
<ul class="nav" ui-nav>
...
@Html.RenderAction("buildUsersAndRoles", "menu", new area = "" )
...
</ul>
MenuController.cs
基本思想是呈现您的逻辑以获取您需要的必要数据,包括显示用户是否为管理员的标志。基于这些,您可以确定要在视图模型中传回的内容。
我的方法是如果用户不是管理员,则传递 NULL,因为没有可显示的内容,否则传递包含用户和角色信息的视图模型:
public class MenuController : Controller
...
[ChildActionOnly]
public ActionResult BuildUsersAndRoles()
using (connection...)
...
object adminObject = command.ExecuteScalar();
if (adminObject != null)
string admin = adminObject.ToString();
if (admin == "Y")
var vm = new UsersAndRolesViewModel
Users = new List<...>(),
Roles = new List<...>(),
...
;
return PartialView("_UsersAndRolesPartial", vm);
return PartialView("_UsersAndRolesPartial");
...
_UsersAndRolesPartial.cshtml
最后,在您只想在用户具有管理员角色时显示的部分中,您可以使用视图模型:
@model ...UsersAndRolesViewModel
@if (Model != null)
<h5>Users and Roles</h5>
...
【讨论】:
感谢大卫,这很有效。我对布局文件中的 Html.RenderAction 调用的语法有一些问题。这最终奏效了:@Html.RenderAction("CheckUserAdmin"); ...“CheckUserAdmin”是您称为“BuildUsersAndRoles”的操作的名称。 @IrishChieftain:对不起,这些都是我亲手写的。我想我会使用@Html.Action()
代替,因为我不喜欢将;
放在剃须刀代码的中间。我可能应该改为调用BuildUsersAndRolesMenuSection
操作。我不喜欢CheckUserAdmin
的名字。我不喜欢将其视为检查用户是否具有管理员角色的逻辑。构建一些局部视图确实是逻辑。
好电话,我重命名了 ;-)【参考方案2】:
如您所知 Html.Action
返回 MvcHtmlString
这就是它显示 True
或 False
的原因
你乐于尝试这样的事情吗?
_Layout.cshtml
<li>@if(Html.Action("Menu").ToString().ToLower()=="true")
@Html.Partial("_Menu")
</li>
局部视图
<ul class="nav" ui-nav>
<li>
<a href="#"><span>Users and Roles</span></a>
</li>
</ul>
【讨论】:
感谢 Raju,将整个菜单作为 HTML 字符串发回是我的 B 计划。但我需要一些可以更好地扩展的东西。【参考方案3】:我假设单击菜单链接的操作将涉及获取控制器或页面,使用 asp.net 授权来控制访问。
这是我对 asp.net core 的看法(它不能回答你的问题,但将来可能会很有趣)。编写一个标签助手,删除用户无权查看的标签。这样您就可以重复使用相同的授权策略名称来控制可见性和权限。
[HtmlTargetElement(Attributes = "policy")]
public class PolicyTagHelper : TagHelper
private readonly IAuthorizationService authService;
private readonly IHttpContextAccessor httpContextAccessor;
public PolicyTagHelper(IAuthorizationService authService, IHttpContextAccessor httpContextAccessor)
this.authService = authService;
this.httpContextAccessor = httpContextAccessor;
public string Policy get; set;
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
if (!(await authService.AuthorizeAsync(httpContextAccessor.HttpContext.User, Policy)).Succeeded)
output.SuppressOutput();
用法;
public void ConfigureServices(IServiceCollection services)
services.AddRazorPages(options =>
options.Conventions
.AuthorizePage("/UserRole", "Admin");
services.AddAuthorization(options =>
options.AddPolicy("Admin", policy => ...);
<ul class="nav" ui-nav>
<li policy="Admin">
<a href="#"><span>Users and Roles</span></a>
</li>
</ul>
【讨论】:
我认为 OP 在 ASP.NET MVC 5 中还不是 ASP.NET Core MVC,但我不得不承认这确实是一种有趣的方法,我没有想到 :) 是的,我发现标签丢失了。以上是关于安全修剪菜单作为局部视图的主要内容,如果未能解决你的问题,请参考以下文章