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


75

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

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

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

Answers:


62

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

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

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

基于自定义策略的授权

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


12
这个答案也非常好stackoverflow.com/a/31688792/632495
Jon49'1

79

经过几天的研究,从中学到的知识,这是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();
}

请记住,在上面的代码中,我们说过,如果任何未经[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);
    });
}

创建您的UserManager班级,该班级还将管理登录和注销。它应该看起来像下面的代码片段(请注意,我正在使用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操作,该操作应如下所示:

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);
         }
    }
}

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

随时评论任何问题或错误。


1
谢啦!这是受此答案启发的实现,它使用nhibernate对用户进行身份验证。它是从asp.net core 2.1支架式身份UI代码修改而来的asp.net 3项目模板代码的混合-github.com/xhafan/emailmaker/tree/master/src/…–
xhafan

放置UserManager类的正确位置在哪里?
lcssanches

您的AddAuthentication代码中有两次代码ConfigureServices。是由于错误还是其他原因?
ibubi

您还添加两次NameIdentifier声明。
N-ate

@lcssanchessrc/yourProjectCore/Authorization/Users/AppUserManager.cs检查
AmiNadimi

1

@Manish Jain,我建议用boolean return实现该方法:

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;
    }
}

0

对于要在.NET Core 3中实现其解决方案的每个人,我想在@AmiNadimi答案中添加一些精彩内容:

首先,您应该从以下SignIn方法更改UserManager类中方法的签名:

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

最后但并非最不重要的是,您的Configure()方法Startup.cs应包含app.UseAuthorization并按app.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?}");
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.