web-dev-qa-db-fra.com

Identity 2.0 avec des tables personnalisées

Je suis nouveau dans l'identité ASP.NET et j'essaie encore de comprendre comment tout cela fonctionne. Malheureusement, j'ai trouvé que beaucoup de tutoriels que j'ai essayés sont pour Identity 1.0, alors que j'essaie de travailler avec Identity 2.0.

Le plus gros problème auquel je suis confronté est quelque chose qui, à mon avis, serait simple mais qui ne l’a pas été Ce que j'essaie de faire est d'utiliser une base de données existante avec une table utilisateur existante. Actuellement, tout ce que je peux sembler faire est de demander à Identity de créer ses propres tables pour stocker les données utilisateur. Je ne souhaite pas utiliser Entity Framework, mais j'ai eu beaucoup de difficulté à séparer Entity Framework d'Identity 2.0.

Alors que j'utilisais SQL Server, je pensais essayer d'implémenter le fournisseur personnalisé pour MySQL à ce lien: http://www.asp.net/identity/overview/extensibility/implementing-a-custom -mysql-aspnet-identity-storage-provider et https://github.com/raquelsa/AspNet.Identity.MySQL . Cela semble fonctionner sous Identité 1 uniquement. Il semble qu'il y en ait un plus récent, qui utilise cependant Entity Framework. J'ai également essayé https://github.com/ILMServices/RavenDB.AspNet.Identity .

Avec tout ce que j'ai essayé, je suis coincé avec la ligne suivante:

var manager = new IdentityUserManager(new UserStore<IdentityUser>(context.Get<ApplicationDbContext>()));

Le problème auquel je suis confronté est que je dois supprimer la classe ApplicaitonDbContext conformément aux instructions de RavenDB, mais je ne sais pas quoi mettre dans cette ligne à la place.

Les erreurs que je reçois sont:

Le type non générique 'AspNet.Identity.MySQL.UserStore' ne peut pas être utilisé avec des arguments de type.

et

Le type ou le nom de l'espace de noms 'ApplicationDbContext' est introuvable (vous manque une directive using ou une référence Assembly?)

La deuxième erreur est à prévoir, cependant je ne suis pas sûr de ce qu'il faut utiliser dans cette ligne de code à la place. Quelqu'un a-t-il déjà implémenté un fournisseur personnalisé sans utiliser Entity Framework?

Merci.

_ {Update 1:} _

J'ai essayé le tutoriel suivant [ http://aspnetguru.com/customize-authentication-to-your-own-set-of-tables-in-asp-net-mvc-5/ ] mais il semble être incomplet, avec des erreurs de compilation ou d'exécution en suivant exactement le tutoriel. Quelques problèmes que j'ai encore sont ...

Lors du remplacement de toutes les instances de "ApplicationUser" par "User", un problème se produit avec la ligne suivante dans IdentityConfig.cs

var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<MyDbContext>()));

Changer ApplicationUser en utilisateur génère l'erreur suivante

Le type "WebApplicationTest2.Models.User" ne peut pas être utilisé comme paramètre de type "TUser" dans le type ou la méthode générique "Microsoft.AspNet.Identity.EntityFramework.UserStore". Il n'y a pas de conversion de référence implicite de 'WebApplicationTest2.Models.User' en 'Microsoft.AspNet.Identity.EntityFramework.IdentityUser'.

J'ai également du mal à comprendre comment utiliser le gestionnaire d'utilisateurs et de nombreuses méthodes ASync. Les lignes suivantes ne fonctionnent pas:

AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, await user.GenerateUserIdentityAsync(UserManager));

Dans AccountController.cs avec les erreurs suivantes:

La meilleure méthode surchargée pour 'Microsoft.Owin.Security.IAuthenticationManager.SignIn (Microsoft.Owin.Security.AuthenticationProperties, paramètres System.Security.Claims.ClaimsIdentity [])' contient des arguments non valides.

'WebApplicationTest2.Models.User' ne contient pas de définition pour 'GenerateUserIdentityAsync' et aucune méthode d'extension 'GenerateUserIdentityAsync' n'accepte un premier argument de type 'WebApplicationTest2.Models.User' (il vous manque une directive d'utilisation ou une référence d'assembly ?)

29
joshhendo

Dans vos exemples, vous semblez vouloir remplacer la DbContext par quelque chose d'autre, mais je pense qu'en réalité, vous devez concentrer vos efforts plus haut.

Le cadre a une classe UserManager qui a la responsabilité de gérer, mais pas de stocker, les utilisateurs et leurs informations associées. Lorsqu'il souhaite stocker les utilisateurs (ou leurs informations associées), le comportement par défaut consiste à utiliser le UserStore<IdentityUser> fourni, qui sait comment stocker les instances IdentityUser dans une base de données à l'aide de DbContext.

Dans le framework 2.0, les différents bits du stockage d’identité ont été divisés en plusieurs interfaces. L'implémentation par défaut fournie, UserStore<IdentityUser> implémente plusieurs de ces interfaces et stocke toutes les données correspondantes dans la base de données à l'aide de DBContext

Si vous examinez la définition de UserStore basé sur une structure d'entité fournie par défaut, vous pouvez constater qu'il implémente bon nombre de ces petites interfaces:

public class UserStore<TUser, TRole, TKey, TUserLogin, TUserRole, TUserClaim> : IUserLoginStore<TUser, TKey>, 
IUserClaimStore<TUser, TKey>, IUserRoleStore<TUser, TKey>, IUserPasswordStore<TUser, TKey>, 
IUserSecurityStampStore<TUser, TKey>, IQueryableUserStore<TUser, TKey>, IUserEmailStore<TUser, TKey>, 
IUserPhoneNumberStore<TUser, TKey>, IUserTwoFactorStore<TUser, TKey>, IUserLockoutStore<TUser, TKey>, 
IUserStore<TUser, TKey>, IDisposable 
where TUser : IdentityUser<TKey, TUserLogin, TUserRole, TUserClaim>
where TRole : IdentityRole<TKey, TUserRole>
where TKey : Object, IEquatable<TKey>
where TUserLogin : new(), IdentityUserLogin<TKey>
where TUserRole : new(), IdentityUserRole<TKey>
where TUserClaim : new(), IdentityUserClaim<TKey>

Comme vous ne voulez pas du tout utiliser Entity Framework, vous devez fournir vos propres implémentations de certaines de ces interfaces clés qui stockeront ces données aux endroits où vous souhaitez les stocker. L'interface principale est IUserStore<Tuser,TKey> . ceci définit le contrat de stockage des utilisateurs possédant une clé d'un type particulier. Si vous souhaitez uniquement stocker des utilisateurs et aucune autre information, vous pouvez implémenter cette interface, puis passer votre implémentation à la variable UserManager. Vous devriez pouvoir continuer.

Il est peu probable que cela suffise, car vous voudrez probablement des mots de passe, des rôles, des identifiants de connexion, etc. pour vos utilisateurs. Si c'est le cas, vous devez faire en sorte que votre classe implémentant IUserStore<Tuser,TKey> implémente également IUserPasswordStore<TUser, TKey>, IRoleStore<TRole, TKey> et IUserClaimStore<TUser, TKey>.

Vous pouvez trouver une liste de toutes les interfaces sur MSDN ici

Selon les bits que vous souhaitez utiliser, vous devez implémenter ces interfaces. 

Vous devrez probablement également définir vos propres versions des classes Identity* qui existent déjà pour le framework Entity . Vous aurez donc besoin de votre propre classe IdentityUser qui représente les utilisateurs que vous souhaitez stocker et de IdentityUserClaim pour les revendications des utilisateurs. Je n'ai pas fait cela moi-même, alors je ne suis pas tout à fait sûr, mais j'ai le sentiment que vous devrez le faire.

Scott Allen a un bon article sur les différentes parties du modèle qui pourraient être utiles.

En ce qui concerne vos problèmes avec cette ligne:

AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, await user.GenerateUserIdentityAsync(UserManager));

Il existe une méthode appelée GenerateUserIdentityAsync qui est définie sur Applicationuser et qui étend IdentityUser. Il est défini dans le projet de modèle je crois et ressemble à ceci:

public class ApplicationUser : IdentityUser 
{    
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(
    UserManager<ApplicationUser> manager) {
    // Note the authenticationType must match the one 
    // defined in CookieAuthenticationOptions.AuthenticationType
    var userIdentity = 
        await manager.CreateIdentityAsync(this, 
            DefaultAuthenticationTypes.ApplicationCookie);
    // Add custom user claims here
    return userIdentity;
    }
}

Comme vous n'utilisez plus l'entité structure IdentityUser, vous devez définir une méthode similaire ou votre propre classe User ou implémenter la même fonctionnalité d'une autre manière (par exemple, en appelant simplement await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie)).

37
Sam Holder

Je suis assez nouveau pour Identity moi-même. Votre entité utilisateur implémente-t-elle l'interface IUser? par exemple.

public partial class User : IUser<Guid> //Whatever your key is
{
    public Task<ClaimsIdentity> GenerateUserIdentityAsync(ApplicationUserManager manager)
    {
        return Task.FromResult(GenerateUserIdentity(manager));
    }

    public ClaimsIdentity GenerateUserIdentity(ApplicationUserManager manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = manager.CreateIdentity<User, Guid>(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        return userIdentity;
    }
}

Ensuite, pour vous connecter, vous pouvez appeler ce qui précède:

public async Task SignInAsync(User user, bool isPersistent)
    {
        var userIdentity = await user.GenerateUserIdentityAsync(UserManager);
        AuthenticationManager.SignIn(
            new AuthenticationProperties
            {
                IsPersistent = isPersistent
            },
            userIdentity
        );
    }   
1
Jenkie

Je pense que cela a été mis à jour récemment à ceci dans ApplicationUser:

public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager, string authenticationType)
{
    // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
    var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
    // Add custom user claims here
    return userIdentity;
}

On l’appelle comme ceci de AccountController -> GetExternalLogin

ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(UserManager,
    OAuthDefaults.AuthenticationType);
ClaimsIdentity cookieIdentity = await user.GenerateUserIdentityAsync(UserManager,
    CookieAuthenticationDefaults.AuthenticationType);
1
Ogglas