Benutzerdefinierte Authentifizierung in ASP.Net-Core

74

Ich arbeite an einer Web-App, die in eine vorhandene Benutzerdatenbank integriert werden muss. Ich möchte die [Authorize]Attribute weiterhin verwenden, aber ich möchte das Identitätsframework nicht verwenden. Wenn ich das Identity Framework verwenden wollte, würde ich so etwas in die Datei startup.cs einfügen:

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

Ich gehe davon aus, dass ich dort etwas anderes hinzufügen und dann eine Art Klasse erstellen muss, die eine bestimmte Schnittstelle implementiert. Kann mich jemand in die richtige Richtung weisen? Ich benutze gerade RC1 von asp.net 5.

rgvassar
quelle

Antworten:

61

Das Erstellen einer benutzerdefinierten Authentifizierung in ASP.NET Core kann auf verschiedene Arten erfolgen. Wenn Sie vorhandene Komponenten ausbauen möchten (aber keine Identität verwenden möchten), überprüfen Sie die Dokumentkategorie "Sicherheit" auf docs.asp.net. https://docs.asp.net/en/latest/security/index.html

Einige Artikel, die Sie vielleicht hilfreich finden:

Verwenden der Cookie-Middleware ohne ASP.NET-Identität

Benutzerdefinierte richtlinienbasierte Autorisierung

Und wenn dies fehlschlägt oder die Dokumente nicht klar genug sind, finden Sie den Quellcode unter https://github.com/dotnet/aspnetcore/tree/master/src/Security, der einige Beispiele enthält.

Natemcmaster
quelle
12
Diese Antwort ist auch sehr gut stackoverflow.com/a/31688792/632495
Jon49
78

Nach dem, was ich nach mehreren Tagen Recherche gelernt habe, finden Sie hier das Handbuch für die benutzerdefinierte Benutzerauthentifizierung von ASP .Net Core MVC 2.x.

In Startup.cs:

Fügen Sie der ConfigureServicesMethode die folgenden Zeilen hinzu :

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

Beachten Sie, dass wir im obigen Code gesagt haben, dass ein nicht authentifizierter Benutzer, der eine mit Anmerkungen versehene Aktion anfordert, die [Authorize]Umleitung zur /Account/LoginURL erzwingen muss .

Fügen Sie der ConfigureMethode die folgenden Zeilen hinzu :

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

Erstellen Sie Ihre UserManagerKlasse, die auch die An- und Abmeldung verwaltet. es sollte wie folgt aussehen: beachte, dass ich dapper benutze):

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

Dann haben Sie vielleicht eine, AccountControllerdie eine LoginAktion hat, die wie folgt aussehen sollte:

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

Jetzt können Sie [Authorize]Anmerkungen für jedes Actionoder verwenden Controller.

Fühlen Sie sich frei, Fragen oder Fehler zu kommentieren.

AmiNadimi
quelle
1
Danke, Mann! Hier ist eine Implementierung, die von dieser Antwort inspiriert ist und nhibernate zur Authentifizierung von Benutzern verwendet. Es ist eine Mischung aus asp.net 3-Projektvorlagencode, der aus dem UI-Code für die Gerüstidentität von asp.net Core 2.1 geändert wurde - github.com/xhafan/emailmaker/tree/master/src/…
xhafan
Wo ist der richtige Ort, um die UserManager-Klasse zu platzieren?
lcssanches
Sie haben zweimal AddAuthenticationCode in Ihrem ConfigureServices. Ist es aus Versehen oder so?
Ibubi
Sie können den NameIdentifier-Anspruch auch zweimal hinzufügen.
N-aß
@lcssanches src/yourProjectCore/Authorization/Users/AppUserManager.cscheck this out
AmiNadimi
1

@ Manish Jain, ich schlage vor, die Methode mit boolescher Rückgabe zu implementieren:

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;
    }
}
FcoJavier99
quelle
0

Ich möchte der brillanten @ AmiNadimi- Antwort für alle, die seine Lösung in .NET Core 3 implementieren möchten, etwas hinzufügen :

Zunächst sollten Sie die Signatur der SignInMethode in der UserManagerKlasse ändern von:

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

zu:

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

Es ist, weil Sie nie verwenden sollten async void, besonders wenn Sie mit arbeiten HttpContext. Quelle: Microsoft Docs

Die letzte, aber nicht zuletzt Ihre Configure()Methode Startup.cssollte enthalten app.UseAuthorizationund app.UseAuthenticationin der richtigen Reihenfolge:

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?}");
});
1_bug
quelle