首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >ASP.NET MVC -角色提供者的替代方案?

ASP.NET MVC -角色提供者的替代方案?
EN

Stack Overflow用户
提问于 2011-01-29 21:26:23
回答 4查看 16.4K关注 0票数 47

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

所谓更易管理/更灵活,我的意思是我只能使用Roles静态类,而不是直接实现到与数据库上下文交互的服务层中,相反,我必须使用Roles静态类,它有自己的数据库上下文等等,而且表名也很糟糕。

提前谢谢。

EN

回答 4

Stack Overflow用户

发布于 2011-06-17 23:20:00

我在这里实现了一个基于@TheCloudlessSky帖子的角色提供者。我认为我可以添加和分享我所做的事情的事情很少。首先,如果您希望将动作过滤器的RequirepPermission类用作属性,则需要为RequirepPermission类实现ActionFilterAttribute类。

接口类IAuthenticationServiceIAuthorizationService

代码语言:javascript
复制
public interface IAuthenticationService
{
    void SignIn(string userName, bool createPersistentCookie);
    void SignOut();
}

public interface IAuthorizationService
{
    bool Authorize(UserSession user, string[] requiredRoles);
}

FormsAuthenticationService

代码语言:javascript
复制
/// <summary>
/// This class is for Form Authentication
/// </summary>
public class FormsAuthenticationService : IAuthenticationService
{

    public void SignIn(string userName, bool createPersistentCookie)
    {
        if (String.IsNullOrEmpty(userName)) throw new ArgumentException(@"Value cannot be null or empty.", "userName");

        FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
    }

    public void SignOut()
    {
        FormsAuthentication.SignOut();
    }
}

UserSession

代码语言:javascript
复制
public class UserSession
{
    public string UserName { get; set; }
    public IEnumerable<string> UserRoles { get; set; }
}

另一个要点是FormsAuthorizationService类,以及如何将用户分配给httpContext.Session["CurrentUser"]。在这种情况下,我的方法是创建一个userSession类的新实例,并将httpContext.User.Identity.Name中的用户直接分配给userSession变量,如FormsAuthorizationService类中所示。

代码语言:javascript
复制
[AttributeUsageAttribute(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method, Inherited = false)]
public class RequirePermissionAttribute : ActionFilterAttribute, IAuthorizationFilter
{
    #region Fields

    private readonly IAuthorizationService _authorizationService;
    private readonly string[] _permissions;

    #endregion

    #region Constructors

    public RequirePermissionAttribute(string requiredRoles)
    {
        _permissions = requiredRoles.Trim().Split(',').ToArray();
        _authorizationService = null;
    }

    #endregion

    #region Methods

    private IAuthorizationService CreateAuthorizationService(HttpContextBase httpContext)
    {
        return _authorizationService ?? new FormsAuthorizationService(httpContext);
    }

    public void OnAuthorization(AuthorizationContext filterContext)
    {
        var authSvc = 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.
        if (filterContext.HttpContext.Session == null) return;
        if (filterContext.HttpContext.Request == null) return;
        var success = false;
        if (filterContext.HttpContext.Session["__Roles"] != null)
        {
            var rolesSession = filterContext.HttpContext.Session["__Roles"];
            var roles = rolesSession.ToString().Trim().Split(',').ToList();
            var userSession = new UserSession
            {
                UserName = filterContext.HttpContext.User.Identity.Name,
                UserRoles = roles
            };
            success = authSvc.Authorize(userSession, _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 = OnCacheAuthorization(new HttpContextWrapper(context));
                                                }, null);
            }
            else
            {
                HandleUnauthorizedRequest(filterContext);
            }
    }

    private static 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();
        }
    }

    private HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext)
    {
        var authSvc = CreateAuthorizationService(httpContext);
        if (httpContext.Session != null)
        {
            var success = false;
            if (httpContext.Session["__Roles"] != null)
            {
                var rolesSession = httpContext.Session["__Roles"];
                var roles = rolesSession.ToString().Trim().Split(',').ToList();
                var userSession = new UserSession
                {
                    UserName = httpContext.User.Identity.Name,
                    UserRoles = roles
                };
                success = authSvc.Authorize(userSession, _permissions);
            }
            return success ? HttpValidationStatus.Valid : HttpValidationStatus.IgnoreThisRequest;
        }
        return 0;
    }

    #endregion
}

internal class FormsAuthorizationService : IAuthorizationService
{
    private readonly HttpContextBase _httpContext;

    public FormsAuthorizationService(HttpContextBase httpContext)
    {
        _httpContext = httpContext;
    }

    public bool Authorize(UserSession userSession, string[] requiredRoles)
    {
        return userSession.UserRoles.Any(role => requiredRoles.Any(item => item == role));
    }
}

然后在您的控制器中,在用户通过身份验证后,您可以从数据库中获取角色,并将其分配给角色会话:

代码语言:javascript
复制
var roles = Repository.GetRolesByUserId(Id);
if (ControllerContext.HttpContext.Session != null)
   ControllerContext.HttpContext.Session.Add("__Roles",roles);
FormsService.SignIn(collection.Name, true);

用户从系统注销后,您可以清除会话

代码语言:javascript
复制
FormsService.SignOut();
Session.Abandon();
return RedirectToAction("Index", "Account");

此模型中的警告是,当用户登录到系统时,如果为用户分配了角色,则除非用户注销并重新登录系统,否则授权将不起作用。

另一件事是,角色不需要单独的类,因为我们可以直接从数据库中获取角色,并将其设置为控制器中的角色会话。

完成所有这些代码的实现后,最后一步是将此属性绑定到控制器中的方法:

代码语言:javascript
复制
[RequirePermission("Admin,DM")]
public ActionResult Create()
{
return View();
}
票数 5
EN

Stack Overflow用户

发布于 2011-06-18 08:52:45

如果您使用Castle Windsor依赖注入,则可以注入RoleProviders列表,这些列表可用于确定您选择实现的任何来源的用户权限。

http://ivida.co.uk/2011/05/18/mvc-getting-user-roles-from-multiple-sources-register-and-resolve-arrays-of-dependencis-using-the-fluent-api/

票数 2
EN

Stack Overflow用户

发布于 2011-01-29 21:58:05

您不需要为角色使用静态类。例如,SqlRoleProvider允许您定义数据库中的角色。

当然,如果您想从您自己的服务层检索角色,那么创建您自己的角色提供程序并不是那么困难--实际上并没有那么多方法可以实现。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4837103

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档