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

Posted

技术标签:

【中文标题】ASP.Net-Core 中的自定义身份验证【英文标题】:Custom Authentication in ASP.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。

【问题讨论】:

【参考方案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 其中包括一些示例。

【讨论】:

这个答案也很好***.com/a/31688792/632495【参考方案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;
    

【讨论】:

以上是关于ASP.Net-Core 中的自定义身份验证的主要内容,如果未能解决你的问题,请参考以下文章

Kong API 网关中的自定义身份验证服务

JWT 身份验证不适用于 Django 中的自定义控制器

如何从 ASP.NET Core 2.0 中的自定义中间件请求身份验证

Flask 中的自定义身份验证和参数检查

SQL Server 报告服务的自定义身份验证中的“用户 xxx 没有所需的权限”

如何处理 grails spring-security-rest 插件中的自定义身份验证异常?