【问题标题】:Custom Authentication in ASP.Net-CoreASP.Net-Core 中的自定义身份验证
【发布时间】:2016-07-05 20:08:15
【问题描述】:

我正在开发一个需要与现有用户数据库集成的网络应用程序。我仍然想使用 [Authorize] 属性,但我不想使用 Identity 框架。如果我确实想使用 Identity 框架,我会在 startup.cs 文件中添加类似的内容:

services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
    options.Password.RequireNonLetterOrDigit = false;
}).AddEntityFrameworkStores<ApplicationDbContext>()
  .AddDefaultTokenProviders();

我假设我必须在那里添加其他东西,然后创建某种实现特定接口的类?有人可以指出我正确的方向吗?我现在正在使用 asp.net 5 的 RC1。

【问题讨论】:

    标签: c# asp.net authentication asp.net-core asp.net-core-mvc


    【解决方案1】:

    经过几天的研究,我了解到, 这是 ASP .Net Core MVC 2.x 自定义用户身份验证指南

    Startup.cs

    ConfigureServices 方法中添加以下行:

    public void ConfigureServices(IServiceCollection services)
    {
    
    services.AddAuthentication(
        CookieAuthenticationDefaults.AuthenticationScheme
    ).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,
        options =>
        {
            options.LoginPath = "/Account/Login";
            options.LogoutPath = "/Account/Logout";
        });
    
        services.AddMvc();
    
        // authentication 
        services.AddAuthentication(options =>
        {
           options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        });
    
        services.AddTransient(
            m => new UserManager(
                Configuration
                    .GetValue<string>(
                        DEFAULT_CONNECTIONSTRING //this is a string constant
                    )
                )
            );
         services.AddDistributedMemoryCache();
    }
    

    请记住,在上面的代码中,我们说过,如果任何 unauthenticated 用户请求一个带有 [Authorize] 注释的操作,他们会强制重定向到 /Account/Login url。

    Configure 方法中添加以下行:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseBrowserLink();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler(ERROR_URL);
        }
         app.UseStaticFiles();
         app.UseAuthentication();
         app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: DEFAULT_ROUTING);
        });
    }
    

    创建您的UserManager 类,该类也将管理登录和注销。它应该如下所示 sn-p(请注意,我使用的是 dapper):

    public class UserManager
    {
        string _connectionString;
    
        public UserManager(string connectionString)
        {
            _connectionString = connectionString;
        }
    
        public async void SignIn(HttpContext httpContext, UserDbModel user, bool isPersistent = false)
        {
            using (var con = new SqlConnection(_connectionString))
            {
                var queryString = "sp_user_login";
                var dbUserData = con.Query<UserDbModel>(
                    queryString,
                    new
                    {
                        UserEmail = user.UserEmail,
                        UserPassword = user.UserPassword,
                        UserCellphone = user.UserCellphone
                    },
                    commandType: CommandType.StoredProcedure
                ).FirstOrDefault();
    
                ClaimsIdentity identity = new ClaimsIdentity(this.GetUserClaims(dbUserData), CookieAuthenticationDefaults.AuthenticationScheme);
                ClaimsPrincipal principal = new ClaimsPrincipal(identity);
    
                await httpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);
            }
        }
    
        public async void SignOut(HttpContext httpContext)
        {
            await httpContext.SignOutAsync();
        }
    
        private IEnumerable<Claim> GetUserClaims(UserDbModel user)
        {
            List<Claim> claims = new List<Claim>();
    
            claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id().ToString()));
            claims.Add(new Claim(ClaimTypes.Name, user.UserFirstName));
            claims.Add(new Claim(ClaimTypes.Email, user.UserEmail));
            claims.AddRange(this.GetUserRoleClaims(user));
            return claims;
        }
    
        private IEnumerable<Claim> GetUserRoleClaims(UserDbModel user)
        {
            List<Claim> claims = new List<Claim>();
    
            claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id().ToString()));
            claims.Add(new Claim(ClaimTypes.Role, user.UserPermissionType.ToString()));
            return claims;
        }
    }
    

    那么也许你有一个AccountController,它有一个Login Action,应该如下所示:

    public class AccountController : Controller
    {
        UserManager _userManager;
    
        public AccountController(UserManager userManager)
        {
            _userManager = userManager;
        }
    
        [HttpPost]
        public IActionResult LogIn(LogInViewModel form)
        {
            if (!ModelState.IsValid)
                return View(form);
             try
            {
                //authenticate
                var user = new UserDbModel()
                {
                    UserEmail = form.Email,
                    UserCellphone = form.Cellphone,
                    UserPassword = form.Password
                };
                _userManager.SignIn(this.HttpContext, user);
                 return RedirectToAction("Search", "Home", null);
             }
             catch (Exception ex)
             {
                ModelState.AddModelError("summary", ex.Message);
                return View(form);
             }
        }
    }
    

    现在您可以在任何ActionController 上使用[Authorize] 注释。

    如有任何问题或错误,请随时发表评论。

    【讨论】:

    • 谢谢你!这是一个受此答案启发的实现,使用 nhibernate 对用户进行身份验证。它是从 asp.net core 2.1 脚手架身份 UI 代码修改的 asp.net 3 项目模板代码的混合 - github.com/xhafan/emailmaker/tree/master/src/…
    • 在哪里放置 UserManager 类的正确位置?
    • 您的ConfigureServices 中有两次AddAuthentication 代码。是误会还是什么?
    • 您还添加了两次 NameIdentifier 声明。
    • @lcssanches src/yourProjectCore/Authorization/Users/AppUserManager.cs check this out
    【解决方案2】:

    可以通过多种方式在 ASP.NET Core 中创建自定义身份验证。如果您想构建现有组件(但不想使用身份),请查看 docs.asp.net 上文档的“安全”类别。 https://docs.asp.net/en/latest/security/index.html

    一些您可能会觉得有帮助的文章:

    Using Cookie Middleware without ASP.NET Identity

    Custom Policy-Based Authorization

    当然,如果失败或文档不够清晰,源代码位于 https://github.com/dotnet/aspnetcore/tree/master/src/Security 其中包括一些示例。

    【讨论】:

    【解决方案3】:

    我想为要在 .NET Core 3 中实现他的解决方案的每个人添加一些精彩的 @AmiNadimi 答案:

    首先,您应该将UserManager 类中SignIn 方法的签名从:

    public async void SignIn(HttpContext httpContext, UserDbModel user, bool isPersistent = false)
    

    到:

    public async Task SignIn(HttpContext httpContext, UserDbModel user, bool isPersistent = false)
    

    这是因为你永远不应该使用async void,尤其是如果你使用HttpContext。来源:Microsoft Docs

    最后但并非最不重要的一点是,Startup.cs 中的 Configure() 方法应按正确顺序包含 app.UseAuthorizationapp.UseAuthentication

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }
    
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseAuthentication();
    app.UseRouting();
    app.UseAuthorization();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
    

    【讨论】:

      【解决方案4】:

      @Manish Jain,我建议用布尔返回实现该方法:

      public class UserManager
      {
      
          // Additional code here...            
      
          public async Task<bool> SignIn(HttpContext httpContext, UserDbModel user)
          {
              // Additional code here...            
      
              // Here the real authentication against a DB or Web Services or whatever 
              if (user.Email != null)
                  return false;                    
      
              ClaimsIdentity identity = new ClaimsIdentity(this.GetUserClaims(dbUserData), CookieAuthenticationDefaults.AuthenticationScheme);
              ClaimsPrincipal principal = new ClaimsPrincipal(identity);
      
              // This is for give the authentication cookie to the user when authentication condition was met
              await httpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);
              return true;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2017-02-15
        • 2018-02-24
        • 2018-03-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多