none
User-Anmeldung / Registrierung RRS feed

  • Frage

  • Hi,

    ich habe eine neue Standart-Blazor App mit User-Anmeldung als neues Projekt angelegt und versuche mich durch das Projekt zu hangeln um eine Kenntnis darüber zu erlangen, wie die User-Anmeldung und Registrierung abläuft. Auf den ersten Blick sehe ich, dass es sehr kompliziert zu sein scheint. 

    Es gibt <AuthorizeView> Elemente und sehr sehr viele Klassen wie CreateIdentitySchema usw. 

    Weiterhin finde ich Pages, die zur Anmeldung benutzt werden und vorhanden sein müssen gar nicht in meiner Projektmappe... So wird zum Beispiel beim Registrieren auf asp-page="/Account/Register" verwiesen... Ich finde aber gar keine Page dazu... Genau so wenn ich auf "Forgot your Password" klicke werde ich verwiesen auf "Identity/Account/ForgotPassword", jedoch lässt sich das Wort "ForgotPassword" in der ganzen Projektmappe nicht auffinden - aber die Seite öffnet sich. 

    Gibt es irgendwie einen einfacheren Weg eine sichere User-Registrierung durchzuführen? Die Beispielapp erzeugt allein sieben(!!) Tabellen wie AspNetUserClaims, AspNetUsers usw...  Die Useranmeldungen der App landen in der Tabelle AspNetUsers und die hat Spalten wie PasswordHash, Security Stamp,  ConcurrencyStamp..... da blickt doch keiner durch  :S

    Geht es nicht einfach mit einer Tabelle Users und den Spalten Username, Email, Password?  Ich könnte mir vorstellen, z.B. das Passwort als SHA 512 Schlüssel zu speichern. Das sollte doch genügend Sicherheit mit sich bringen, wenn ich zumindest an das vom User eingegebene Passwort einen eigenen Anhang anfüge und daraus den SHA Schlüssel generiere... Was wären denn die Mindestanforderungen an eine solche Registrierung?

    Freu mich auf Eure Hilfe hierzu.

    LG


    .::datekk::.



    • Bearbeitet datekk2 Dienstag, 29. Oktober 2019 09:05
    Dienstag, 29. Oktober 2019 08:48

Alle Antworten

  • Hallo,

    im Grunde hat man immer die Wahl zwischen der Standard Implementierung und einer eigenen. Wenn Du eine eigene haben willst, solltest Du dich zuerst in die Standard Implementierung einlesen.

    Die ganze Tabellen in der DB kommen vom IdentityUser und sind nötig. Ich würde dir empfehlen das auch so zu nutzen und keine Änderungen an den Tabellen vorzunehmen.

    Wie sich der User aber registriert oder anmeldet ist eine andere Geschichte. Hier kann man eigene Pages bereitstellen. 

    Ich persönlich nutze Blazor WebAssembly und habe hier eigene Pages und eine Web Api zu Registrierung und Anmeldung. Wie das aber bei Blazor Server Apps funktioniert weiß ich nicht.


    Gruß Thomas
    13 Millionen Schweine landen jährlich im Müll
    Dev Apps von mir: UWP Segoe MDL2 Assets, UI Strings

    Mittwoch, 30. Oktober 2019 13:13
  • Ok, bei der "Standard Implementierung" blicke ich nicht durch. Über den Code habe ich da keine Chance mir was rauszulesen, da reichen meine Kenntnisse bei weitem noch nicht. Wo kann ich mich denn "einlesen"? Gibt es irgenwo eine verständliche Beschreibung des Ganzen?

    Im Grunde geht es doch nur um den Schutz der Login-Daten. Ich habe mir überlegt, in meiner User-Tabelle ein GUID Feld mit einem uniqueidentifer anzulegen. Wenn der User sich registriert wird sein Passwort an den Server gesendet, dieser hängt an den String die GUID an. Dann erstelle ich aus diesem neuen String wiederum einen String - diesmal allerdings einen SHA 512 Schlüssel. Und diesen speichere ich in der Passwort Spalte ab.

    Das sollte doch ausreichen oder?

    Die Formulare dafür baue ich selbst. Hast Du ggf. noch einen Tipp für die Zusendung der Bestätigungs- und Passwortänderungsmails? Ggf. gibt es da ja einen externen Service den ich bedienen kann oder baue ich das besser in der eigenen Anwendung über SMPT?

    LG

    datekk


    .::datekk::.

    Mittwoch, 30. Oktober 2019 15:48
  • Klar kann man sich was eigenes zusammenbasteln nur dann kannst Du ASP.NET Core Identity nicht nutzen.

    Eine Website läuft auf den Rechner des Users und nicht auf deinem Server. Die Kommunikation zwischen Client und Server erfolgt über das Netzwerk. Der Server muss aus dieser Kommunikation entnehmen können um welchen User es sich hier handelt, welche Rechte der User hat und so weiter. Das alles kann man selbst entwickeln oder einfach ASP.NET Identity verwenden. Mit ASP.NET Identity kann man auch externe Auth Anbieter nutzen wie z.B. Microsoft, Google, Facebook und alle anderen die oAuth nutzen.

    Hier die Doku zu Identity Einführung in die Identität auf ASP.net Core und hier zu Blazor Authentifizierung und Autorisierung in ASP.NET Core Blazor


    Gruß Thomas
    13 Millionen Schweine landen jährlich im Müll
    Dev Apps von mir: UWP Segoe MDL2 Assets, UI Strings

    Mittwoch, 30. Oktober 2019 18:08
  • Hallo Thomas,

    leider kann ich Deiner Antwort nicht entnehmen, ob die von mir geschilderte Vorgehensweise praktikabel ist oder nicht. Die Website wird meines Erachtens natürlich auf dem Rechner des Clienten ausgeführt, Serveraktionen oder C# Code stattdessen nur auf dem Server bzw. sogar nur auf dem SQL Server.

    Daher denke ich, dass meine geschilderte Vorgehensweise sicher sein müsste. Oder?


    .::datekk::.

    Mittwoch, 30. Oktober 2019 18:53
  • Ich wollte dir mit meiner Antwort klar machen das es nicht nur darum geht ein Passwort sicher abzulegen. Der gesamte Prozess erfordert einiges mehr. Du hast bisher kein gesamt Konzept vorgelegt das man in irgendeiner Form bewerten könnte. Ich glaube auch nicht das dir bewusst wie ein gesamt Konzept aussehen könnte (ist nicht böse gemeint). Du hast in einem Thread geschrieben das Du gern Empfehlungen haben willst "um nicht in die falsche Richtung zu rennen" Meine Empfehlung ist, arbeite dich in ASP.NET Core Identity ein. Dieses Framework bietet alles was man braucht. Klar könnte ich dir hier eine Anleitung schreiben wie das System genau funktioniert aber die Infos findest Du auch in der Doku. Zudem wäre das ein sehr langer Post für den ich lange brauchen würde.

    Mir ist bewusst das es anstrengend ist wieder ein neues Framework zu erlernen obwohl auf dem ersten Blick eine Lösung einfach sein könnte. Aus meiner mehrjährigen Erfahrung in der Webentwicklung kann ich dir sagen das diese Thematik sehr komplex ist und mit ASP.NET Core Identity sehr einfach zu lösen ist.

    Z.B. sieht meine Web Api so aus

    [HttpPost]
    [Route("register")]
    [AllowAnonymous]
    public async Task<IActionResult> Register(LoginViewModel vm)
    {
        try
        {
            var user = await _userManager.FindByNameAsync(vm.Email);
            if (user != null)
            {
                return BadRequest(Shared.ErrorType.RegUserIsExist);
            }
    
            user = new AppUser()
            {
                UserName = vm.Email,
                Email = vm.Email
            };
            var res = await _userManager.CreateAsync(user, vm.Password);
            if (res.Succeeded)
            {
                var token = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                var b = Encoding.UTF8.GetBytes(token);
                var t = Microsoft.AspNetCore.WebUtilities.WebEncoders.Base64UrlEncode(b);
                var url = $"{Shared.GlobalConfig.WebApiUri}Confirm/Email?Token={t}&Id={user.Id}";
    
                //Eigene Klasse die einfach per STMP eine Mail versendet
                await SendMail.SendEmailConfirmMail(user.Email, url);
    
                return Ok();
            }
    
            Shared.ErrorType errorType = Shared.ErrorType.Unknown;
    
            if (res.Errors.Count() > 0)
            {
                var err = res.Errors.ElementAt(0);
    
                switch (err.Code)
                {
                    case "PasswordRequiresDigit":
                        errorType = Shared.ErrorType.RegPasswordRequiresDigit;
                        break;
                    case "PasswordRequiresLower":
                        errorType = Shared.ErrorType.RegPasswordRequiresLower;
                        break;
                    case "PasswordRequiresNonAlphanumeric":
                        errorType = Shared.ErrorType.RegPasswordRequiresNonAlphanumeric;
                        break;
                    case "PasswordRequiresUpper":
                        errorType = Shared.ErrorType.RegPasswordRequiresUpper;
                        break;
                    case "PasswordTooShort":
                        errorType = Shared.ErrorType.RegPasswordTooShort;
                        break;
                    case "InvalidEmail":
                        errorType = Shared.ErrorType.RegInvalidEmail;
                        break;
                }
            }
    
            return BadRequest();
        }
        catch (Exception)
        {
    
        }
        return BadRequest(Shared.ErrorType.Unknown);
    }


    [HttpPost]
    [Route("login")]
    [AllowAnonymous]
    public async Task<IActionResult> Login(LoginViewModel loginViewModel)
    {
        try
        {
            var user = await _userManager.FindByNameAsync(loginViewModel.Email);
            if (user == null)
            {
                return BadRequest(Shared.ErrorType.LoginBadUserOrPasswort);
            }
    
            var result = await _signInManager.PasswordSignInAsync(loginViewModel.Email, loginViewModel.Password, false, false);
            if (result.Succeeded)
            {
                var claims = new[]
                {
                            new Claim(ClaimTypes.Name, user.UserName)
                        };
    
                var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Startup.SecureKey));
                var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
                var expiry = DateTime.Now.AddDays(1);
    
                var token = new JwtSecurityToken(
                    Shared.GlobalConfig.WebApiUri,
                    Shared.GlobalConfig.WebApiUri,
                    claims,
                    expires: expiry,
                    signingCredentials: creds
                );
    
                loginViewModel.Password = "";
                loginViewModel.Token = new JwtSecurityTokenHandler().WriteToken(token);
                return Ok(loginViewModel);
            }
            else
            {
                return BadRequest(Shared.ErrorType.LoginBadUserOrPasswort);
            }
        }
        catch (Exception)
        {
    
        }
    
        return BadRequest(Shared.ErrorType.Unknown);
    }

    Ich nutze deswegen eine WebApi weil sich an dieser nicht nur die Blazor App anmeldet/registriert sonder auch meine Win10, Android und iOS App. Alles kein Problem mit ASP.NET Identity


    Gruß Thomas
    13 Millionen Schweine landen jährlich im Müll
    Dev Apps von mir: UWP Segoe MDL2 Assets, UI Strings



    Mittwoch, 30. Oktober 2019 23:26
  • Ok. Das Problem ist, ich habe mit meiner Blazor App bereits begonnen. Kann ich das Framework nachträglich dort noch einfügen? Wenn ja, wie?

    Ich bin vom Wissenstand noch zu weit weg um die Dokumentation zu verstehen. Wie schon geschrieben ist bei mir alles Learning by Doing.

    Vielleicht kannst Du mir helfen, Schritt für Schritt dieses Framework in meine Blazor App zu integieren?

    Ich verstehe wie gesagt nicht, wo die Pages des Frameworks liegen? Wo ist die ForgotPassword-Page? Sie ist da im laufenden Projekt aber taucht nicht mal mit dem Namen in der Projektmappe auf... Ich finde nur _LoginPartial und Logout Warum haben die Klassen wie CreateIdentitySchema zig Nullen vor dem Namen?

    Wärst Du bereit, mich hierbei zu begleiten und mir (und den anderen Einsteigern hier) Schritt für Schritt die Implementierung des Frameworks und seine grundlegende Funktionsweise beizubringen? Sicher ist wieder wie bei Blazor selbst alles leicht verständlich, wenn man ein paar Grundlagen an die Hand bekommt.

    also Schritt 1: Ich habe gesehen, dass das IdentityFramework ein NuGet Paket ist. Also lade ich mir dieses mal runter, richtig? Wie gehts weiter?


    .::datekk::.

    Donnerstag, 31. Oktober 2019 09:05
  • Ja es ist ein Nuget Paket und in diesem sind auch die Pages. Diese kann man nach meinem Wissensstand auch nicht bearbeiten.

    Für eine ausführliche Anleitung habe ich im moment keine Zeit. Nutze doch erstmal die Standard Pages. Sobald ich Zeit habe schreibe ich eine Anleitung.

    Erstelle dir ein neues Projekt mit Auth und kopiere alles was mit Auth zu tun hat in dein bestehendes Projekt. Das ist der Areas Ordner, die Migrations, der ConnectionStrings in appsettings.json und der ApplicationDbContext, die Konfiguration in der Startup.cs und LoginDisplay.razor

    Vergleiche auch die Nuget Pakete


    Gruß Thomas
    13 Millionen Schweine landen jährlich im Müll
    Dev Apps von mir: UWP Segoe MDL2 Assets, UI Strings


    Donnerstag, 31. Oktober 2019 13:53