在针对Active Directory对用户进行身份验证时存储ASP.NET Core Authorization声明的最佳实践?

时间:2016-06-14 19:37:30

标签: asp.net-core asp.net-identity asp.net-core-mvc

我正在创建一个企业内部网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();
 });

提前感谢您的帮助!

2 个答案:

答案 0 :(得分:4)

我认为这方面没有最好的做法,但你确实有很多选择。也许你可以详细说明你想要实现的目标?这里有一些指示可以帮助您解决其中的一些问题。只是一个问题......你用什么来验证引擎盖下的AD?如果你使用IdentityServer或类似的东西,我会建议倾向于选项4。

选项1 - 将声明存储为ApplicationUser属性

首先,索赔只是键值对。这意味着您可以创建一个结构,例如:

public class UserClaim 
{
    public string UserName {get; set;}
    public string Key {get; set;}
    public string Value {get; set;}
}

这样您就可以将声明存储在ApplicationUser课程中。

选项2 - 使用UserManager

存储声明

更好的是,您可以通过向要添加用户声明的类中注入UserManager<ApplicationUser> userManager来利用内置标识组件,然后使用适当的值调用AddClaim()。由于Core中的DI系统,您可以在任何将由运行时激活的类中自由执行此操作。

选项3 - 将索赔存储在自己的表中

另一种方法是使用UserClaim属性扩充UserName类,然后使用原则的唯一标识符(User.Identity.Name)。然后,您可以将其存储在DbSet<UserClaim>的{​​{1}}中,并按用户名获取声明。

选项4 - 不存储声明

如果您只是需要访问声明,而不是存储它们(我不确定您的意图是否是您的问题)那么您最好只访问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希望当前用户自己访问。