我正在创建一个企业内部网ASP.NET核心MVC应用程序。我希望我的用户使用Active Directory进行身份验证,我希望用户授权(声明)存储在 ApplicationDbContext 中。
我认为我需要使用 Microsoft.AspNetCore.Identity 和 Microsoft.AspNetCore.Identity.EntityFrameworkCore 来实现我的目标。在针对Active Directory进行身份验证时,存储ASP.NET核心授权声明的最佳做法是什么?
以下代码将允许我从管道内访问当前的Windows用户安全上下文(当前登录用户)。不知何故,我需要使用关联的 Microsoft.AspNetCore.Identity 声明来映射用户?
app.Use(async (context, next) =>
{
var identity = (ClaimsIdentity) context.User.Identity;
await next.Invoke();
});
提前感谢您的帮助!
答案 0 :(得分:4)
我认为这方面没有最好的做法,但你确实有很多选择。也许你可以详细说明你想要实现的目标?这里有一些指示可以帮助您解决其中的一些问题。只是一个问题......你用什么来验证引擎盖下的AD?如果你使用IdentityServer或类似的东西,我会建议倾向于选项4。
ApplicationUser
属性首先,索赔只是键值对。这意味着您可以创建一个结构,例如:
public class UserClaim
{
public string UserName {get; set;}
public string Key {get; set;}
public string Value {get; set;}
}
这样您就可以将声明存储在ApplicationUser
课程中。
UserManager
更好的是,您可以通过向要添加用户声明的类中注入UserManager<ApplicationUser> userManager
来利用内置标识组件,然后使用适当的值调用AddClaim()
。由于Core中的DI系统,您可以在任何将由运行时激活的类中自由执行此操作。
另一种方法是使用UserClaim
属性扩充UserName
类,然后使用原则的唯一标识符(User.Identity.Name
)。然后,您可以将其存储在DbSet<UserClaim>
的{{1}}中,并按用户名获取声明。
如果您只是需要访问声明,而不是存储它们(我不确定您的意图是否是您的问题)那么您最好只访问ApplicationDbContext
属性,如果您在控制器,只要您使用的身份验证服务能够正确地保证声明。
User
使用属于登录到您应用的用户的声明进行修饰,并且可在每个控制器上使用。
您可以获得User
并以这种方式访问用户的声明。在这种情况下(在控制器之外),您要做的是向类的构造函数添加ClaimsPrinciple
并导航到IHttpContextAccessor accessor
属性,该属性又是HttpContextAccessor.HttpContext.User
。< / p>
答案 1 :(得分:0)
这是我的方法:
实施MyUser类
public class MyUser: IdentityUser
{
}
在单独的&#34;安全&#34;中使用ASP.Net Core DbContext。 DBContext(我更喜欢有限的上下文,对自己的功能负责)
public class SecurityDbContext : IdentityDbContext<MyUser>
{
public SecurityDbContext(DbContextOptions<SecurityDbContext> options)
: base(options)
{ }
}
创建声明转换器。这用于将商店中的声明添加到ClaimsIdentity(HttpContext中的用户对象)
public class ClaimsTransformer : IClaimsTransformer
{
private readonly SecurityDbContext _context;
private readonly UserManager<MyUser> _userManager;
public ClaimsTransformer(SecurityDbContext context, UserManager<MyUser> userManager)
{
_context = context;
_userManager = userManager;
}
public Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context)
{
var identity = context.Principal.Identity as ClaimsIdentity;
if (identity == null) return Task.FromResult(context.Principal);
try
{
if (context.Context.Response.HasStarted)
return Task.FromResult(context.Principal);
var claims = AddClaims(identity);
identity.AddClaims(claims);
}
catch (InvalidOperationException)
{
}
catch (SqlException ex)
{
if (!ex.Message.Contains("Login failed for user") && !ex.Message.StartsWith("A network-related or instance-specific error"))
throw;
}
return Task.FromResult(context.Principal);
}
private IEnumerable<Claim> AddClaims(IIdentity identity)
{
var claims = new List<Claim>();
var existing = _userManager.Users.Include(u => u.Claims).SingleOrDefault(u => u.UserName == identity.Name);
if (existing == null) return claims;
claims.Add(new Claim(SupportedClaimTypes.ModuleName, Constants.ADGroupName));
claims.AddRange(existing.Claims.Select(c => c.ToClaim()));
return claims;
}
}
你需要在startup.cs类中添加一些东西,我在这里只添加了相关内容:
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentity<FreightRateUser, IdentityRole>(config =>
{
config.User.AllowedUserNameCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@\\";
config.User.RequireUniqueEmail = false;
config.Cookies.ApplicationCookie.LoginPath = "/Auth/Login";
})
.AddEntityFrameworkStores<SecurityDbContext>();
}
别忘了配置方法
public async void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseIdentity();
}
最后,你需要一些View来将相应的用户/声明添加到Identity表中,我有一个带有几个Actions的控制器(只显示在这里创建):
[AllowAnonymous]
public IActionResult CreateAccess()
{
var vm = new AccessRequestViewModel
{
Username = User.Identity.Name
};
return View(vm);
}
[HttpPost]
[ValidateAntiForgeryToken]
[AllowAnonymous]
public async Task<IActionResult> CreateAccess(AccessRequestViewModel viewModel)
{
if (User == null || !User.Identity.IsAuthenticated) return View("Index");
var newUser = new MyUser
{
UserName = viewModel.Username
};
var x = await _userManager.CreateAsync(newUser);
if (!x.Succeeded)
return View(ModelState);
var myClaims = new List<Claim>();
if (viewModel.CanManageSecurity)
myClaims.Add(new Claim(SupportedClaimTypes.Security, "SITE,LOCAL"));
if (viewModel.CanChangeExchangeRates)
myClaims.Add(new Claim(SupportedClaimTypes.ExchangeRates, "AUD,USD"));
if (viewModel.CanChangeRates)
myClaims.Add(new Claim(SupportedClaimTypes.Updates, "LOCAL"));
if (viewModel.CanManageMasterData)
myClaims.Add(new Claim(SupportedClaimTypes.Admin, "SITE,LOCAL"));
await _userManager.AddClaimsAsync(newUser, myClaims);
}
return View("Index");
}
当用户被保存并再次显示经过身份验证的页面(索引)时,声明转换器会将声明加载到ClaimsIdentity中,并且一切都应该是好的。
请注意, 这是针对当前的HttpContext用户,他们希望在Create中为其他用户创建,因为你显然不喜欢&# 39; t希望当前用户自己访问。