我有一个使用Windows身份验证的 ASP.NET 核心(基于.NET Framework(。关键是,我需要在该用户上添加一个角色声明,并且此角色存储在远程数据库中。
我读了很多关于OWIN/Cookie/UserManager/UserStore/Identity等的东西,以至于我迷失了方向。
问:如何以最简单的方式为整个应用程序的当前用户登录(Windows(添加角色声明?
我需要的是轻松使用[Authorize(Role= "MyAddedRole")]
或bool res = User.IsInRole("MyAddedRole")
谢谢
除了答案之外,我刚刚找到了在asp .net core中完全预定义的答案。添加声明时,只需:
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, UserName),
new Claim(ClaimTypes.Role, "User"),
new Claim(ClaimTypes.Role, "Admin"),
new Claim(ClaimTypes.Role, Watever)
};
之后,您可以按说使用它:
[Authorize(Roles = "Watever")]
或
User.IsInRole("Watever")
回答我自己,所以我做了什么:
创建我自己的用户声明商店(我只需要这个存储,不需要其他存储(:
public class MyIdentityStore :
IUserClaimStore<IdentityUser>
{
private MyDbContext _myDbContext;
private bool _disposed = false;
public MyIdentityStore(MyDbContext myDbContext)
{
_myDbContext = myDbContext;
}
#region IUserClaimStore
public Task<IList<Claim>> GetClaimsAsync(IdentityUser user, CancellationToken cancellationToken)
{
// logic here to retrieve claims from my own database using _myDbContext
}
// All other methods from interface throwing System.NotSupportedException.
#endregion
#region IDisposable Support
protected virtual void Dispose(bool disposing)
{ /* do cleanup */ }
#endregion
}
然后创建了我自己的ClaimTransformer:
public class MyClaimsTransformer : IClaimsTransformer
{
private UserManager<IdentityUser> _userManager;
public MyClaimsTransformer(UserManager<IdentityUser> userManager)
{
_userManager = userManager;
}
public async Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context)
{
var identity = ((ClaimsIdentity)context.Principal.Identity);
// Accessing the UserClaimStore described above
var claims = await _userManager.GetClaimsAsync(new IdentityUser(identity.Name));
identity.AddClaims(claims);
return await Task.FromResult(context.Principal);
}
}
最后,在启动中.cs :
public void ConfigureServices(IServiceCollection services)
{
/* All other stuff here */
// Adding Database connection
services.AddDbContext<MyDbContext>(o => /* my options */);
// Associates our database and store to identity
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<MyDbContext>()
.AddUserStore<MyIdentityStore>();
// Claims transformation from database to claims
services.AddTransient<IClaimsTransformer, MyClaimsTransformer>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
/* All other stuff here */
app.UseIdentity();
app.UseClaimsTransformation(async (context) =>
{ // Retrieve user claims from database
IClaimsTransformer transformer = context.Context.RequestServices.GetRequiredService<IClaimsTransformer>();
return await transformer.TransformAsync(context);
});
}
现在我可以自由使用[Authorize(Roles = "MyRole")]
或User.IsInRole("MyRole")
甚至User.HasClaim(/* */)
!
您正在谈论的用户对象具有多个标识,这些标识都可以具有多个声明。
将自定义声明添加到 User 对象的一种方法是编辑由您选择的身份验证/授权框架(例如 OAuth(自动创建的标识,并且该步骤显然特定于每个框架。它归结为阅读该框架的文档,以确定在哪个点创建标识,并使用添加新声明的自定义代码扩展该点。
另一种可能更简单的方法是创建一个新的 Identity 对象(其中包含所有其他声明(,并使用 AddIdentity(( 方法将其添加到标识的用户列表中。
当您访问User.Claims
该枚举将返回您在 User 对象上拥有的所有标识的所有声明。
所以,无论你在应用程序代码的哪个阶段(我想最合适的一点是某种中间件(,你都可以做这样的事情:
var myIdentity = new ClaimsIdentity(new []
{
new Claim("claim type", "claim value"),
new Claim("claim type", "claim value"),
new Claim("claim type", "claim value"),
});
context.User.AddIdentity(myIdentity);
从那时起,对User.Claims
的每次调用都将返回 User 对象上的所有原始声明以及您的其他声明。