ASP.NET MVC - 替代角色提供? [英] ASP.NET MVC - Alternative to Role Provider?

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

问题描述

我试图避免使用,因为在我看来,它太笨拙的角色提供及会员提供的,因此,我试图让我自己的版本,这是少笨拙和更易于管理/灵活。现在是我的问题..有角色提供这是体面的选择吗? (我知道我可以做自定义角色provier,会员供应商等。)

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.)

通过更易于管理/灵活我的意思是我有限的使用角色静态类,而不是直接落实到其与数据库交互的情况下我的服务层,而不是我一定要使用的角色有静态类,其自己的数据库环境等,也表名是可怕的。

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);
}

然后,您的用户可以有一个角色枚举:

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 /验证服务或者在更多的细节,从这里去,让我知道。

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);
}

然后您的视图(使用剃刀这里语法)内:

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天全站免登陆