首页 文章

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

提问于
浏览
15

我正在创建一个企业内部网ASP.NET核心MVC应用程序 . 我希望我的用户使用Active Directory进行身份验证,我希望存储在ApplicationDbContext中的用户授权(声明) .

我假设我需要使用Microsoft.AspNetCore.Identity和Microsoft.AspNetCore.Identity.EntityFrameworkCore来实现我的目标 . 在针对Active Directory进行身份验证时,存储ASP.NET Core Authorization声明的最佳做法是什么?

以下代码将允许我从管道内访问当前Windows用户安全上下文(当前登录用户) . 不知何故,我需要将用户映射到相关的Microsoft.AspNetCore.Identity声明?

app.Use(async (context, next) =>
 {
      var identity = (ClaimsIdentity) context.User.Identity;
      await next.Invoke();
 });

在此先感谢您的帮助!

2 回答

  • 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 - 将索赔存储在自己的表中

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

    选项4 - 不存储声明

    如果您只是需要访问声明,而不是存储它们(我不确定您的问题的意图)那么您最好只是访问 User 属性,如果您使用正确保证声明的身份验证服务 .

    User 使用属于登录到您的应用程序的用户的声明进行修饰,并且可在每个控制器上使用 .

    您可以以其他方式获取 ClaimsPrinciple 并以该方式访问用户的声明 . 在这种情况下(在控制器之外)你要做的是将 IHttpContextAccessor accessor 添加到类的构造函数并导航到 HttpContextAccessor.HttpContext.User 属性,这又是 ClaimsPrinciple .

  • 0

    这是我的方法:

    实现MyUser类

    public class MyUser: IdentityUser
    {
    }
    

    在一个单独的“安全”DBContext中使用ASP.Net Core 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>();
    }
    

    不要忘记Configure方法

    public async void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        app.UseIdentity();
    }
    

    最后你需要一些View来为Identity表添加适当的User / claim,我有一个带有几个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中,并且一切都应该是好的 .

    Please Note, 这是针对当前的HttpContext用户,想要在Create中为其他用户创建,因为你显然不希望当前用户给自己访问权限 .

相关问题