创建AuthorizeAttribute - 我需要知道什么?

Onl*_*ere 13 roles asp.net-mvc-3

这是我的要求:

  • 我将为N个角色添加用户; 在数据库中定义.

  • 我需要使用authorize属性保护每个控制器操作.

例如,Web应用程序将检查登录用户是否属于这两个角色中的任何一个,如果他们这样做,我让他们进入.如何告诉Authorize属性从我选择的数据库表中获取用户角色?

 [Authorize(Roles = "Admin, Technician")]
 public ActionResult Edit(int id)
 {
     return View();
 }
Run Code Online (Sandbox Code Playgroud)

我已经尝试使用谷歌搜索许多不同的页面,但似乎没有一个符合我需要的东西,而且过于复杂.

如果官方文档有我喜欢的东西,因为我没有看到任何我可以使用的东西.

有什么建议?

例如,这个问题有一个非常干净的答案,但我不知道它是完整的还是缺少一些重要的东西.

ASP.NET MVC3角色和权限管理 - >使用运行时权限分配


编辑

我真正想要的是创建自定义角色提供程序,对吗?我是否需要实现此类并将其用作我的角色提供程序?我对此很新,有什么想法吗?

http://msdn.microsoft.com/en-us/library/8fw7xh74.aspx

Cia*_*uen 10

在过去的几周里,我经历了几乎相同的情况,所以这可能会帮助其他人在同一条船上.我的场景是公司内部网上的MVC4应用程序,用户存储在Active Directory中.这允许Windows身份验证提供单点登录,因此无需进行Forms身份验证.角色存储在Oracle数据库中.我有3个角色:

  • Readonly:所有用户都需要成为此成员才能访问该应用程序
  • 用户:创建新的resords
  • 管理员:编辑和删除记录

我决定使用asp.net角色提供程序api来创建自己的AccountRoleProvider.到目前为止,我只需要使用2个方法,GetRolesForUser和IsUserInRole:

public class AccountRoleProvider : RoleProvider // System.Web.Security.RoleProvider
{
    private readonly IAccountRepository _accountRepository;

    public AccountRoleProvider(IAccountRepository accountRepository)
    {
        this._accountRepository = accountRepository;
    }

    public AccountRoleProvider() : this (new AccountRepository())
    {}

    public override string[] GetRolesForUser(string user521)
    {
        var userRoles = this._accountRepository.GetRoles(user521).ToArray();

        return userRoles;
    }

    public override bool IsUserInRole(string username, string roleName)
    {
        var userRoles = this.GetRolesForUser(username);

        return Utils.IndexOfString(userRoles, roleName) >= 0;
    }
}
Run Code Online (Sandbox Code Playgroud)

我更新了web.config以使用我的角色提供程序:

<authentication mode="Windows" />
<roleManager enabled="true" defaultProvider="AccountRoleProvider">
  <providers>
    <clear/>
    <add name="AccountRoleProvider"
         type="MyApp.Infrastructure.AccountRoleProvider" />
  </providers>
</roleManager>
Run Code Online (Sandbox Code Playgroud)

然后我从AuthorizeAttribute,ReadOnlyAuthorize和CustomAuthorize创建了2个自定义属性.

ReadonlyAuthorize:

public class ReadonlyAuthorize : AuthorizeAttribute
{
    private IAccountRepository _accountRepository;

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var user = httpContext.User;
        this._accountRepository = new AccountRepository();

        if (!user.Identity.IsAuthenticated)
        {
            return false;
        }

        // Get roles for current user
        var roles = this._accountRepository.GetRoles(user.Identity.Name);

        if (!roles.Contains("readonly"))
        {
            return false;
        }

        return base.AuthorizeCore(httpContext);
    }

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);

        if (filterContext.HttpContext.User.Identity.IsAuthenticated && filterContext.Result is HttpUnauthorizedResult)
        {
            filterContext.Result = new ViewResult { ViewName = "AccessDenied" };
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

CustomAuthorize:

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    public string RedirectActionName { get; set; }
    public string RedirectControllerName { get; set; }
    private IAccountRepository _accountRepository;

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var user = httpContext.User;
        this._accountRepository = new AccountRepository();
        var accessAllowed = false;

        // Get the roles passed in with the (Roles = "...") on the attribute
        var allowedRoles = this.Roles.Split(',');

        if (!user.Identity.IsAuthenticated)
        {
            return false;
        }

        // Get roles for current user
        var roles = this._accountRepository.GetRoles(user.Identity.Name);

        foreach (var allowedRole in allowedRoles)
        {
            if (roles.Contains(allowedRole))
            {
                accessAllowed = true;
            }
        }

        if (!accessAllowed)
        {
            return false;
        }

        return base.AuthorizeCore(httpContext);
    }

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);

        if (filterContext.HttpContext.User.Identity.IsAuthenticated && filterContext.Result is HttpUnauthorizedResult)
        {   
            var values = new RouteValueDictionary(new
            {
                action = this.RedirectActionName == string.Empty ? "AccessDenied" : this.RedirectActionName,
                controller = this.RedirectControllerName == string.Empty ? "Home" : this.RedirectControllerName
            });

            filterContext.Result = new RedirectToRouteResult(values);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

2个不同属性的原因是我使用一个用于所有用户必须成为其成员的Readonly角色才能访问该应用程序.我可以在Global.asax的RegisterGlobalFilters方法中添加它,这意味着它会自动应用到每个Controller:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute());
    filters.Add(new ReadonlyAuthorize());
}
Run Code Online (Sandbox Code Playgroud)

然后在CustomAuthorize中,我可以采用更细粒度的方法并指定我想要的角色并应用于Controller或单个Action,例如,我可以在Admin角色中限制对用户的Delete方法的访问:

[AccessDeniedAuthorize(RedirectActionName = "AccessDenied", RedirectControllerName = "Home", Roles = "Admin")]
public ActionResult Delete(int id = 0)
{
    var batch = myDBContext.Batches.Find(id);
    if (batch == null)
    {
        return HttpNotFound();
    }

    return View(batch);
}
Run Code Online (Sandbox Code Playgroud)

我需要采取进一步的步骤,例如使用当前用户所属的角色更新User对象.这将检索用户的角色,而不是每次都在我的自定义属性中,并且还使用User.IsInRole.在Gloal.asax中的Application_AuthenticateRequest中应该可以这样:

var roles = "get roles for this user from respository";

if (Context.User != null)
    Context.User = new GenericPrincipal(Context.User.Identity, roles);
Run Code Online (Sandbox Code Playgroud)


Ada*_*SFT 1

有很多方法可以处理这个问题。达林的方法和吹镖(都是非常熟练的人 - 其中一位也是安全作者)在您提供的链接中很不错。

需要注意的一件事是缓存。如果您使用服务器端输出缓存缓存,您可能会无意中为一个用户缓存一些返回给另一用户的内容。请参见:

MVC3 中的 OutputCache 和授权过滤器

使用 Azure 缓存(.NET MVC3 应用程序)时,为什么无法组合 [Authorize] 和 [OutputCache] 属性?

MVC 自定义身份验证、授权和角色实现

有关这方面的更多信息以及如果您使用授权属性如何处理缓存。