2013-04-12 21:29 107人阅读 收藏 举报
昨天做了一个例子,是在Mvc4下,对于不同的用户角色(Roles),可以访问不同的页面。根据MVC3中的方式,只需要在相应的Controller上添加上类似于[Authorize(Roles="Admin")]这样的描述就行。后来通过测试发现,如果单独使用[Authorize]或者使用[Authorize(User="xxx")]都是可以的,但是一旦使用[Authorize(Roles="xxx")],就会报数据库连接错误:在 与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误。未找到或无法访问服务器。请验证实例名称是否正确并且 SQL Server 已配置为允许远程连接。 (provider: SQL Network Interfaces, error: 26 - 定位指定的服务器/实例时出错)。在网上查了好多资料,都无法解决,后来我决定自定义AuthorizeAttribute。
首先,应该定义角色,以及用户和角色的对应关系:
- public enum Roles
- {
- Admin,
- PowerManager,
- User,
- Guest
- }
-
- public class RolesManager
- {
- public static List<Roles> GetRoles(string userName)
- {
- switch (userName)
- {
- case "admin":
- return new List<Roles> {Roles.Admin, Roles.PowerManager};
- case "gqq":
- return new List<Roles> {Roles.Admin};
- default:
- return new List<Roles> {Roles.Guest};
- }
- }
-
- }
其次,在登录的时候,就应该把用户的组信息写到验证Cookie中去。
- <span style="white-space:pre"> </span>[HttpPost]
- [AllowAnonymous]
- [ValidateAntiForgeryToken]
- public ActionResult Login(LoginModel model, string returnUrl)
- {
-
- if (ModelState.IsValid && AccountBiz.Login(model.UserName, model.Password))
- {
-
- var roles = string.Join(",", RolesManager.GetRoles(model.UserName).ToArray());
-
- FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1,
-
- model.UserName,
- DateTime.Now,
- DateTime.Now.AddMinutes(20),
- false,
- roles
- );
-
- string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
-
-
- var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
- System.Web.HttpContext.Current.Response.Cookies.Add(authCookie);
-
- if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
- && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
- {
- return Redirect(returnUrl);
- }
- return RedirectToAction("Index", "Home");
- }
-
-
-
- ModelState.AddModelError("", "提供的用户名或密码不正确。");
- return View(model);
- }
第三步:自定义继承自AuthorizeAttribute的类ManagerOnlyAttribute,重写AuthorizeCore方法改变验证规则。
- public class ManagerOnlyAttribute : AuthorizeAttribute
- {
-
- protected override bool AuthorizeCore(HttpContextBase httpContext)
- {
-
- HttpCookie authCookie = httpContext.Request.Cookies[FormsAuthentication.FormsCookieName];
-
- if (authCookie == null || authCookie.Value == "")
- {
- return false;
- }
- FormsAuthenticationTicket authTicket;
- try
- {
-
- authTicket = FormsAuthentication.Decrypt(authCookie.Value);
- }
- catch
- {
- return false;
- }
-
- if (authTicket != null)
- {
-
- var userRoles = authTicket.UserData.Split(new[] {','}).ToList();
- var roles = Roles.Split(new[] {','}).ToList();
- return roles.Any(x => userRoles.Contains(x));
- }
- return false;
-
- }
-
- }
第四步:将自定义的属性描述加在需要访问的Controller或Action上。
- <strong> </strong>[ManagerOnly(Roles = "Admin,PowerManager")]
- public partial class MusicStoreController : Controller
- {<span style="font-family: Arial, Helvetica, sans-serif;">}</span>
当我们以admin用户登录,访问http://localhost:8090/MusicStore时,由于admin用户既属于Admin组,也属于PowerManager组,所以可以访问。如果以gqq登录,由于gqq属于Admin组,因此也可以访问该链接(属于Admin、PowerManager中的任意一个组即可)。如果以test用户登录,则该链接不可以访问。(根据上文代码,test属于Guest组)
|
请发表评论