我有一个Windows身份验证MVC应用程序需要用户名进行查找以确定链接是否可见并设置授权。注意:我也可以使用角色进行可见性/授权。
我需要用户名,所以我目前正在使用OnAuthentification(不确定这是不是正确的地方)。我正在拼接用户名以将其放在主页上并说欢迎,用户。 (演示目的)
[Authorize]
public abstract class ApplicationController : Controller
{
public static bool IsApprover;
protected override void OnAuthentication(AuthenticationContext filterContext)
{
base.OnAuthentication(filterContext);
if (filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated == true)
{
string userName = User.Identity.Name.Remove(0, 16).Replace('.', ' ').ToLower();
HttpContext.Application["UserName"] = TitleCase(userName, "Nothing");
//Initialize Values
HttpContext.Application["IsApprover"] = false; //used for link visibility
IsApprover = false; //used for Authorization
//do db lookup and set IsApprover values
}
}
}
所以,我设置了上面的值。我不包括实体框架代码只是为了简短。以上工作正常,每个控制器都继承自ApplicationController。
我也有
public class CustomAuthorizationValue : AuthorizeAttribute
{
private bool localIsAllowed;
public CustomAuthorizationValue(bool isAllowed)
{
localIsAllowed = isAllowed;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext.Request.IsLocal)
{
var authorized = base.AuthorizeCore(httpContext);
if (!authorized)
{
// The user is not authorized => no need to go any further
return false;
}
return localIsAllowed;
}
return false;
}
}
对于授权,我使用:
[CustomAuthorizationValue(IsApprover)]
public ActionResult Approve()
{
//code
}
对于Razor中的可见性,我使用
@if((bool)@HttpContext.Current.Application["IsApprover"] == true)
{
<li><a href="@Url.Action("Approve", "Approve")">Approve (@HttpContext.Current.Application["ApproveCount"])</a></li>
}
这很好但我有2个不同的变量可供使用, 一个用于可见性(HttpContext.Current.Application [&#34; IsApprover&#34;]) 和 一个用于授权(IsApprover)。
有更优雅的解决方案吗?
是否有其他地方可以放置代码而不是覆盖void OnAuthentication?
有没有办法可以设置1个变量用于可见性和授权而不是2?
这是最好的做法还是我离开了?
答案 0 :(得分:1)
以上工作正常,每个控制器都继承自 ApplicationController中。
Hmmmm。您正在将用户特定信息信息存储在错误的范围内:
HttpContext.Application["UserName"] = TitleCase(userName, "Nothing");
HttpContext.Application["IsApprover"] = false;
在ASP.NET中,应用程序范围由您网站的所有用户共享。所以这里有一个并发问题。
您应该使用HTTP Context范围:
HttpContext.Items["UserName"] = TitleCase(userName, "Nothing");
HttpContext.Items["IsApprover"] = false;
有更优雅的解决方案吗?
您可以使用视图模型:
public class MyViewModel
{
public string UserName { get; set; }
public bool IsApprover { get; set; }
}
然后有几种扩展方法可以更轻松地工作:
public static class HttpContextExtensions
{
private const string MyViewModelKey = "__MyViewModel__";
public static MyViewModel GetMyViewModel(this HttpContextBase context)
{
return (MyViewModel)context.Items[MyViewModelKey];
}
public static void SetMyViewModel(this HttpContextBase context, MyViewModel model)
{
context.Items[MyViewModelKey] = model;
}
}
然后使用这些扩展方法:
if (filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated)
{
string userName = User.Identity.Name.Remove(0, 16).Replace('.', ' ').ToLower();
bool isApprover = ... do db lookup and set IsApprover value
var model = new MyViewModel
{
UserName = TitleCase(userName, "Nothing"),
IsApprover = isApprover,
}
this.HttpContext.SetMyViewModel(model);
}
并在您看来:
@if(HttpContext.GetMyViewModel().IsApprover)
{
<li>
<a href="@Url.Action("Approve", "Approve")">
Approve (@HttpContext.Current.Application["ApproveCount"])
</a>
</li>
}
注意:在此锚文本中,您似乎再次使用应用程序范围来存储用户特定信息,例如我们之前讨论过的ApproveCount
。
这是最好的做法还是我离开了?
好吧,我可能会使用基于声明的身份验证,并将此信息(IsApprover,...)存储为当前用户的声明。