RoL*_*LLs 3 c# linq asp.net asp.net-mvc asp.net-identity
我无法找出正确且最有效的方法来做到这一点。我觉得日期和版本很重要,以防将来事情发生变化(在我寻找答案时似乎经常发生)。
使用Visual Studio 2017
v15.5.5,我使用个人帐户启动了一个新的 MVC ASP.NET Web 应用程序(.Net Framework,而不是 CORE)。我升级了所有的包。目前使用EntityFramework
v6.2.0 和Identity
v2.2.1。
我做了什么
我手动实现了我自己的版本RoleClaims
。我有一个class
定义了RoleClaims
应用class
程序的所有Claims
. 在应用程序中,Claims
用于定义可以做什么。例如,aClaim
可以是View Users
orEdit Users
甚至Delete Users
。
目标
根据给定的IdentityUser
和Claim
名称,我想知道用户是否有该名称Claim
?
课程
public class RoleClaim {
public int Id { get; set; }
public string RoleId { get; set; }
public IdentityRole Role { get; set; }
public int ClaimId { get; set; }
public Claim Claim { get; set; }
}
public class Claim {
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string ClaimType { get; set; }
public virtual ICollection<RoleClaim> RoleClaims { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
更多背景信息
我更喜欢用表达式来回答Linq
,但Linq
查询也可以。
另外,我AuthorizeAttribute
根据以下内容在自定义中执行所有这些逻辑,因此我很可能会做其他错误的事情。=) 请随意发表评论。
声明授权属性
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class ClaimsAuthorizationAttribute : AuthorizeAttribute {
private static readonly string[] _emptyArray = new string[0];
private string _claims;
private string[] _claimsSplit = _emptyArray;
public string Claims {
get => _claims ?? string.Empty;
set {
_claims = value;
_claimsSplit = SplitString(value);
}
}
public override void OnAuthorization(AuthorizationContext filterContext) {
if (filterContext == null) {
throw new ArgumentException("filterContext");
}
if (AuthorizeCore(filterContext.HttpContext)) {
// allowed... research anything else needed to be done
} else {
HandleUnauthorizedRequest(filterContext);
}
}
protected override bool AuthorizeCore(HttpContextBase httpContext) {
if (httpContext == null) {
throw new ArgumentException("httpContext");
}
var user = httpContext.User;
if (!user.Identity.IsAuthenticated) {
return false;
}
/*
* _claimsSplit contains all allowed Claims with access
*
* Based on the list of Claims, check if any of the Roles
* the user is a member of has at least the same Claim
*
* OR
*
* Based on the users' Roles, check if any of those
* roles has at least one of the claims that were passed in
*
*
*
* Should I check for any or should it be ALL Claims
* passed in? or should I pass another variable (bool)
* allowing the ability to decide if it should be
* at least 1 or all?
*/
return true;
}
internal static string[] SplitString(string original) {
if (string.IsNullOrEmpty(original)) {
return _emptyArray;
}
var split = from piece in original.Split(',')
let trimmed = piece.Trim()
where !string.IsNullOrEmpty(trimmed)
select trimmed;
return split.ToArray();
}
}
Run Code Online (Sandbox Code Playgroud)
概括
我需要帮助找出一种有效的方法来检查 a 是否User
拥有Claim
他们的Roles
.
解决方案
对于任何感兴趣的人,感谢Stephen Muecke,我能够创建解决方案。任何感兴趣的人都可以查看我的ClaimsAuthorizationAttribute.cs版本。
小智 5
假设您有User
(例如var User = db.Users.FirstOrDefault(u => u.UserName == user.Identity.Name)
,您可以首先获取用户的角色 ID 的集合
var roleIds = User.Roles.Select(x => x.Id);
Run Code Online (Sandbox Code Playgroud)
然后获取具有这些角色 ID 之一的所有声明的名称
var claims = db.RoleClaims.Where(x => roleIds.Contains(x => x.RoleId)).Select(x => x.Claim.Name);
Run Code Online (Sandbox Code Playgroud)
最后测试是否有匹配项
if (claims.Any(x => _claimsSplit.Contains(x)))
Run Code Online (Sandbox Code Playgroud)
但是,由于这将在每个请求上调用,因此您应该考虑缓存结果MemoryCache
(假设RoleClaim
不会经常更改)。一种方法是使用一个,Dictionary<string, IEnumerable<string>>
其中键是RoleId
,值是Claim
名称的集合。
您可以Dictionary
在启动时填充所有值,也可以根据需要添加。伪代码类似于
private const string key = "RoleClaims"
private bool HasClaim(string[] requiredClaims)
{
// Check the cache
Dictionary<string, IEnumerable<string>> roleClaims = Cache.Get(key)
if (roleClaims == null)
{
roleClaims = new Dictionary<string, IEnumerable<string>>();
Cache.Set(key, roleClaims, 240);
}
foreach (var role in roleIds)
{
IEnumerable<string> claims;
if (roleClaims.ContainsKey(role))
{
claims = roleClaims[role];
}
else
{
claims = db.RoleClaims.Where(roleIds == role).Select(x => x.Claim.Name);
roleClaims.Add(role, claims)
}
if (claims.Any(x => requiredClaims.Contains(x)))
{
return true // exit
}
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
并将其称为AuthorizeCore()
使用
return HasClaim(_claimsSplit);
Run Code Online (Sandbox Code Playgroud)
您只需要确保缓存在RoleClaim
修改现有缓存或添加新缓存时失效,这样您就不会使用“过时”数据。
注意Cache
上面的类是
public static class Cache
{
public static object Get(string key)
{
return MemoryCache.Default[key];
}
public static void Set(string key, object data, int duration = 30)
{
CacheItemPolicy policy = new CacheItemPolicy();
policy.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMinutes(duration);
MemoryCache.Default.Add(new CacheItem(key, data), policy);
}
public static void Invalidate(string key)
{
MemoryCache.Default.Remove(key);
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
4748 次 |
最近记录: |