如何从 HttpContext 访问角色对象,或者更具体地说,如何从自定义授权属性访问角色对象?
How do I access role objects from HttpContext, or more specifically from a custom authorize attribute?
背景
我想根据他们的 ApplicationRole
和 RoleClaim
授权一个 ApplicationUser
。我想这样实现:
public class RoleClaimAuthorizeAttribute : AuthorizeAttribute
{
public RoleClaim RoleClaim { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
foreach (ApplicationRole role in Roles)
{
if ((RoleClaim & role.Claims) > 0)
{
return true;
}
}
return false;
}
}
然后我可以像这样装饰控制器动作:
[RoleClaimAuthorize(RoleClaim =
RoleClaim.CanCreateRoles |
RoleClaim.CanReadRoles |
RoleClaim.CanDeleteRoles |
RoleClaim.CanUpdateRoles
)]
//
// GET: /Roles/
public ActionResult Index()
{
return View(_roleManager.Roles);
}
问题
我遇到的问题是我可以找到从我的自定义授权属性 returns 到达 ApplicationUser
的 ApplicationRole
的任何方法 [=21] 的字符串数组=] 不是 ApplicationRole
的数组,所以我无法到达 ApplicationRole.Claims
。我还使用 Unity 而不是 Owin 来处理 ApplicationRoleManager
,所以我无法通过 HttpContext.Current.GetOwinContext().Get<ApplicationRoleManager>()
.
请求 ApplicationRoleManager
那么我怎样才能为当前用户获取 ApplicationRole
个对象的集合,从而 ApplicationRole.Claims
?
或者,如果这是一个更合适的解决方案,我如何将当前 ApplicationUser
's ApplicationRole
s' RoleClaim
的字符串数组存储在 HttpContext
中,就像角色如何存储一样存储?我知道在这种情况下我的授权属性无法正常工作,但我仍然可以处理这种情况。
相关类
应用程序用户
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser<Guid, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public override Guid Id { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, Guid> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, Guid> manager, string authenticationType)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
// Add custom user claims here
return userIdentity;
}
}
应用角色
public class ApplicationRole : IdentityRole<Guid, ApplicationUserRole>
{
public ApplicationRole() : base()
{
this.Id = Guid.NewGuid();
}
public ApplicationRole(string name)
: this()
{
this.Name = name;
}
public ApplicationRole(string name, params string[] claims)
: this(name)
{
Claims = (RoleClaim)Enum.Parse(typeof(RoleClaim), String.Join(",", claims));
}
public RoleClaim Claims { get; set; }
}
角色声明
[Flags]
public enum RoleClaim : int
{
CanCreateUsers = 1,
CanReadUsers = 2,
CanUpdateUsers = 4,
CanDeleteUsers = 8,
CanCreateRoles = 16,
CanReadRoles = 32,
CanUpdateRoles = 64,
CanDeleteRoles = 128,
CanCreateTests = 256,
CanReadTests = 512,
CanUpdateTests = 1024,
CanDeleteTests = 2048
}
ApplicationRoleManager
public class ApplicationRoleManager : RoleManager<ApplicationRole, Guid>
{
public ApplicationRoleManager(IRoleStore<ApplicationRole, Guid> store) : base(store)
{
}
}
如果您在 Unity 中注册了角色管理器,您可以在任何地方检索,包括您的自定义属性,只需调用以下方法即可:
var roleManager = DependencyResolver.Current.GetService<ApplicationRoleManager>();
或者,如果您不想直接使用解析器,您可以使用 Unity 的 属性 注入功能,以便 Unity 自动将角色管理器注入自定义属性中,这在 中进行了解释。然后调用 roleManager.FindByNameAsync()
方法来检索角色对象。
但不推荐使用这种方法,因为在每次调用中,您的代码都会访问数据库以检索声明。最好在用户登录时将用户的声明存储在 ClaimsIdentity
中,然后像这样在属性中检索它们:
public class ApplicationSignInManager : SignInManager<ApplicationUser, string>
{
private readonly ApplicationRoleManager _roleManager;
public ApplicationSignInManager(ApplicationUserManager userManager,
IAuthenticationManager authenticationManager,
ApplicationRoleManager rolemanager)
: base(userManager, authenticationManager)
{
//inject the role manager to the sign in manager
_roleManager=rolemanager;
}
public override async Task<ClaimsIdentity> CreateUserIdentityAsync(ApplicationUser user)
{
var ident= await user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager);
// add your custom claims here
var userRoles=user.Roles.Select(r=>r.RoleId);
ident.AddClaims(_roleManager.Roles.Where(r => userRoles.Any(ur => ur == r.Id))
.Select(r=>r.Claims).ToList()
.Select(c => new Claim("RoleClaims", c.ToString())));
return ident;
}
}
现在 RoleClaims
在用户登录时添加为声明。您可以像这样在属性中检索它们:
public class RoleClaimAuthorizeAttribute : AuthorizeAttribute
{
public RoleClaim RoleClaim { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
foreach (var claims in GetClaims(httpContext.User.Identity as ClaimsIdentity))
{
if ((RoleClaim & claims) > 0)
{
return true;
}
}
return false;
}
private IEnumerable<RoleClaim> GetClaims(ClaimsIdentity ident)
{
return ident==null
? Enumerable.Empty<RoleClaim>()
: ident.Claims.Where(c=>c.Type=="RoleClaims")
.Select(c=>(RoleClaim)Enum.Parse(typeof(RoleClaim), c.Value));
}
}
背景
我想根据他们的 ApplicationRole
和 RoleClaim
授权一个 ApplicationUser
。我想这样实现:
public class RoleClaimAuthorizeAttribute : AuthorizeAttribute
{
public RoleClaim RoleClaim { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
foreach (ApplicationRole role in Roles)
{
if ((RoleClaim & role.Claims) > 0)
{
return true;
}
}
return false;
}
}
然后我可以像这样装饰控制器动作:
[RoleClaimAuthorize(RoleClaim =
RoleClaim.CanCreateRoles |
RoleClaim.CanReadRoles |
RoleClaim.CanDeleteRoles |
RoleClaim.CanUpdateRoles
)]
//
// GET: /Roles/
public ActionResult Index()
{
return View(_roleManager.Roles);
}
问题
我遇到的问题是我可以找到从我的自定义授权属性 returns 到达 ApplicationUser
的 ApplicationRole
的任何方法 [=21] 的字符串数组=] 不是 ApplicationRole
的数组,所以我无法到达 ApplicationRole.Claims
。我还使用 Unity 而不是 Owin 来处理 ApplicationRoleManager
,所以我无法通过 HttpContext.Current.GetOwinContext().Get<ApplicationRoleManager>()
.
ApplicationRoleManager
那么我怎样才能为当前用户获取 ApplicationRole
个对象的集合,从而 ApplicationRole.Claims
?
或者,如果这是一个更合适的解决方案,我如何将当前 ApplicationUser
's ApplicationRole
s' RoleClaim
的字符串数组存储在 HttpContext
中,就像角色如何存储一样存储?我知道在这种情况下我的授权属性无法正常工作,但我仍然可以处理这种情况。
相关类
应用程序用户
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser<Guid, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public override Guid Id { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, Guid> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, Guid> manager, string authenticationType)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
// Add custom user claims here
return userIdentity;
}
}
应用角色
public class ApplicationRole : IdentityRole<Guid, ApplicationUserRole>
{
public ApplicationRole() : base()
{
this.Id = Guid.NewGuid();
}
public ApplicationRole(string name)
: this()
{
this.Name = name;
}
public ApplicationRole(string name, params string[] claims)
: this(name)
{
Claims = (RoleClaim)Enum.Parse(typeof(RoleClaim), String.Join(",", claims));
}
public RoleClaim Claims { get; set; }
}
角色声明
[Flags]
public enum RoleClaim : int
{
CanCreateUsers = 1,
CanReadUsers = 2,
CanUpdateUsers = 4,
CanDeleteUsers = 8,
CanCreateRoles = 16,
CanReadRoles = 32,
CanUpdateRoles = 64,
CanDeleteRoles = 128,
CanCreateTests = 256,
CanReadTests = 512,
CanUpdateTests = 1024,
CanDeleteTests = 2048
}
ApplicationRoleManager
public class ApplicationRoleManager : RoleManager<ApplicationRole, Guid>
{
public ApplicationRoleManager(IRoleStore<ApplicationRole, Guid> store) : base(store)
{
}
}
如果您在 Unity 中注册了角色管理器,您可以在任何地方检索,包括您的自定义属性,只需调用以下方法即可:
var roleManager = DependencyResolver.Current.GetService<ApplicationRoleManager>();
或者,如果您不想直接使用解析器,您可以使用 Unity 的 属性 注入功能,以便 Unity 自动将角色管理器注入自定义属性中,这在 roleManager.FindByNameAsync()
方法来检索角色对象。
但不推荐使用这种方法,因为在每次调用中,您的代码都会访问数据库以检索声明。最好在用户登录时将用户的声明存储在 ClaimsIdentity
中,然后像这样在属性中检索它们:
public class ApplicationSignInManager : SignInManager<ApplicationUser, string>
{
private readonly ApplicationRoleManager _roleManager;
public ApplicationSignInManager(ApplicationUserManager userManager,
IAuthenticationManager authenticationManager,
ApplicationRoleManager rolemanager)
: base(userManager, authenticationManager)
{
//inject the role manager to the sign in manager
_roleManager=rolemanager;
}
public override async Task<ClaimsIdentity> CreateUserIdentityAsync(ApplicationUser user)
{
var ident= await user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager);
// add your custom claims here
var userRoles=user.Roles.Select(r=>r.RoleId);
ident.AddClaims(_roleManager.Roles.Where(r => userRoles.Any(ur => ur == r.Id))
.Select(r=>r.Claims).ToList()
.Select(c => new Claim("RoleClaims", c.ToString())));
return ident;
}
}
现在 RoleClaims
在用户登录时添加为声明。您可以像这样在属性中检索它们:
public class RoleClaimAuthorizeAttribute : AuthorizeAttribute
{
public RoleClaim RoleClaim { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
foreach (var claims in GetClaims(httpContext.User.Identity as ClaimsIdentity))
{
if ((RoleClaim & claims) > 0)
{
return true;
}
}
return false;
}
private IEnumerable<RoleClaim> GetClaims(ClaimsIdentity ident)
{
return ident==null
? Enumerable.Empty<RoleClaim>()
: ident.Claims.Where(c=>c.Type=="RoleClaims")
.Select(c=>(RoleClaim)Enum.Parse(typeof(RoleClaim), c.Value));
}
}