ASP.Net-Core中的自定义身份验证

rgv*_*sar 62 c# asp.net authentication asp.net-core-mvc asp.net-core

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

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

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

Ami*_*imi 61

根据我在几天研究后学到的知识,这里是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();
}
Run Code Online (Sandbox Code Playgroud)

请记住,在上面的代码中,我们说如果任何未经[Authorize]身份验证的用户请求注释的操作,他们就会强制重定向到/Account/Loginurl.

将以下行添加到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);
    });
}
Run Code Online (Sandbox Code Playgroud)

创建您的UserManager类,也将管理登录和注销.它应该看起来像下面的片段(注意我正在使用短小精悍):

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

那么也许你有AccountController一个LoginAction应该如下所示:

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);
         }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在您可以[Authorize]在任何Action或上使用注释Controller.

随意评论任何问题或错误.

  • 您的“ConfigureServices”中有两次“AddAuthentication”代码。是错误还是什么原因? (2认同)

nat*_*ter 54

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

您可能会发现一些有用的文章:

使用没有ASP.NET身份的Cookie中间件

自定义基于策略的授权

当然,如果失败或文档不够清楚,源代码位于 https://github.com/aspnet/Security,其中包含一些示例.

  • 这个答案也非常好http://stackoverflow.com/a/31688792/632495 (8认同)

1_b*_*bug 5

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

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

public async void SignIn(HttpContext httpContext, UserDbModel user, bool isPersistent = false)
Run Code Online (Sandbox Code Playgroud)

到:

public async Task SignIn(HttpContext httpContext, UserDbModel user, bool isPersistent = false)
Run Code Online (Sandbox Code Playgroud)

这是因为你永远不应该使用async void,特别是如果你使用HttpContext. 来源:微软文档

最后但并非最不重要的是,您的Configure()方法Startup.cs应该包含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?}");
});
Run Code Online (Sandbox Code Playgroud)