web-dev-qa-db-fra.com

Comment créer un objet ClaimsIdentity pour Asp.NET MVC 5?

Je travaille dans une application .NET MVC 5. Je ne veux pas utiliser Entity Framework. Je souhaite m'authentifier auprès d'une base de données RavenDB. Il me semble que je souhaite remplacer la UserManager fournie avec le contrôleur de compte. Je pense que je peux réécrire toutes les fonctions de UserManager pour qu'elles fonctionnent avec ma base de données, sauf que je ne comprends pas l'objet ClaimsIdentity.

Dans la méthode SignInAsync, il existe un appel à UserManager.CreateIdentityAsync(...). Je sais qu'il renvoie un objet ClaimsIdentity. Ce que je ne sais pas, c'est comment créer un objet ClaimsIdentity par moi-même.

Je vois qu'il a 4 propriétés Actor, BootstrapContext, Claims et Label. Je ne sais pas à quoi servent ces propriétés et je ne sais pas comment les générer correctement. Je suppose que les générer correctement est important car c'est la façon dont le cookie d'authentification est créé.

J'ai regardé l'explication de l'objet ClaimsIdentity ici , mais cela ne m'a pas vraiment aidée à comprendre.

Si je pouvais voir le code pour CreateIdentityAsync(), cela aiderait probablement.

Si je me trompe complètement, faites-le-moi savoir. Sinon, si quelqu'un pouvait m'indiquer comment générer l'objet ClaimsIdentity, cela serait utile.

ClaimsIdentity identity = new ClaimsIdentity
{
    Actor = ????,
    BootstrapContext = ?????,
    Claims = ?????,
    Label = ?????
}
27
user1304444

Le lien suivant peut peut-être aider:

var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.Name, "Brock"));
claims.Add(new Claim(ClaimTypes.Email, "[email protected]"));
var id = new ClaimsIdentity(claims,DefaultAuthenticationTypes.ApplicationCookie);

var ctx = Request.GetOwinContext();
var authenticationManager = ctx.Authentication;
authenticationManager.SignIn(id);
41
Vlince

Je pense que vous "allez à ce sujet tout faux". ASP.NET Identity Framework a été conçu dans un souci de persistance connectable. La bonne façon de remplacer RavenDB par EF n’est PAS de remplacer UserManager. Il s’agit plutôt de mettre en place une variable de remplacement UserStore. Ainsi, la ligne dans la AccountController qui crée la UserManager changerait de:

public AccountController()
    : this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))

À:

public AccountController()
    : this(new UserManager<ApplicationUser>(new RavenDBUserStore<ApplicationUser>/* connection info here*/)))

RavenDBUserStore serait une classe que vous avez écrite et qui implémenterait IUserStore, IUserPasswordStore et toute autre interface * Store dont vous aviez besoin pour votre application particulière.

Cette approche vous évite d'avoir à tout comprendre et à tout réimplémenter dans UserManager et vous permet de tirer parti des améliorations futures apportées à UserManager par MS.

Pour plus d'informations sur cette procédure, voir Vue d'ensemble des fournisseurs de stockage personnalisé pour l'identité ASP.NET et l'exemple de Implémentation d'un fournisseur de stockage d'identité MySQL ASP.NET personnalisé . Vous devez également consulter le code du paquet RavenDB.AspNet.Identity Nuget créé par David Boike mentionné dans sa réponse . La source est sur github à https://github.com/ILMServices/RavenDB.AspNet.Identity/tree/master/RavenDB.AspNet.Identity

Voici ce que je suis venu avec. J'aimerais savoir si c'est la bonne façon d'accomplir cette tâche.

Travaillant sur un site Web par défaut de MVC5, je suis allé au contrôleur de compte et j'ai trouvé la fonction SignInAsync(). Je l'ai ajusté comme suit:

    private async Task SignInAsync(ApplicationUser user, bool isPersistent)
    {
        AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
        //var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie); --> this is where I want to get rid of UserManager
        List<Claim> claims = new List<Claim>{
            new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", user.Name), //user.Name from my database
            new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", user.Id), //user.Id from my database
            new Claim("http://schemas.Microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "MyApplication"),
            new Claim("FirstName", user.FirstName) //user.FirstName from my database
        };
        ClaimsIdentity identity = new System.Security.Claims.ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie, ClaimTypes.Name, ClaimTypes.Role);

        AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
    }

N'oubliez pas que cela nécessite également de modifier la fonction [HttpPost] Login pour que l'utilisateur soit placé dans ma base de données au lieu d'utiliser la fonction UserManager.FindAsync().

Les parties LogIn/LogOff du site par défaut semblent fonctionner correctement après ces ajustements. Je vais laisser cette réponse ici pendant un moment avant de l'accepter au cas où quelqu'un pourrait me dire pourquoi je ne devrais pas le faire de cette façon.

9
user1304444

J'ai créé une implémentation RavenDB pour la nouvelle identité ASP.NET MVC 5 et l'ai publiée sous forme de package NuGet. Cela pourrait fonctionner pour vous.

http://www.nuget.org/packages/RavenDB.AspNet.Identity/

C'est un peu avant-première mais je l'utilise dans un vrai projet.

Voici le projet de GitHub et un fil court sur le groupe de discussion RavenDB à ce sujet.

6
David Boike

J'espère qu'il n'y a pas de problème à ce que je poste un Q/A ici, ce qui ne rentre pas dans la section commentaires

@Katstevens vous semble-t-il correct: mon coéquipier a trouvé cette solution et l'a utilisée pendant longtemps; je l'ai donc implémentée dans ma propre application ajoutez la revendication à mes données personnalisées, sur la méthode de démarrage Global.aspx:

protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
    HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
    if (authCookie != null)
    {
        FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
        CustomPrincipalSerializeModel serializeModel = JsonConvert.DeserializeObject<CustomPrincipalSerializeModel>(authTicket.UserData);
        CustomPrincipal newUser = new CustomPrincipal(authTicket.Name);
        newUser.UserId = serializeModel.UserId;
        newUser.UserName = serializeModel.UserName;
        newUser.NameFamily = serializeModel.NameFamily;
        newUser.IP = serializeModel.IP;
        newUser.roles = serializeModel.roles;
        HttpContext.Current.User = newUser;
        System.Threading.Thread.CurrentPrincipal = newUser;

        //Added by myself... (make UserId work as identity.GetUserId())
        (newUser.Identity as ClaimsIdentity)?.AddClaims(new List<Claim>{
            new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", authTicket.Name), //user.Name from my database
            new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", serializeModel.UserId), //user.Id from my database
            new Claim("http://schemas.Microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "RealEstate"), //MyApplication
        });
    }
}

Oui, cela fonctionne, mais est-ce une bonne chose de le faire comme ceci? D'où devraient provenir les données, où cela devrait-il se produire? ETC .... Les données sont-elles irremplaçables? et sécurisé?

0
deadManN