Asp.Net MVC 自定义授权不工作
Asp.Net MVC Custom Authorization Not Working
我正在处理一个 MVC 项目。我想使用自定义授权属性。首先,我在 this blog post 中使用了一个示例。
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
public string RolesConfigKey { get; set; }
protected virtual CustomPrincipal CurrentUser => HttpContext.Current.User as CustomPrincipal;
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (!filterContext.HttpContext.Request.IsAuthenticated) return;
var authorizedRoles = ConfigurationManager.AppSettings["RolesConfigKey"];
Roles = string.IsNullOrEmpty(Roles) ? authorizedRoles : Roles;
if (string.IsNullOrEmpty(Roles)) return;
if (CurrentUser == null) return;
if (!CurrentUser.IsInRole(Roles)) base.OnAuthorization(filterContext);
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (!filterContext.HttpContext.Request.IsAuthenticated) return;
}
}
我在我的基本控制器中使用这个自定义主体。
public class CustomPrincipal : IPrincipal
{
public CustomPrincipal(string userName) { this.Identity = new GenericIdentity(userName); }
public bool IsInRole(string userRoles)
{
var result = true;
var userRolesArr = userRoles.Split(',');
foreach (var r in Roles)
{
if (userRolesArr.Contains(r)) continue;
result = false;
break;
}
return result;
}
public IIdentity Identity { get; }
public string UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string[] Roles { get; set; }
}
在我的路由配置中,我的默认路由是 /Account/Index
用户登录操作所在的位置。这是帐户控制器索引操作。
[HttpPost, ValidateAntiForgeryToken]
public ActionResult Index(AccountViewModel accountModel)
{
var returnUrl = string.Empty;
if (!ModelState.IsValid) { return UnsuccessfulLoginResult(accountModel.UserName, ErrorMessages.WrongAccountInfo); }
var account = _accountService.CheckUser(accountModel.UserName, accountModel.Password);
if (account == null) return UnsuccessfulLoginResult(accountModel.UserName, ErrorMessages.WrongAccountInfo);
var roles = account.Roles.Select(r => r.RoleName).ToArray();
var principalModel = new CustomPrincipalModel
{
UserId = account.UserId,
FirstName = "FirstName",
LastName = "LastName",
Roles = roles
};
var userData = JsonConvert.SerializeObject(principalModel);
var ticket = new FormsAuthenticationTicket(1, account.UserId, DateTime.Now, DateTime.Now.AddMinutes(30), false, userData);
var encryptedTicket = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
Response.Cookies.Add(cookie);
SetCulture(account.DefaultCulture);
if (!Array.Exists(roles, role => role == "admin" || role == "user")) return UnsuccessfulLoginResult(accountModel.UserName, ErrorMessages.WrongAccountInfo);
if (roles.Contains("admin")) { returnUrl = Url.Action("Index", "Admin"); }
if (roles.Contains("user")) { returnUrl = Url.Action("Index", "Upload"); }
return SuccessfulLoginResult(accountModel.UserName, returnUrl);
}
如您所见,当用户处于管理员角色时,此操作会重定向用户 /Admin/Index
,否则 /Upload/Index
。但是在我登录后,用户具有用户角色并输入 /Admin/Index
,授权过滤器不起作用,用户可以访问管理页面。
虽然我已将此属性添加到 UploadController 和 AdminController,但仍会发生此错误。我该如何解决这个问题?
[CustomAuthorize(Roles = "user")]
public class UploadController : BaseController
[CustomAuthorize(Roles = "admin")]
public class AdminController : BaseController
您需要为您的用户添加声明,将此部分添加到您的方法中:
. . .
var roles = account.Roles.Select(r => r.RoleName).ToArray();
ClaimsIdentity identity = new ClaimsIdentity(DefaultAuthenticationTypes.ApplicationCookie);
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, accountModel.UserName));
roles.ToList().ForEach((role) => identity.AddClaim(new Claim(ClaimTypes.Role, role)));
identity.AddClaim(new Claim(ClaimTypes.Name, userCode.ToString()));
. . .
这些更改解决了问题。
在我的 CustomAuthorizeAttribute 中更改了这一行
if (!filterContext.HttpContext.Request.IsAuthenticated) return;
到
if (!filterContext.HttpContext.Request.IsAuthenticated) base.OnAuthorization(filterContext);
并删除了我从网络配置中读取允许角色的行。所以我的属性最终版本如下
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
protected virtual CustomPrincipal CurrentUser => HttpContext.Current.User as CustomPrincipal;
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (!filterContext.HttpContext.Request.IsAuthenticated) base.OnAuthorization(filterContext);
if (string.IsNullOrEmpty(Roles)) return;
if (CurrentUser == null) return;
if (!CurrentUser.IsInRole(Roles)) filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Error", action = "AccessDenied" }));
}
}
然后我添加了一个名为 ErrorController 的控制器,并在用户不在角色时重定向到此页面。
通过这些更改,我意识到我无法访问我的 /Account/Index
并向下面的操作添加了 [AllowAnonymous]
属性。
[AllowAnonymous]
public ActionResult Index() { return View(); }
[HttpPost, ValidateAntiForgeryToken, AllowAnonymous]
public ActionResult Index(AccountViewModel accountModel)
我正在处理一个 MVC 项目。我想使用自定义授权属性。首先,我在 this blog post 中使用了一个示例。
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
public string RolesConfigKey { get; set; }
protected virtual CustomPrincipal CurrentUser => HttpContext.Current.User as CustomPrincipal;
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (!filterContext.HttpContext.Request.IsAuthenticated) return;
var authorizedRoles = ConfigurationManager.AppSettings["RolesConfigKey"];
Roles = string.IsNullOrEmpty(Roles) ? authorizedRoles : Roles;
if (string.IsNullOrEmpty(Roles)) return;
if (CurrentUser == null) return;
if (!CurrentUser.IsInRole(Roles)) base.OnAuthorization(filterContext);
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (!filterContext.HttpContext.Request.IsAuthenticated) return;
}
}
我在我的基本控制器中使用这个自定义主体。
public class CustomPrincipal : IPrincipal
{
public CustomPrincipal(string userName) { this.Identity = new GenericIdentity(userName); }
public bool IsInRole(string userRoles)
{
var result = true;
var userRolesArr = userRoles.Split(',');
foreach (var r in Roles)
{
if (userRolesArr.Contains(r)) continue;
result = false;
break;
}
return result;
}
public IIdentity Identity { get; }
public string UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string[] Roles { get; set; }
}
在我的路由配置中,我的默认路由是 /Account/Index
用户登录操作所在的位置。这是帐户控制器索引操作。
[HttpPost, ValidateAntiForgeryToken]
public ActionResult Index(AccountViewModel accountModel)
{
var returnUrl = string.Empty;
if (!ModelState.IsValid) { return UnsuccessfulLoginResult(accountModel.UserName, ErrorMessages.WrongAccountInfo); }
var account = _accountService.CheckUser(accountModel.UserName, accountModel.Password);
if (account == null) return UnsuccessfulLoginResult(accountModel.UserName, ErrorMessages.WrongAccountInfo);
var roles = account.Roles.Select(r => r.RoleName).ToArray();
var principalModel = new CustomPrincipalModel
{
UserId = account.UserId,
FirstName = "FirstName",
LastName = "LastName",
Roles = roles
};
var userData = JsonConvert.SerializeObject(principalModel);
var ticket = new FormsAuthenticationTicket(1, account.UserId, DateTime.Now, DateTime.Now.AddMinutes(30), false, userData);
var encryptedTicket = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
Response.Cookies.Add(cookie);
SetCulture(account.DefaultCulture);
if (!Array.Exists(roles, role => role == "admin" || role == "user")) return UnsuccessfulLoginResult(accountModel.UserName, ErrorMessages.WrongAccountInfo);
if (roles.Contains("admin")) { returnUrl = Url.Action("Index", "Admin"); }
if (roles.Contains("user")) { returnUrl = Url.Action("Index", "Upload"); }
return SuccessfulLoginResult(accountModel.UserName, returnUrl);
}
如您所见,当用户处于管理员角色时,此操作会重定向用户 /Admin/Index
,否则 /Upload/Index
。但是在我登录后,用户具有用户角色并输入 /Admin/Index
,授权过滤器不起作用,用户可以访问管理页面。
虽然我已将此属性添加到 UploadController 和 AdminController,但仍会发生此错误。我该如何解决这个问题?
[CustomAuthorize(Roles = "user")]
public class UploadController : BaseController
[CustomAuthorize(Roles = "admin")]
public class AdminController : BaseController
您需要为您的用户添加声明,将此部分添加到您的方法中:
. . .
var roles = account.Roles.Select(r => r.RoleName).ToArray();
ClaimsIdentity identity = new ClaimsIdentity(DefaultAuthenticationTypes.ApplicationCookie);
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, accountModel.UserName));
roles.ToList().ForEach((role) => identity.AddClaim(new Claim(ClaimTypes.Role, role)));
identity.AddClaim(new Claim(ClaimTypes.Name, userCode.ToString()));
. . .
这些更改解决了问题。
在我的 CustomAuthorizeAttribute 中更改了这一行
if (!filterContext.HttpContext.Request.IsAuthenticated) return;
到
if (!filterContext.HttpContext.Request.IsAuthenticated) base.OnAuthorization(filterContext);
并删除了我从网络配置中读取允许角色的行。所以我的属性最终版本如下
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
protected virtual CustomPrincipal CurrentUser => HttpContext.Current.User as CustomPrincipal;
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (!filterContext.HttpContext.Request.IsAuthenticated) base.OnAuthorization(filterContext);
if (string.IsNullOrEmpty(Roles)) return;
if (CurrentUser == null) return;
if (!CurrentUser.IsInRole(Roles)) filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Error", action = "AccessDenied" }));
}
}
然后我添加了一个名为 ErrorController 的控制器,并在用户不在角色时重定向到此页面。
通过这些更改,我意识到我无法访问我的 /Account/Index
并向下面的操作添加了 [AllowAnonymous]
属性。
[AllowAnonymous]
public ActionResult Index() { return View(); }
[HttpPost, ValidateAntiForgeryToken, AllowAnonymous]
public ActionResult Index(AccountViewModel accountModel)