这是我的版本,基于@CalebHC 和@Lee Harold 的回答。
我遵循了在属性中使用命名参数的风格并覆盖了基类Roles
属性。
@CalebHC 的答案使用了一个Is
我认为不必要的新属性,因为AuthorizeCore()
它被覆盖(在基类中使用角色),所以使用我们自己的也是有意义的Roles
。通过使用我们自己的Roles
,我们可以在控制器上编写Roles = Roles.Admin
,它遵循其他 .Net 属性的样式。
我使用了两个构造函数来CustomAuthorizeAttribute
显示传入的真实活动目录组名称。在生产中,我使用参数化构造函数来避免类中的魔术字符串:组名称在创建期间从 web.config 中提取,Application_Start()
并在创建时使用 DI 传入工具。
您的文件夹NotAuthorized.cshtml
中需要一个或类似Views\Shared
文件,否则未经授权的用户将收到错误屏幕。
这是基类AuthorizationAttribute.cs的代码。
控制器:
public ActionResult Index()
{
return this.View();
}
[CustomAuthorize(Roles = Roles.Admin)]
public ActionResult About()
{
return this.View();
}
自定义授权属性:
// The left bit shifting gives the values 1, 2, 4, 8, 16 and so on.
[Flags]
public enum Roles
{
Admin = 1,
User = 1 << 1
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
private readonly string adminGroupName;
private readonly string userGroupName;
public CustomAuthorizeAttribute() : this("Domain Admins", "Domain Users")
{
}
private CustomAuthorizeAttribute(string adminGroupName, string userGroupName)
{
this.adminGroupName = adminGroupName;
this.userGroupName = userGroupName;
}
/// <summary>
/// Gets or sets the allowed roles.
/// </summary>
public new Roles Roles { get; set; }
/// <summary>
/// Checks to see if the user is authenticated and has the
/// correct role to access a particular view.
/// </summary>
/// <param name="httpContext">The HTTP context.</param>
/// <returns>[True] if the user is authenticated and has the correct role</returns>
/// <remarks>
/// This method must be thread-safe since it is called by the thread-safe OnCacheAuthorization() method.
/// </remarks>
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
{
throw new ArgumentNullException("httpContext");
}
if (!httpContext.User.Identity.IsAuthenticated)
{
return false;
}
var usersRoles = this.GetUsersRoles(httpContext.User);
return this.Roles == 0 || usersRoles.Any(role => (this.Roles & role) == role);
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
filterContext.Result = new ViewResult { ViewName = "NotAuthorized" };
}
private IEnumerable<Roles> GetUsersRoles(IPrincipal principal)
{
var roles = new List<Roles>();
if (principal.IsInRole(this.adminGroupName))
{
roles.Add(Roles.Admin);
}
if (principal.IsInRole(this.userGroupName))
{
roles.Add(Roles.User);
}
return roles;
}
}