我搜索过很多SO和其他页面,但仍然找不到类似的案例。
我的应用程序正在使用SimpleMembership。它具有基于角色的用户菜单,大多数操作都是[Authorize(Roles =“aaa,bbb”)]属性。
在应用程序构建或使浏览器闲置一段时间后,用户将从任何单击的链接重定向到登录页面。奇怪的是,登录名仍然有效,但没有附加的角色名称。
在上述情况下,用户可以使用[授权]属性访问操作。我想知道是否有任何我遗漏的内容,或者只要认证有效,我就能保持角色信息的存在?
以下是控制器操作中用于呈现菜单的代码:
public ActionResult Menu() { if (Roles.IsUserInRole("Admin")) { return View("MenuAdmin"); } if (Roles.IsUserInRole("Advising")) { return View("MenuAdvising"); } if (Roles.IsUserInRole("StudentDevelopment")) { return View("MenuStudentDevelopment"); }...
自定义_logonPartial以显示登录名和角色
> @if (Request.IsAuthenticated) {
<text>
Logged in: @Html.ActionLink(User.Identity.Name, "Manage", "Account", routeValues: null, htmlAttributes: new { @class = "username", title = "Manage" }) as
@String.Join(",", Roles.GetRolesForUser(User.Identity.Name))
@using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm" })) {
@Html.AntiForgeryToken()
<a href="javascript:document.getElementById('logoutForm').submit()">Log off</a>
}
</text>
答案 0 :(得分:1)
只要用户已登录,角色信息就可用。在您的情况下,您正在呼叫:
Roles.GetRolesForUser(User.Identity.Name)
获取角色列表。这实际上命中数据库以获取角色,因此只要我们用户名在Identity中可用,它将返回角色,假设用户已分配角色。如果用户身份验证,则用户名应该可用。您正在检查Request.IsAuthenticated。检查User.Identity.IsAuthenticated。
可能更好有一种方法可以在不使用声明查询数据库的情况下获取角色。一般来说,我不会在视图中放置这样的逻辑和访问系统变量。我会在我的控制器动作中使用这种方法来获得角色。
var prinicpal = (ClaimsPrincipal)Thread.CurrentPrincipal;
var roles = prinicpal.Claims.Where(c => c.Type == ClaimTypes.Role).Select(c => c.Value);
ViewBag.Roles = roles;
将您需要的信息放在ViewBag中,或者创建一个传递给View的模型。这种获取角色的方法不需要往返数据库。
更新地址评论
MVC 4的标准AuthorizeAttribute使用配置的成员资格和角色提供程序(在您的情况下为SimpleMembership)来获取角色。它不会假设使用的声明,因此每次都会进入数据库。实际上,它必须两次访问数据库,一次获取登录用户的用户ID,然后根据该用户ID获取角色。不是很有效率。令人惊讶的是,即使您没有将任何角色作为参数传递,它也不会根据角色授权用户并且只需要进行身份验证即可。我用剖析器验证了这一点。
为了提高效率并且不需要访问数据库,您可以编写自定义AuthorizeAttribute以使用声明。 Here is an article that describes how to do this,包含示例源代码的链接。
我无法解释您所描述的情景,这种情况发生在构建之后。但是,如果您创建自定义属性并使用它,您将能够调试并查看到底发生了什么。此外,我不会过分担心它,因为它不应该是您在生产中看到的典型情况。