ASP.NET MVC - 角色提供程序的替代方案? [英] ASP.NET MVC - Alternative to Role Provider?

查看:24
本文介绍了ASP.NET MVC - 角色提供程序的替代方案?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图避免使用角色提供者和成员资格提供者,因为在我看来它太笨拙了,因此我试图制作我自己的版本",它不那么笨拙且更易于管理/灵活.现在是我的问题.. 是否有合适的角色提供者的替代方案?(我知道我可以自定义角色提供者、成员资格提供者等)

I'm trying to avoid the use of the Role Provider and Membership Provider since its way too clumsy in my opinion, and therefore I'm trying to making my own "version" which is less clumsy and more manageable/flexible. Now is my question.. is there an alternative to the Role Provider which is decent? (I know that I can do custom Role provier, membership provider etc.)

通过更易于管理/灵活,我的意思是我仅限于使用 Roles 静态类,而不是直接在与数据库上下文交互的服务层中实现,而是必须使用具有它的角色的静态类自己的数据库上下文等,表名也很糟糕..

By more manageable/flexible I mean that I'm limited to use the Roles static class and not implement directly into my service layer which interact with the database context, instead I'm bound to use the Roles static class which has its own database context etc, also the table names is awful..

提前致谢.

推荐答案

我和你在同一条船上 - 我一直讨厌 RoleProviders.是的,如果您想为小型网站启动和运行它们,它们非常棒,但它们不太现实.我一直发现的主要缺点是它们将您直接绑定到 ASP.NET.

I'm in the same boat as you - I've always hated the RoleProviders. Yeah, they're great if you want to get things up and running for a small website, but they're not very realistic. The major downside I've always found is that they tie you directly to ASP.NET.

我最近的一个项目的方法是定义几个作为服务层一部分的接口(注意:我对它们进行了相当多的简化 - 但您可以轻松地添加到它们中):

The way I went for a recent project was defining a couple of interfaces that are part of the service layer (NOTE: I simplified these quite a bit - but you could easily add to them):

public interface IAuthenticationService
{
    bool Login(string username, string password);
    void Logout(User user);
}

public interface IAuthorizationService
{
    bool Authorize(User user, Roles requiredRoles);
}

然后你的用户可以有一个 Roles 枚举:

Then your users could have a Roles enum:

public enum Roles
{
    Accounting = 1,
    Scheduling = 2,
    Prescriptions = 4
    // What ever else you need to define here.
    // Notice all powers of 2 so we can OR them to combine role permissions.
}

public class User
{
    bool IsAdministrator { get; set; }
    Roles Permissions { get; set; }
}

对于您的 IAuthenticationService,您可以有一个执行标准密码检查的基本实现,然后您可以有一个 FormsAuthenticationService 做更多的工作,例如设置 cookie等等.对于你的 AuthorizationService,你需要这样的东西:

For your IAuthenticationService, you could have a base implementation that does standard password checking and then you could have a FormsAuthenticationService that does a little bit more such as setting the cookie etc. For your AuthorizationService, you'd need something like this:

public class AuthorizationService : IAuthorizationService
{
    public bool Authorize(User userSession, Roles requiredRoles)
    {
        if (userSession.IsAdministrator)
        {
            return true;
        }
        else
        {
            // Check if the roles enum has the specific role bit set.
            return (requiredRoles & user.Roles) == requiredRoles;
        }
    }
}

在这些基本服务之上,您可以轻松添加服务以重置密码等.

On top of these base services, you could easily add services to reset passwords etc.

由于您使用的是 MVC,您可以使用 ActionFilter 在操作级别进行授权:

Since you're using MVC, you could do authorization at the action level using an ActionFilter:

public class RequirePermissionFilter : IAuthorizationFilter
{
    private readonly IAuthorizationService authorizationService;
    private readonly Roles permissions;

    public RequirePermissionFilter(IAuthorizationService authorizationService, Roles requiredRoles)
    {
        this.authorizationService = authorizationService;
        this.permissions = requiredRoles;
        this.isAdministrator = isAdministrator;
    }

    private IAuthorizationService CreateAuthorizationService(HttpContextBase httpContext)
    {
        return this.authorizationService ?? new FormsAuthorizationService(httpContext);
    }

    public void OnAuthorization(AuthorizationContext filterContext)
    {
        var authSvc = this.CreateAuthorizationService(filterContext.HttpContext);
        // Get the current user... you could store in session or the HttpContext if you want too. It would be set inside the FormsAuthenticationService.
        var userSession = (User)filterContext.HttpContext.Session["CurrentUser"];

        var success = authSvc.Authorize(userSession, this.permissions);

        if (success)
        {
            // Since authorization is performed at the action level, the authorization code runs
            // after the output caching module. In the worst case this could allow an authorized user
            // to cause the page to be cached, then an unauthorized user would later be served the
            // cached page. We work around this by telling proxies not to cache the sensitive page,
            // then we hook our custom authorization code into the caching mechanism so that we have
            // the final say on whether or not a page should be served from the cache.
            var cache = filterContext.HttpContext.Response.Cache;
            cache.SetProxyMaxAge(new TimeSpan(0));
            cache.AddValidationCallback((HttpContext context, object data, ref HttpValidationStatus validationStatus) =>
            {
                validationStatus = this.OnCacheAuthorization(new HttpContextWrapper(context));
            }, null);
        }
        else
        {
            this.HandleUnauthorizedRequest(filterContext);
        }
    }

    private void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        // Ajax requests will return status code 500 because we don't want to return the result of the
        // redirect to the login page.
        if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
        {
            filterContext.Result = new HttpStatusCodeResult(500);
        }
        else
        {
            filterContext.Result = new HttpUnauthorizedResult();
        }
    }

    public HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext)
    {
        var authSvc = this.CreateAuthorizationService(httpContext);
        var userSession = (User)httpContext.Session["CurrentUser"];

        var success = authSvc.Authorize(userSession, this.permissions);

        if (success)
        {
            return HttpValidationStatus.Valid;
        }
        else
        {
            return HttpValidationStatus.IgnoreThisRequest;
        }
    }
}

然后你可以装饰你的控制器动作:

Which you can then decorate on your controller actions:

[RequirePermission(Roles.Accounting)]
public ViewResult Index()
{
   // ...
}

这种方法的优点是你还可以使用依赖注入和 IoC 容器来连接东西.此外,您可以在多个应用程序(不仅仅是您的 ASP.NET 应用程序)中使用它.您将使用 ORM 来定义适当的架构.

The advantage of this approach is you can also use dependency injection and an IoC container to wire things up. Also, you can use it across multiple applications (not just your ASP.NET one). You would use your ORM to define the appropriate schema.

如果您需要有关 FormsAuthorization/Authentication 服务的更多详细信息或从这里开始,请告诉我.

If you need more details around the FormsAuthorization/Authentication services or where to go from here, let me know.

要添加安全修整",您可以使用 HtmlHelper 来完成.这可能需要更多……但你明白了.

To add "security trimming", you could do it with an HtmlHelper. This probably needs a little more... but you get the idea.

public static bool SecurityTrim<TModel>(this HtmlHelper<TModel> source, Roles requiredRoles)
{
    var authorizationService = new FormsAuthorizationService();
    var user = (User)HttpContext.Current.Session["CurrentUser"];
    return authorizationService.Authorize(user, requiredRoles);
}

然后在您的视图中(此处使用 Razor 语法):

And then inside your view (using Razor syntax here):

@if(Html.SecurityTrim(Roles.Accounting))
{
    <span>Only for accounting</span>
}

UserSession 看起来像这样:

public class UserSession
{
    public int UserId { get; set; }
    public string UserName { get; set; }
    public bool IsAdministrator { get; set; }
    public Roles GetRoles()
    {
         // make the call to the database or whatever here.
         // or just turn this into a property.
    }
}

这样,我们就不会在当前用户的会话中公开密码哈希和所有其他详细信息,因为它们在用户的会话生命周期中确实不需要.

This way, we don't expose the password hash and all other details inside the session of the current user since they're really not needed for the user's session lifetime.

这篇关于ASP.NET MVC - 角色提供程序的替代方案?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆