Estoy usando la autenticación de Google en mi aplicación web y las claves de OAuth actualmente están codificadas en ConfigureServices:
services.AddAuthentication() .AddGoogle(options => { options.ClientId = "my-client-id"; options.ClientSecret = "my-client-secret"; });Sin embargo, me gustaría darle al administrador del sitio la oportunidad de cambiar ClientId y ClientSecret desde la página de configuración de la aplicación web, preferiblemente sin tener que reiniciar el servidor.
Para hacer esto, tendría que activar de alguna manera una reconfiguración del servicio de Google y el objeto GoogleOptions cuando el usuario presione 'Guardar' en la página de configuración. Esto es con lo que estoy teniendo problemas. Además, me gustaría almacenar esta configuración en un EF Core DbContext y no en un archivo de configuración físico.
Hasta ahora, he intentado mover la configuración a una clase separada que implementa IPostConfigureOptions. Esto debería permitirme inyectar el contexto de mi base de datos, porque según la documentación, se supone que PostConfigure se ejecuta después de que se hayan producido todas las demás configuraciones. La configuración se carga correctamente desde esta nueva clase, pero la inyección del contexto DB falla con la siguiente excepción:
System.InvalidOperationException: Cannot consume scoped service 'AppDatabase' from singleton 'IOptionsMonitor`1[GoogleOptions]'Esto es extraño, porque ConfigureGoogleOptions está registrado como Scoped, y no como Singleton.
Aquí está mi clase de opciones:
public class ConfigureGoogleOptions : IPostConfigureOptions<GoogleOptions> { private readonly AppDatabase database; public ConfigureGoogleOptions(AppDatabase database) { this.database = database; } public void PostConfigure(string name, GoogleOptions options) { options.ClientId = "my-client-id.apps.googleusercontent.com"; options.ClientSecret = "my-client-secret"; } }Y registrándolo en ConfigureServices:
services.AddScoped<IPostConfigureOptions<GoogleOptions>, ConfigureGoogleOptions>(); Incluso si la inyección de la base de datos funcionó, todavía hay un segundo problema. La función PostConfigure en mi clase solo se llama una vez después de que se inicia la aplicación, y nunca más. Supongo que almacena en caché la configuración en algún lugar, y no sé cómo invalidar o deshabilitar este caché para poder proporcionar valores dinámicamente.
Breve resumen / tl; dr:
Quiero cargar la configuración de ClientId y ClientSecret del servicio Google OAuth desde mi propia base de datos, y quiero poder cambiarlos dinámicamente mientras el servidor se está ejecutando.
Internamente, el controlador de Google usará IOptionsMonitor<GoogleOptions> para obtener GoogleOptions una vez o hasta que se vuelva a cargar (como cuando las opciones están vinculadas desde un archivo de configuración y guardar el archivo activará la recarga). IOptionsMonitor utilizará internamente IOptionsMonitorCache y esta caché se registra como singleton. Entonces, la instancia de opciones que obtiene de IOptionsMonitor<GoogleOptions> es la misma (referencia) con AuthenticationHandler<GoogleOptions>.Options que se usa para varias operaciones dentro del controlador. Incluso otro código si usa esas opciones debería obtenerlo correctamente de IOptionsMonitor<GoogleOptions> .
Entonces, para cambiar las opciones en tiempo de ejecución, es tan simple como esto:
//inject the IOptionsMonitor<GoogleOptions> into _googleOptionsMonitor; var runtimeOptions = _googleOptionsMonitor.Get(GoogleDefaults.AuthenticationScheme); //you change properties of runtimeOptions here //... El punto importante aquí es que necesitamos usar GoogleDefaults.AuthenticationScheme como la clave para obtener la instancia correcta de opciones. IOptionsMonitor.CurrentValue utilizará la clave predeterminada de Options.DefaultName (que es una cadena vacía).