2

Is there a way to use Dependency Injection to configure the cookie authentication options? I would like to get some of the settings from the database, but I don't have access to the DatabaseContext at this point.

public void ConfigureServices(IServiceCollection services)
{
  ...
  services
            .AddAuthentication(Authentication.scheme)
            .AddCookie(Authentication.scheme, options =>
            {
                options.ExpireTimeSpan = new TimeSpan(30, 0, 0, 0, 0);
                options.Cookie.IsEssential = true;
                options.Cookie.Name = ".AUTH-Cookie";
                options.ReturnUrlParameter = "returnUrl";
                options.LoginPath = "/Security/SignIn";
                options.LogoutPath = "/Security/SignOut";
                options.EventsType = typeof(CookieAuthenticationEvents);
            });
  ...
}

I'm able to use AddOptions() and Configure() to do this with other items in ConfigureServices, but I can't figure out how to do it with the CookieAuthenticationOptions...

services
  .AddOptions<MvcOptions>()
  .Configure<IDisplayMetadataProvider>((options, localizationMetadataProvider) =>
  {
    options.ModelMetadataDetailsProviders.Add(localizationMetadataProvider);
  });

I tried to do the same thing with CookieAuthenticationOptions, but it doesn't appear to work the same way...

Failwyn
  • 767
  • 8
  • 22

2 Answers2

1

For how to get the data from the database in cookie authentication options,here is a simple sample:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<MyDbContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("YourConnnectionString")));

    var sp = services.BuildServiceProvider();
    var myDbContext = sp.GetService<MyDbContext>();
    var data = GetData(myDbContext);

    services.AddAuthentication(Authentication.scheme)
    .AddCookie(Authentication.scheme,options =>
    {
        options.LoginPath = data;
        //...
    });         
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{        
    //be sure you have added authentication middleware
    app.UseAuthentication();

    //if you use asp.net core 3.x,also need to add this
    //app.UseAuthorization();

}
public static string GetData(MyDbContext _context)
{
    //get the data from database
    var data = _context.Tables.Select(j => j.Loginpath).FirstOrDefault();
    return data;
}
Rena
  • 30,832
  • 6
  • 37
  • 72
  • Is building the service provider multiple times considered an acceptable practice? – Failwyn May 29 '20 at 13:48
  • No need to build the service provider multiple times,just use sp.GetService() multiple times to get your service.If my answer helped you,could you accept as answer? – Rena Jun 01 '20 at 01:22
  • I ended up querying the database directly instead of using the DatabaseContext from the services, but since your answer was a viable, functional route, I'll accept it as the answer. I still wish there was a way to use DI the way you can with AddOptions, but it doesn't appear that it's possible. Thanks for your assistance! – Failwyn Jun 02 '20 at 16:04
1

To use Dependency Injection with CookieAuthenticationOptions you must call the AddOptions<>() and Configure<>() methods before calling AddAuthentication() or AddCookie() authentication handlers.

Here is a sample DbContext with a User as the user model

public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
    {

    }

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

public class User
{
    public string Id { get; set; }

    public string CompanyId { get; set; }
}

The code to use dependency injection is below

services.AddOptions<CookieAuthenticationOptions> 
(CookieAuthenticationDefaults.AuthenticationScheme)
 .Configure<ApplicationDbContext>(async (options, context) => 
{
    var user = new User
    {
            Id= Guid.NewGuid().ToString(),
            CompanyId = Guid.NewGuid().ToString(),
    };
    Console.WriteLine($"------Adding user with DI {user.Id.ToString()}");
    await context.Users.AddAsync(user);
    await context.SaveChangesAsync();
}); 

When adding CookieAuthenticationOptions you must provide the name of the Auth Scheme because it is a named instance. CookieAuthenticationDefaults.AuthenticationScheme defaults to the value of "Cookies". You then can configure these options, and this is where dependency injection kicks in.

You must specify what you want to configure in the <>, and this object will be passed into the Configure() method along with the named instance of CookieAuthenticationOptions that you are configuring.

The anonymous/lambda method is async (in this case I use it, but not required) and sends an instance of the options and the specified context into its method.

I create a user using the User class example from above. I create a dummy user to test this and then log the user's id to the console to easily spot it in your logs. I then add the user and save changes to the database and the changes are reflected. This only works/is called when the authentication handler is invoked (ex. logging in/out)

I found this answer based upon these links when attempting to use Redis as my session store and needed Dependency Injection. More Info below

https://stackoverflow.com/a/60394756/14465032

AspNet Core CookieAuthentication with injected SessionStore

John Murphy
  • 57
  • 2
  • 9