MVC站点有一定要求的细粒度权限我不喜欢内置的会员提供程序。我决定自己做。我正在尝试想出一种在操作级别执行授权的好方法。以下是我要求的要求:属性使用-我喜欢这个,因为它在调用堆栈中的控制非常高,是组织权限的好地方。没有神奇的字符串-这就是我偏离当前角色提供者的原因。我不想留下不容易重命名的字符串。一个权限应该由另一个权限组成。示例:ReadWrite具有读取权限。就像或与枚举一样。注意:有些人认为这套要求过于宽泛(见评论)。我不这么认为,我认为它们相当简单。最大的障碍是属性的使用。只能有“属性参数类型的常量表达式、typeof表达式或数组创建表达式”。我想也许有这样的东西可以让动作静态访问。在属性内部,它将“转换”为实际的权限或...:publicstaticclassOperations{publicstaticclassSectionA{publicconstintRead=1;公共常量intReadWrite=2;}publicstaticclassSectionB{//...等等...}}但是确实限制了组合。我确定您在想“为什么不走枚举路线?”好吧,我想计划改变的事情,不想被限制在32(int)或64(long)操作,并且以后必须做很多重写(还有db,它只是丑陋)。另外,如果有比动作/控制器上的属性更好的选择,那么我会全力以赴。编辑:也是从这篇文章中,我读到了BitArray类。它看起来有点难看,尤其是对于数据库中的任意存储。首先,我要感谢你吸引我回答这个问题;)这是一个很长的答案,只是一个起点。您必须弄清楚如何为用户分配角色以及如何在AuthenticateRequest中重新创建它们。如果这不能回答您的问题,我希望它能给您带来启发。请享用!装饰控制器动作我首先在默认的HomeController中装饰这两个动作:返回视图();}[AuthorizeRoles(Role.Write)]publicActionResultAbout(){returnView();然后,应授予ReadWrite角色中的所有用户访问权限。我在这里选择使用枚举作为魔术字符串的类型安全占位符。这个枚举只不过是一个占位符。没有必须在其他地方维护的复合枚举值。稍后会详细介绍。publicenumRole{Read,Write,ReadWrite}实现新的授权属性由于字符串不见了,我需要一个新的授权属性:publicclassAuthorizeRolesAttribute:AuthorizeAttribute{privatereadonlyRoleSetauthorizedRoles;publicAuthorizeRolesAttribute(paramsRole[]roles){authorizedRoles=newRoleSet(roles);}protectedoverrideboolAuthorizeCore(HttpContextBasehttpContext){returnauthorizedRoles.Includes(httpContext.User);}}RoleSet包装了一组枚举值,并验证IPrincipal是否是其中一个成员:}publicboolIncludes(IPrincipaluser){returnNames.Any(user.IsInRole);}publicboolIncludes(stringrole){returnNames.Contains(role);}公共IEnumerable名称{得到;私有集;}}保留角色CompositeRoleSet是注册和处理复合角色的地方。CreateDefault()是注册所有复合材料的地方。Resolve()将采用角色列表(枚举值)并将组合转换为单个对应物。公共类CompositeRoleSet{publicstaticCompositeRoleSetCreateDefault(){varset=newCompositeRoleSet();set.Register(Role.ReadWrite,Role.Read,Role.Write);返回集;}privatereadonlyDictionarycompositeRoles=newDictionary();privatevoidRegister(Rolecomposite,paramsRole[]contains){compositeRoles.Add(composite,contains);}publicRoleSetResolve(paramsRole[]roles){returnnewRoleSet(roles.SelectMany(Resolve));}privateIEnumerableResolve(Rolerole){Role[]roles;if(compositeRoles.TryGetValue(role,outroles)==false){roles=new[]{role};}返回角色;要连接它,我们需要通过身份验证,只有经过身份验证的用户才能使用它。我在global.asax中进行了欺骗和硬编码:publicMvcApplication(){AuthenticateRequest+=OnAuthenticateRequest;}privatevoidOnAuthenticateRequest(objectsender,EventArgseventArgs){varallRoles=CompositeRoleSet.CreateDefault();varroles=allRoles.Resolve(.ReadWrite);Context.User=newApplicationUser(角色);最后,我们需要一个知道所有这些的IPrincipal:publicclassApplicationUser:IPrincipal{privatereadonlyRoleSetroles;publicApplicationUser(RoleSetroles){this.roles=roles;}publicboolIsInRole(stringrole){returnroles.Includes(role);}publicIIdentityIdentity{get{returnnewGenericIdentity("User");}}}似乎你想要一些非常灵活的东西,不需要安全检查所需的东西。所以,这取决于“你准备了多远”。为了朝着正确的方向前进,我强烈建议您看一下基于声明的访问控制方面。并使用本文作为起点和ASP.NETMVC示例。但请记住,这是一个复杂的话题。非常灵活(甚至允许在不更改任何代码的情况下进行联合访问控制)但很复杂。我们必须以这样一种方式来做到这一点,即我们的应用程序对于那些“正确检查”的实现是完全不可用的。我们所有的系统都知道他们需要执行特定操作的“声明”,并根据提供的用户身份请求它(这也是一个“声明”)。角色、权限和其他声明可以很容易地“翻译”成对我们的应用程序有意义的特定于应用程序的“声明”。完全灵活。PS它并没有解决像“魔术字符串”这样的技术问题(你必须认为这取决于你的情况),而是给你一个非常灵活的访问控制架构。所以@thomas似乎有一个很好的答案,但它包含了更多使用枚举的要求,使其成为IPricipal可以理解的角色。我的解决方案是自下而上的,因此您可以在我的IPrincipal之上使用thomas的解决方案我真的需要类似于您想要的东西并且总是害怕使用Forms身份验证(是的,我知道您也很害怕,但请听我说out)所以我一直使用表单进行廉价的身份验证,但是随着我学习mvc,(在过去几周)发生了很多变化。Formsauth非常独立且非常灵活。基本上您并没有真正使用表单身份验证,而只是将您自己的逻辑插入到系统中。所以这就是我解决这个问题的方法,(请注意,我自己也是一个学习者)。摘要:您将重写一些表单身份验证类来验证您自己的用户(您甚至可以模拟它),然后您将创建一个IIdentity。您使用字符串中的角色列表加载GenericPrincipal(我知道,没有神奇的字符串......继续阅读)完成上述操作后,MVC足以知道您想要什么!您现在可以在任何控制器上使用[Authorize(Roles="Write,Read")],MVC几乎可以完成所有工作。现在没有神奇的字符串,您只需要在属性周围创建一个包装器。长答案你使用MVC自带的InternetApplication模板,所以首先你创建MVC项目,在新的对话框中,说你想要一个InternetApplication。检查应用程序时,它将有一个覆盖表单身份验证的主类。IMembershipService移除了本地MembershipProvider变量__provider_,在这个类中你至少应该在ValidateUser方法中添加逻辑。(尝试向一个用户/通行证添加虚假身份验证)另请参阅在VS中创建的默认v测试应用程序。实施IIdentitypublicclassMyIdentity:IIdentity{publicMyIdentity(stringusername){_username=username;//这里来自数据库的auth。//从数据库或其他任何地方加载角色}string_username;公共用户用户数据{得到;放;}#regionIIdentityMemberspublicstringAuthenticationType{get{return"MyOwn.Authentication";}}publicboolIsAuthenticated{get{returntrue;}}publicstringName{get{return_username;}}#endregionpublicstring[]Roles{get{return//从你的Db或其他东西中获取角色列表作为字符串。}}}请记住,我们仍在使用MVC项目附带的默认Internet应用程序模板。所以现在AccountController.LogOn()应该看起来像这样:FormsService.SignIn(model.UserName,model.RememberMe);FormsAuthenticationTicketticket=newFormsAuthenticationTicket(model.UserName,model.RememberMe,15);字符串encTicket=FormsAuthentication.Encrypt(ticket);this.Response.Cookies.Add(newHttpCookie(FormsAuthentication.FormsCookieName,encTicket));如果(Url.IsLocalUrl(returnUrl)){returnRedirect(returnUrl);}else{returnRedirectToAction("Index","Home");}}else{ModelState.AddModelError("","提供的用户名或密码不正确。");所以你正在做的是像会话一样设置表单票证,然后我们将在每个请求中读取它:将它放在Global.asax中。publicoverridevoidInit(){this.PostAuthenticateRequest+=newEventHandler(MvcApplication_PostAuthenticateRequest);基地.初始化();无效MvcApplication_PostAuthent在csicateRequest(objectsender,EventArgse){HttpCookieauthCookie=HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];if(authCookie!=null){stringencTicket=authCookie.Value;如果(!String.IsNullOrEmpty(encTicket)){FormsAuthenticationTicketticket=FormsAuthentication.Decrypt(encTicket);MyIdentityid=newMyIdentity(ticket.Name);//这里是魔法发生的地方!!GenericPrincipalprin=newGenericPrincipal(id,id.Roles);HttpContext.Current.User=原则;我问了一个关于上述方法的有效性和正确性的问题,现在你差不多完成了,你可以像这样装饰你的控制器:[Authorize(Roles="RoleA,RoleB")](更多关于字符串稍后)这里有一个小问题,如果你用AuthorizeAttribute装饰你的控制器,并且登录的用户没有特定的权限,而不是默认说“拒绝访问”,用户将被重定向到登录页面重新登录。你解决了这个问题(我从SO答案中改编了这个):publicclassRoleAuthorizeAttribute:AuthorizeAttribute{protectedoverridevoidHandleUnauthorizedRequest(AuthorizationContextfilterContext){//返回HTTP401//如果用户没有登录提示if(!filterContext.HttpContext.User.Identity.IsAuthenticated){base.HandleUnauthorizedRequest(filterContext);}//否则拒绝访问else{filterContext.Result=newRedirectToRouteResult(@"Default",newRouteValueDictionary{{"controller","Account"},{"action","NotAuthorized"}});现在您只需要在AuthorizeAttribute周围添加另一个包装器以支持将转换为Principal期望的字符串的强类型。有关更多信息,请参阅此帖子我计划稍后更新我的应用程序以使用强类型,然后我将更新此答案。我希望它有所帮助。以上就是C#学习教程:对MVC站点有一定要求的详细权限分享的全部内容。如果对大家有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,并不代表侵权,如有侵权,请点击右边联系管理员删除。如需转载请注明出处:
