0

我需要编写需要ConfigureServices完全执行的业务逻辑。 OnTokenValidated位置很差ConfigureServices

中间件的替代品是什么,AddOpenIdConnect以便我可以 Success完全灵活地调用以使用注入的服务?

        services.AddAuthentication(options =>
        {
            options.DefaultScheme = "cookie";
            //...
        })
        .AddOpenIdConnect("oidc", options =>
        {
            options.Authority = "https://localhost:5001";
            /....
            options.Scope.Add("offline_access");

            options.Events.OnTokenValidated = async n =>
            {
                //Need other services which will only 
                //get injected once ConfigureServices method has fully executed.
            };
        }

参考:为什么 https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-5.0#ASP0000

4

2 回答 2

1

要在OnTokenValidated事件处理程序中解析服务,您可以使用TokenValidatedContext.HttpContext.RequestServices

Events =
{
    OnTokenValidated = async context =>
    {
        var someService = context.HttpContext.RequestServices.GetRequiredService<ISomeService>();
        var result = await someService.DoSomethingAsync();
        // a custom callback
    }
}
于 2021-07-27T16:10:31.143 回答
0

IAuthenticationSchemeProvider您可以在运行时使用和添加身份验证方案IOptionsMonitorCache

public class AuthInitializer
{
    private IAuthenticationSchemeProvider _provider;
    private IOptionsMonitorCache<OpenIdConnectOptions> _optionsCache;
    // other services you need

    public AuthInitializer(IAuthenticationSchemeProvider provider, IOptionsMonitorCache<OpenIdConnectOptions> options)
    {
        _provider = provider;
        _optionsCache = options;
    }

    public Task InitializeAsync(CancellationToken cancellationToken = default)
    {
        // execute some business logic
        // ...

        var schemeName = "OidcCustom1"; // must be unique for different schemes
        var schemeOptions = new OpenIdConnectOptions()
        {
            Authority = "https://demo.identityserver.io/",
            ClientId = "m2m", // fetch credentials from another service or database
            ClientSecret = "secret",
            Events = {
                OnTokenValidated = async context => {
                    var someService = context.HttpContext.RequestServices.GetRequiredService<ISomeService>();
                    var result = await someService.DoSomethingAsync();
                    // handle the event
                }
            }
        };
    
        var scheme = new AuthenticationScheme(schemeName, displayName:null, typeof(OpenIdConnectHandler));
        _provider.TryAddScheme(scheme);
        _optionsCache.TryAdd(
            schemeName,
            schemeOptions
        );
        return Task.CompletedTask;
    }
}

在 DI 中注册这个类:

services.AddTransient<AuthInitializer>();

然后在构建主机后执行它:

public class Program
{
    public static async Task Main(string[] args)
    {
        var host = CreateHostBuilder(args).Build();
        using var scope = host.Services.CreateScope();
        var authInitializer = scope.ServiceProvider.GetRequiredService<AuthInitializer>();
        await authInitializer.InitializeAsync();
        await host.RunAsync();
    }
}

然后你可以像往常一样参考这个认证方案:

services.AddAuthentication(
    options =>
    {
        options.DefaultScheme = "OidcCustom";
    });

或者

[Authorize(AuthenticationSchemes = "OidcCustom")]
[HttpGet]
public async Task<IActionResult> Index(CancellationToken cancellationToken) { ... }
于 2021-07-27T15:55:38.657 回答