【问题标题】:aspnetcore2.0 using services with AzureAd authenticationasp net core 2.0 使用带有 Azure 广告身份验证的服务
【发布时间】:2020-05-03 21:23:15
【问题描述】:

我即将将 ASP.NET Core MVC Web 应用程序从 1.1 迁移到 2.0。该应用使用 AzureAd 进行身份管理。

在 1.1 中,我在 Startup.cs(Configure())中处理了 openidconnect 事件(如 OnTokenReceiverOnAuthorizationCodeReceivedOnRemoteFailure 等),我可以在其中使用依赖注入。我已经注入了很多服务,比如 EF db 上下文,并在事件处理程序中使用了它们。 升级到 2.0 后,我不得不将整个身份验证迁移到 AzureAdAuthenticationBuilderExtensionsConfigureAzureOptions 类(实现 IConfigureNamedOptions<OpenIdConnectOptions> 接口),其中(如我所见)DI 不能使用。

所以现在只有这个在 Startup 的 ConfigureServices 中:

services.AddAuthentication(sharedOptions =>
{
    sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddAzureAd(options => Configuration.Bind("AzureAd", options))
.AddCookie();

我使用此指南进行迁移:https://docs.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/identity-2x#authentication-middleware-and-services

有人知道如何在 openidconnect 事件中使用服务?

更新:我能够在@Balah 的回答的帮助下解决这个问题。基本上解决方案是使用通用的.AddOpenIdConnect(),而不是创建一个名为.AddAzureAd()的扩展。
对答案的一个小补充:由于身份验证部分已从 Configure() 移动到 ConfigureServices() 未启用 DI 且尚未注册服务,因此获取这些服务的方法毕竟是这样的:

var scopeFactory = services
   .BuildServiceProvider()
   .GetRequiredService<IServiceScopeFactory>();
var scope = scopeFactory.CreateScope();
var provider = scope.ServiceProvider;
var dbContext = provider.GetRequiredService<ApplicationDbContext>();
var graphSdkHelper = provider.GetRequiredService<IGraphSDKHelper>();
var memoryCache = provider.GetRequiredService<IMemoryCache>();
...

请记住,您必须在此代码上方添加这些服务!

【问题讨论】:

    标签: c# asp.net-core entity-framework-core asp.net-core-2.0


    【解决方案1】:

    您会发现您提到的那些事件已被移至身份验证选项上的(恰当命名的)Events 属性中。

    可以通过HttpContext.RequestServices 属性访问在 DI 容器中注册的任何服务,如下所示:

    services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
        .AddOpenIdConnect(o =>
        {
            o.Events.OnAuthorizationCodeReceived = async ctx =>
            {
                var db = ctx.HttpContext.RequestServices.GetService<DbContext>();
                await ...
            };
        });
    

    您可能需要添加services.AddSingleton&lt;IHttpContextAccessor, HttpContextAccessor&gt;();,因为这也是我所拥有的。但我怀疑如果没有它,上面的方法也可以工作。

    这里有一个 article 很好地涵盖了它。

    【讨论】:

    • 这似乎不起作用,因为 DI 在 ConfigureServices 中不起作用(已移动身份验证),并且我无法在 Startup() 构造函数中添加服务,因为它们尚不存在。例如。我在 OnTokenReceived() 中完成的第一次登录时发送电子邮件,但电子邮件服务尚不存在。
    • 这很有趣。 DI 应该在这些事件中工作,因为容器在调用这些事件之前已构建并可用。介意用过去在 1.1 中工作的代码 sn-p 更新您的问题吗? (你是对的 - Startup() 构造函数肯定不起作用)
    • 我使用的代码与 1.1 中几乎相同,但我不得不将它从 Configure() 移到没有 DI 的 ConfigureServices() 中。我能够让 DbContext 正常工作,但不能让我的其他服务(Graph SDK Helper、Email、History)......
    • 好的,我能够解决这个问题,请查看问题中的更新。谢谢您的帮助! :)
    【解决方案2】:

    我正在使用 .net core 3.1 并且遇到了类似的问题。 我认为可以通过将身份验证逻辑移至单独的处理程序类来使其更简洁,因为我们希望保持 Startup.cs 尽可能紧凑。

    public class AzureAdOpendIdHandler : IConfigureNamedOptions<OpenIdConnectOptions>
    {
        public void Configure(string name, OpenIdConnectOptions options)
        {
            options.ClientId = _azureOptions.ClientId;
            options.UseTokenLifetime = true;
    
            // The callback path located in AzureAd settings should match the callback path setup up in Azure portal
            options.CallbackPath = _azureOptions.CallbackPath;
            options.RequireHttpsMetadata = false;
            options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
    
            options.TokenValidationParameters = new TokenValidationParameters
            {
                // Ensure that User.Identity.Name is set correctly after login
                NameClaimType = JwtRegisteredClaimNames.Email,
                ValidateIssuer = false,
            };
    
            options.Events = new OpenIdConnectEvents
            {
    
                OnTokenValidated = async context =>
                {
    
                    var dbContext  = (HighEloDbContext)context.HttpContext.RequestServices.GetService(typeof(HighEloDbContext));
                    var acc = dbContext.Accounts.First(x => x.EmailAddress == userEmail);
                    ...
    
    
                },
                OnAuthenticationFailed = context =>
                {
                    context.Response.Redirect("/Error");
                    context.HandleResponse(); // Suppress the exception
                    return Task.CompletedTask;
                },
    
            };
        }
    
        public void Configure(OpenIdConnectOptions options)
        {
            Configure(Options.DefaultName, options);
        }
    }
    

    这是我的 Starup.cs 的样子:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages().AddMvcOptions(options =>
        {
            var policy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .Build();
            options.Filters.Add(new AuthorizeFilter(policy));
        });
        services.AddControllersWithViews().AddRazorRuntimeCompilation();
    
        services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
            .AddAzureAD(options => { Configuration.Bind(nameof(AzureAdConfig), options); });
    
        //here comes registration of services, DAL contexts etc.
    
        services.AddSingleton<IConfigureOptions<OpenIdConnectOptions>, AzureAdOpendIdHandler>();
    }
    

    请注意它适用于.AddAzureAD

    【讨论】:

      猜你喜欢
      • 2018-01-27
      • 2018-08-15
      • 2023-04-01
      • 2020-03-09
      • 1970-01-01
      • 2018-02-04
      • 2018-03-23
      • 2021-10-19
      • 2020-09-29
      相关资源
      最近更新 更多