web-dev-qa-db-fra.com

Puis-je accéder à une base de données lors du démarrage dans ASP.NET Core?

J'ai récemment travaillé sur une API Web .NET Core. Je viens de tenter une authentification à l'aide de JWT, en suivant le guide sur https://stormpath.com/blog/token-authentication-asp-net-core .

Tout se passait bien jusqu'à ce que je devais remplacer le nom d'utilisateur et les mots de passe codés en dur dans la méthode GetIdentity par une requête de base de données et me rendre compte que je ne savais pas comment accéder à la base de données à partir de ce fichier!

La méthode à laquelle je fais référence est indiquée dans le lien ci-dessous, à la ligne 70. https://github.com/nbarbettini/SimpleTokenProvider/blob/master/test/SimpleTokenProvider.Test/Startup.Auth.cs

Mes questions sont les suivantes.

  1. Puis-je accéder à la base de données ici? Si c'est le cas, comment?
  2. Cela devrait-il être la méthode GetIdentity ou existe-t-il un meilleur moyen?
13
Top Rat

Oui, vous pouvez accéder à la base de données! Le code qui s'exécute dans la méthode Configure peut accéder à tous les services ajoutés dans la méthode ConfigureServices, y compris des éléments tels que les contextes de base de données.

Par exemple, si vous avez un contexte Entity Framework simple:

using Microsoft.EntityFrameworkCore;
using SimpleTokenProvider.Test.Models;

namespace SimpleTokenProvider.Test
{
    public class SimpleContext : DbContext
    {
        public SimpleContext(DbContextOptions<SimpleContext> options)
            : base(options)
        {
        }

        public DbSet<User> Users { get; set; }
    }
}

Et vous l'ajoutez dans ConfigureServices:

services.AddDbContext<SimpleContext>(opt => opt.UseInMemoryDatabase());

Ensuite, vous pourrez y accéder lors de la configuration du middleware:

var context = app.ApplicationServices.GetService<SimpleContext>();

app.UseSimpleTokenProvider(new TokenProviderOptions
{
    Path = "/api/token",
    Audience = "ExampleAudience",
    Issuer = "ExampleIssuer",
    SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256),
    IdentityResolver = (username, password) => GetIdentity(context, username, password)
});

Et réécrivez un peu la méthode GetIdentity:

private Task<ClaimsIdentity> GetIdentity(SimpleContext context, string username, string password)
{
    // Access the database using the context
    // Here you'd need to do things like hash the password
    // and do a lookup to see if the user + password hash exists
}

Je suis l'auteur de l'échantillon original. Désolé, ce n'était pas clair au départ! J'ai essayé d'écrire le délégué IdentityResolver de manière à faciliter la fourniture de vos propres fonctionnalités, comme l'intégration à votre propre base de données (comme ci-dessus) ou le raccordement à ASP.NET Core Identity. Bien sûr, vous êtes libre de jeter mon code et de faire quelque chose de mieux aussi. :)

13
Nate Barbettini

Sur .NET CORE 2.1, transmettez simplement le contexte en tant qu’argument à la méthode Configure:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, YourDbContext context)
{
        //do whatever you want with the context here...
}
3
juanora

La réponse acceptée ne fonctionne pas pour les services ciblés ( scoped services sont créés à la demande, si vous utilisez Entity Framework et ajoutez le contexte avec AddDbContext puis c'est le cas ).

Vous pouvez utiliser les services étendus au démarrage comme suit ( source ):

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    using (var serviceScope = app.ApplicationServices.CreateScope())
    {
        var services = serviceScope.ServiceProvider;
        var myDbContext = services.GetService<MyDbContext>();
    }
}

ou passez-le dans l'argument de la méthode Configure comme indiqué dans la réponse de juanora

3
Florian Moser

Je me trompe peut-être à un autre niveau, mais la solution que j'ai trouvée consiste à créer une portée.

J'ai passé l'application à la place du ctx dans GetIdentity, puis dans GetIdentity à l'aide d'une étendue: 

using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope()) {
    if (serviceScope.ServiceProvider.GetService<YourAppDbContext>() != null) 
    {
      var ctx = serviceScope.ServiceProvider.GetService<YourAppDbContext>();

      if (AnAuthenticateMethodHereMaybe(ctx, username, password)) {
        return Task.FromResult(new ClaimsIdentity(new 
GenericIdentity(username, "Token"), new Claim[] { }));
      }
    }
  }
0
Nick G.