web-dev-qa-db-fra.com

Authentification .NET Core Identity Server 4 et authentification d’identité

J'essaie de comprendre la méthode d'authentification correcte dans ASP.NET Core. J'ai examiné plusieurs ressources (dont la plupart sont obsolètes).

Certaines personnes proposent des solutions alternatives indiquant d'utiliser une solution en nuage telle que Azure AD ou d'utiliser IdentityServer4 et Héberger mon propre serveur de jetons.

Dans l'ancienne version de .Net, l'une des formes d'authentification les plus simples consisterait à créer un principe personnalisé et à stocker des données d'utilisateur d'authentification supplémentaires à l'intérieur.

public interface ICustomPrincipal : System.Security.Principal.IPrincipal
{
    string FirstName { get; set; }

    string LastName { get; set; }
}

public class CustomPrincipal : ICustomPrincipal
{
    public IIdentity Identity { get; private set; }

    public CustomPrincipal(string username)
    {
        this.Identity = new GenericIdentity(username);
    }

    public bool IsInRole(string role)
    {
        return Identity != null && Identity.IsAuthenticated && 
           !string.IsNullOrWhiteSpace(role) && Roles.IsUserInRole(Identity.Name, role);
    }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public string FullName { get { return FirstName + " " + LastName; } }
}

public class CustomPrincipalSerializedModel
{
    public int Id { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }
}

Vous devez ensuite Sérialiser vos données dans un cookie et les renvoyer au client.

public void CreateAuthenticationTicket(string username) {     

    var authUser = Repository.Find(u => u.Username == username);  
    CustomPrincipalSerializedModel serializeModel = new CustomPrincipalSerializedModel();

    serializeModel.FirstName = authUser.FirstName;
    serializeModel.LastName = authUser.LastName;
    JavaScriptSerializer serializer = new JavaScriptSerializer();
    string userData = serializer.Serialize(serializeModel);

    FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
    1,username,DateTime.Now,DateTime.Now.AddHours(8),false,userData);
    string encTicket = FormsAuthentication.Encrypt(authTicket);
    HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
    Response.Cookies.Add(faCookie);
}

Mes questions sont:

  1. Comment puis-je m'authentifier de la même manière que dans les versions précédentes de .Net fonctionne toujours à l'ancienne, ou existe-t-il une version plus récente?.

  2. Quels sont les avantages et les inconvénients de l'utilisation de vos propres versets de serveur de jetons pour créer votre propre principe personnalisé?

  3. Si vous utilisiez une solution en nuage ou un serveur Token distinct, comment l'intégreriez-vous à votre application actuelle, aurais-je encore besoin d'une table d'utilisateurs dans mon application, comment associeriez-vous les deux?

  4. Etant donné qu'il y a tellement de solutions différentes, comment puis-je créer une application d'entreprise, pour permettre la connexion via Gmail/Facebook tout en pouvant être étendue à d'autres SSO?

  5. Quelles sont quelques implémentations simples de ces technologies?
64
johnny 5

TL; DR

IdentityServer = services de chiffrement et de validation de jeton via OAuth 2.0/OpenId-Connect

Identité ASP.NET = stratégie actuelle de gestion des identités dans ASP.NET

Comment puis-je m'authentifier de la même manière que dans les versions précédentes de .Net fonctionne toujours à l'ancienne, ou existe-t-il une version plus récente?

Je ne vois aucune raison pour laquelle vous ne pouviez pas atteindre l'ancien système dans ASP.NET Core, mais en général, cette stratégie a été remplacée par ASP.NET Identity, et ASP.NET Identity est bien vivant dans ASP.NET Core.

https://docs.Microsoft.com/en-us/aspnet/core/security/authentication/identity

ASP.NET Identity utilise un magasin de stockage tel que SQL Server pour stocker les informations utilisateur telles que nom d'utilisateur, mot de passe (haché), email, téléphone et peut facilement être étendu pour contenir FirstName, LastName ou autre. Donc, il n'y a vraiment aucune raison de chiffrer les informations de l'utilisateur dans un cookie et de les transmettre d'un client à un autre. Il prend en charge des notions telles que les revendications utilisateur, les jetons utilisateur, les rôles utilisateur et les connexions externes. Voici les entités dans l'identité ASP.NET:

  • AspNetUsers
  • AspNetUserRoles
  • AspNetUserClaims
  • AspNetUserLogins (pour lier des fournisseurs d'identité externes, tels que Google, AAD)
  • AspNetUserTokens (pour stocker des éléments tels que access_tokens et refresh_tokens amassés par l'utilisateur)

Quels sont les avantages et les inconvénients de l'utilisation de votre propre serveur de jetons vers la création de votre propre principe personnalisé?

Un serveur de jetons serait un système générant une structure de données simple contenant des informations d'autorisation et/ou d'authentification. L'autorisation prend généralement la forme d'un jeton nommé access_token . Ce sont les "clés de la maison", pour ainsi dire, vous permettant de franchir la porte et de vous rendre dans la résidence d'une ressource protégée, généralement une interface Web. Pour l'authentification, le id_token contient un identifiant unique pour un utilisateur/personne. Bien qu'il soit courant de mettre un tel identifiant dans le paramètre access_token, il existe maintenant un protocole dédié à cette fin: OpenID-Connect .

La raison de disposer de votre propre service de jeton de sécurité (STS) serait de protéger vos informations, via une cryptographie, et de contrôler les clients (applications) pouvant accéder à ces ressources. De plus, les standards pour les contrôles d'identité existent maintenant dans les spécifications OpenID-Connect. IdentityServer est un exemple de OAuth 2.0 Authorization Server combiné à un serveur OpenID-Connect Authentication.

Mais rien de tout cela n'est nécessaire si vous souhaitez simplement une table d'utilisateurs dans votre application. Vous n'avez pas besoin d'un serveur de jetons - utilisez simplement l'identité ASP.NET. Identité ASP.NET mappe votre utilisateur sur un objet ClaimsIdentity sur le serveur. Aucune classe IPrincipal personnalisée n'est donc nécessaire.

Si vous utilisiez une solution en nuage ou un serveur Token distinct, comment l'intégriez-vous dans votre application actuelle, aurais-je toujours besoin d'une table d'utilisateurs dans mon application, comment associeriez-vous les deux?

Consultez ces didacticiels pour intégrer des solutions d’identité distinctes à une application: https://identityserver4.readthedocs.io/en/latest/quickstarts/0_overview.htmlhttps://auth0.com/ docs/quickstart/webapp/aspnet-core

Au minimum, vous auriez besoin d'une table à deux colonnes mappant le nom d'utilisateur sur l'identificateur d'utilisateur du fournisseur externe. C'est ce que la table AspNetUserLogins fait dans Identité ASP.NET. Cependant, les lignes de cette table dépendent du fait qu’il s’agit d’un enregistrement d’utilisateur dans AspNetUsers.

ASP.NET Identity prend en charge des fournisseurs externes tels que Google, Microsoft, Facebook, n'importe quel fournisseur OpenID-Connect, Azure AD sont déjà présents. (Google et Microsoft ont déjà implémenté le protocole OpenID-Connect, vous n’avez donc pas besoin de leurs packages d’intégration personnalisés, comme celui-ci , par exemple). De plus, ADFS n'est pas encore disponible sur ASP.NET Core Identity.

Consultez cette documentation pour vous familiariser avec les fournisseurs externes dans ASP.NET Identity:

https://docs.Microsoft.com/en-us/aspnet/core/security/authentication/social/

Etant donné qu'il y a tellement de solutions différentes, comment puis-je créer une application d'entreprise, autoriser la connexion via Gmail/Facebook tout en pouvant être étendu à d'autres SSO

Comme expliqué ci-dessus, ASP.NET Identity le fait déjà. Il est assez facile de créer une table "Fournisseurs externes" et les données pilotent votre processus de connexion externe. Ainsi, lorsqu'un nouveau "SSO" arrive, il suffit d'ajouter une nouvelle ligne avec les propriétés telles que l'URL du fournisseur, l'identifiant du client et le secret qu'il vous donne. ASP.NET Identity a déjà l'interface utilisateur intégrée dans ses modèles Visual Studio, mais reportez-vous à la section Connexion sociale pour obtenir des boutons plus pratiques.

Résumé

Si vous avez simplement besoin d'une table d'utilisateurs avec des capacités de connexion par mot de passe et d'un profil d'utilisateur, alors l'identité ASP.NET est parfaite. Pas besoin d'impliquer des autorités externes. Toutefois, si de nombreuses applications doivent accéder à plusieurs API, il est logique de disposer d'une autorité indépendante pour sécuriser et valider les jetons d'identité et d'accès. IdentityServer convient parfaitement, ou consultez openiddict-core , ou Auth pour une solution en nuage.

Je m'excuse, ce n'est pas trop grave ou trop introductif. S'il vous plaît, n'hésitez pas à interagir pour arriver à la cible que vous recherchez.

Addendum: Authentification par cookie

Pour authentifier à nu avec des cookies, procédez comme suit. Mais, à ma connaissance, un principe de revendication personnalisé n'est pas pris en charge. Pour obtenir le même effet, utilisez la liste Claims de l’objet ClaimPrincipal.

Créez une nouvelle application Web ASP.NET Core 1.1 dans Visual Studio 2015/2017 en choisissant "Aucune authentification" dans la boîte de dialogue. Ajoutez ensuite le paquet:

Microsoft.AspNetCore.Authentication.Cookies

Sous la méthode Configure dans Startup.cs, placez ceci (avant app.UseMvc):

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationScheme = "MyCookieMiddlewareInstance",
    LoginPath = new PathString("/Controller/Login/"),
    AutomaticAuthenticate = true,
    AutomaticChallenge = true
});

Créez ensuite une interface de connexion et publiez le formulaire HTML sur une méthode d’action telle que:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(String username, String password, String returnUrl = null)
{
    ViewData["ReturnUrl"] = returnUrl;
    if (ModelState.IsValid)
    {
        // check user's password hash in database
        // retrieve user info

        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.Name, username),
            new Claim("FirstName", "Alice"),
            new Claim("LastName", "Smith")
        };

        var identity = new ClaimsIdentity(claims, "Password");

        var principal = new ClaimsPrincipal(identity);

        await HttpContext.Authentication.SignInAsync("MyCookieMiddlewareInstance", principal);

        return RedirectToLocal(returnUrl);
    }

    ModelState.AddModelError(String.Empty, "Invalid login attempt.");

    return View();
}

L'objet HttpContext.User doit avoir vos revendications personnalisées et est facilement récupérable dans la collection List du ClaimPrincipal.

J'espère que cela suffira, car une solution/projet complet semble un peu trop pour un article de StackOverflow.

106
travis.js

TL; DR

Je voudrais vraiment montrer une publication complète sur la manière de mettre en œuvre correctement IdentityServer4, mais j'ai essayé d'insérer l'intégralité du texte, mais cela dépassait la limite de ce que StackOverflow accepte, alors je vais plutôt corriger certaines astuces et choses que j'ai apprises.

Quels sont les avantages de l’utilisation d’un serveur de jetons vs ASP identité?

Un serveur de jetons présente de nombreux avantages, mais il ne convient pas à tout le monde. Si vous implémentez une solution de type entreprise, dans laquelle vous voulez que plusieurs clients puissent se connecter, le serveur Token est votre meilleur choix. Toutefois, si vous créez simplement un site Web qui souhaite prendre en charge les connexions externes, vous pouvez vous échapper avec ASP Identité et certains intergiciels.

Conseils d'Identity Server 4

Identity Server 4 est assez bien documenté par rapport à beaucoup d'autres frameworks que j'ai vus, mais il est difficile de repartir à zéro et de voir la situation dans son ensemble.

Ma première erreur a été d'essayer d'utiliser OAuth comme authentification. Oui, il existe des moyens de le faire, mais OAuth est pour une autorisation sans authentification, si vous voulez vous authentifier, utilisez OpenIdConnect (OIDC).

Dans mon cas, je voulais créer un client javascript, qui se connecte à une API Web. J'ai examiné de nombreuses solutions, mais au départ, j'avais essayé d'utiliser le Webapi pour appeler Authentifier auprès d'Identity Server et je voulais que ce jeton persiste, car il avait été vérifié sur le serveur. Ce flux peut potentiellement fonctionner, mais il comporte de nombreuses failles.

Enfin, le bon flux lorsque j'ai trouvé l'exemple de client Javascript, j'ai obtenu le bon flux. Votre client se connecte et définit un jeton. Ensuite, votre API Web consomme le client OIDc, ce qui vérifiera que vous êtes un jeton d'accès contre IdentityServer.

Connexion aux magasins et aux migrations Au début, j'ai eu beaucoup d'idées fausses sur les migrations. J'avais l'impression que l'exécution d'une migration générait le code SQL à partir de la dll en interne, au lieu d'utiliser le contexte que vous avez configuré pour déterminer comment créer le code SQL.

Il existe deux syntaxes pour les migrations, sachant que celle utilisée par votre ordinateur est importante:

dotnet ef migrations add InitialIdentityServerMigration -c ApplicationDbContext

Add-Migration InitialIdentityServerDbMigration -c ApplicationDbContext

Je pense que le paramètre après la migration est le nom, pourquoi vous avez besoin d'un nom. Je ne suis pas sûr. Le ApplicationDbContext est un DbContext Code-First dans lequel vous voulez créer.

Les migrations utilisent un peu de magie automatique pour trouver votre chaîne de connexion à partir de la configuration de votre démarrage, je suppose simplement qu'elle utilisait une connexion à partir de l'Explorateur de serveurs.

Si vous avez plusieurs projets, assurez-vous que vous avez le projet avec le jeu ApplicationDbContext défini comme votre démarrage.

Il y a beaucoup de pièces mobiles lors de la mise en œuvre de l'autorisation et de l'authentification. J'espère que ce message aidera quelqu'un. Le moyen le plus simple de comprendre parfaitement les authentifications est de séparer leurs exemples afin de tout rassembler et de vous assurer de lire la documentation.

8
johnny 5

J'ai toujours utilisé l'autorisation/authentification intégrée dans ASP.NET Identity (et précédemment Membership), j'ai récemment implémenté Auth0 ( https://auth0.com ) et le recommande comme autre chose à essayer.

1
Mark Redman

Identité ASP.NET - Il s’agit de la méthode permettant d’authentifier votre application, qu’il s’agisse de l’authentification de base ou du porteur. Elle nous donne le code prêt à être utilisé pour procéder à l’enregistrement de l’utilisateur, se connecter, changer le mot de passe, etc.

Considérons maintenant que nous avons 10 applications différentes et qu'il n'est pas possible de faire la même chose dans les 10 applications. cette pratique très fragile et très mauvaise.

pour résoudre ce problème, nous pouvons centraliser notre authentification et notre autorisation afin que toute modification apportée à ce changement n’affecte pas toutes nos 10 applications.

Le serveur d'identité vous offre la possibilité de faire de même. nous pouvons créer un exemple d'application Web qui vient d'être utilisé en tant que service d'identité. Il validera votre utilisateur et fournira un jeton d'accès JWT.

0
Amol Aher

Les identifiants sociaux ne sont pas difficiles à implémenter avec Identity, mais une configuration initiale est impliquée et parfois, les étapes que vous trouvez en ligne dans la documentation ne sont pas identiques. Vous pouvez généralement trouver de l'aide à ce sujet dans la section développeurs de la plate-forme que vous essayez de configurer. les connexions sociales pour. Identity est le remplacement de l'ancienne fonctionnalité d'appartenance trouvée dans les versions héritées du framework .net. Ce qui m'a surpris, c'est que les cas d'utilisation d'Edge, comme le passage d'un jeton JWT que vous avez déjà à une API Web, ne sont pas traités nulle part dans les exemples en ligne. même sur pluralsight, je suis sûr que vous n'avez pas besoin de votre propre autorité de jeton pour le faire, mais je n'ai trouvé aucun exemple sur la façon de transmettre des données dans un get ou une publication qui ne traite pas avec un serveur auto-hébergé.

0
webdev8183