Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# aspnetcore2.0使用带有AzureAd身份验证的服务_C#_Asp.net Core_Entity Framework Core_Asp.net Core 2.0 - Fatal编程技术网

C# aspnetcore2.0使用带有AzureAd身份验证的服务

C# aspnetcore2.0使用带有AzureAd身份验证的服务,c#,asp.net-core,entity-framework-core,asp.net-core-2.0,C#,Asp.net Core,Entity Framework Core,Asp.net Core 2.0,我将要将ASP.NET核心MVC web应用程序从1.1迁移到2.0。该应用程序使用AzureAd进行身份管理 在1.1中,我在Startup.cs(在Configure()中)处理了openidconnect事件(如OnTokenReceiver,OnAuthorizationCodeReceived,OnRemoteFailure等),在这里我可以使用依赖注入。我已经注入了很多服务,比如efdb context,并在事件处理程序中使用它们。 升级到2.0后,我必须将整个身份验证迁移到Azur

我将要将ASP.NET核心MVC web应用程序从1.1迁移到2.0。该应用程序使用AzureAd进行身份管理

在1.1中,我在Startup.cs(在
Configure()
中)处理了openidconnect事件(如
OnTokenReceiver
OnAuthorizationCodeReceived
OnRemoteFailure
等),在这里我可以使用依赖注入。我已经注入了很多服务,比如efdb context,并在事件处理程序中使用它们。 升级到2.0后,我必须将整个身份验证迁移到
AzureAuthenticationBuilderExtensions
ConfigureAzureOptions
类(实现
IConfigureNameOptions
接口),其中(如我所见)无法使用DI

因此,现在只有这一项在Startup的ConfigureServices中:

services.AddAuthentication(sharedOptions =>
{
    sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddAzureAd(options => Configuration.Bind("AzureAd", options))
.AddCookie();
我在迁移过程中使用了以下指南:

有人知道如何在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>();
...
var scopeFactory=服务
.BuildServiceProvider()
.GetRequiredService();
var scope=scopeFactory.CreateScope();
var provider=scope.ServiceProvider;
var dbContext=provider.GetRequiredService();
var graphsdkheloper=provider.GetRequiredService();
var memoryCache=provider.GetRequiredService();
...

请记住,您必须将这些服务添加到此代码之上

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

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

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddOpenIdConnect(o =>
    {
        o.Events.OnAuthorizationCodeReceived = async ctx =>
        {
            var db = ctx.HttpContext.RequestServices.GetService<DbContext>();
            await ...
        };
    });
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddOpenIdConnect(o=>
{
o、 Events.OnAuthorizationCodeReceived=异步ctx=>
{
var db=ctx.HttpContext.RequestServices.GetService();
等待。。。
};
});
您可能需要添加
services.AddSingleton()

这里有一个很好的例子。我正在使用.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);
    }
}
公共类AzureAdOpendIdHandler:IConfigureNamedOptions
{
public void配置(字符串名称、OpenIdConnectOptions选项)
{
options.ClientId=\u azureOptions.ClientId;
options.UseTokenLifetime=true;
//AzureAd设置中的回调路径应与Azure portal中设置的回调路径匹配
options.CallbackPath=\u azureOptions.CallbackPath;
options.RequireHttpsMetadata=false;
options.ResponseType=OpenIdConnectResponseType.CodeIdToken;
options.TokenValidationParameters=新的TokenValidationParameters
{
//确保在登录后正确设置User.Identity.Name
NameClaimType=JwtRegisteredClaimNames.Email,
validateisuer=false,
};
options.Events=新的OpenIdConnectEvents
{
OnTokenValidated=异步上下文=>
{
var dbContext=(highelodcontext)context.HttpContext.RequestServices.GetService(typeof(highelodcontext));
var acc=dbContext.Accounts.First(x=>x.EmailAddress==userEmail);
...
},
OnAuthenticationFailed=上下文=>
{
context.Response.Redirect(“/Error”);
context.HandleResponse();//抑制异常
返回Task.CompletedTask;
},
};
}
public void配置(OpenIdConnectOptions选项)
{
配置(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>();
}
public void配置服务(IServiceCollection服务)
{
services.AddRazorPages().addmvcopions(选项=>
{
var policy=new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()文件
.Build();
options.Filters.Add(新的授权过滤器(策略));
});
services.AddControllersWithViews().AddRazorRuntimeCompilation();
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options=>{Configuration.Bind(nameof(AzureAdConfig),options);});
//这里是服务注册,等等。
services.AddSingleton();
}

请注意,它可以与
.AddAzureAD

一起使用,这似乎不起作用,因为DI在ConfigureServices中不起作用(身份验证已移动),并且我无法在Startup()构造函数中添加服务,因为它们还不存在。我在第一次登录时发送电子邮件,这是在OnTokenReceived()中完成的,但是电子邮件服务还不存在。这很有趣。DI应该在这些事件中工作,因为容器是在调用这些事件之前构建并可用的。介意用一段在1.1中使用的代码更新你的问题吗?(您是对的-Startup()构造函数肯定不起作用)我使用的代码与1.1中的代码几乎相同,但我不得不将它从Configure()移动到ConfigureServices(),在那里没有DI。我能够让DbContext工作,但我的其他服务(Graph SDK助手、电子邮件、历史记录)无法工作…好的,我能够解决这个问题,请参阅t