OpenIdDict 3.0 跳过了 AllowAnonymous

AllowAnonymous skipped over with OpenIdDict 3.0

我正在使用 OpenIdDict 3.0,它运行良好,但是我有一个使用 AllowAnonymous 属性的控制器,但我仍然收到 "The request was rejected because the access token was missing"。我假设它可能与我的 Startup 中的顺序有关,这使得它不会在管道中受到影响,但我不确定。这是我的创业公司 class:

 public async void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
        {
            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();


            app.UseMvcWithDefaultRoute();
        }


 public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc(options =>
            {
                options.EnableEndpointRouting = false;
            }).AddNewtonsoftJson();

            services.AddAutoMapper(typeof(Startup));

            services.AddDbContext<MyDbContext>(options =>
            {
                options.UseSqlServer(WebConfig.ConnectionString, x => x.MigrationsAssembly("X.Api.DataAccess"));
                options.UseLazyLoadingProxies();
                options.UseOpenIddict();
            });

            services.AddIdentity<ApplicationUser, IdentityRole>(options =>
            {
                options.Password.RequireLowercase = true;
            })
            .AddEntityFrameworkStores<MyDbContext>()
            .AddUserStore<ApplicationUserStore>()
            .AddDefaultTokenProviders();

            services.Configure<IdentityOptions>(options =>
            {
                options.ClaimsIdentity.UserNameClaimType = Claims.Name;
                options.ClaimsIdentity.UserIdClaimType = Claims.Subject;
                options.ClaimsIdentity.RoleClaimType = Claims.Role;
            });

            services.AddOpenIddict()
                .AddCore(options =>
                {
                    options.UseEntityFrameworkCore()
                    .UseDbContext<MyDbContext>();
                })
                .AddServer(options =>
                {
                    options.SetAuthorizationEndpointUris("/connect/authorize")
                     .SetLogoutEndpointUris("/connect/logout")
                     .SetTokenEndpointUris("/connect/token");

                    options.AllowAuthorizationCodeFlow()
                    .AllowRefreshTokenFlow();

                   scopes.
                    options.RegisterScopes(Scopes.Email, Scopes.OpenId, Scopes.OfflineAccess);

                    // Register the signing and encryption credentials.
                    options.AddDevelopmentEncryptionCertificate()
                           .AddDevelopmentSigningCertificate();

                    options.UseAspNetCore()
                    .EnableTokenEndpointPassthrough();
                })
            .AddValidation(options =>
            {
                // Import the configuration from the local OpenIddict server instance.
                options.UseLocalServer();

                // Register the ASP.NET Core host.
                options.UseAspNetCore();
            });

            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme;
            });




        }

如有任何帮助,我们将不胜感激!

您看到的行为实际上是 "normal":当您设置 DefaultAuthenticateScheme 时,身份验证中间件(又名 app.UseAuthentication())- 通常在 ASP.NET 核心管道 - 自动调用相应的身份验证处理程序来填充 HttpContext.User.

无论您的 MVC 操作是用 [Authorize] 还是 [AllowAnonymous] 修饰,这种机制总是独立发生。如果 OpenIddict 在 Authorization header 中找不到访问令牌,它会记录一个错误并告诉身份验证堆栈它无法提供它请求的 AuthenticateResult

如果您的 MVC 操作用 [Authorize] 装饰,身份验证堆栈将要求 OpenIddict return 401 挑战(除非使用 [AllowAnonymous])。

也就是说,虽然它不会阻止一切正常工作,但我同意它可能是一个重要的干扰源,因此我会考虑删除此日志消息。我打开 https://github.com/openiddict/openiddict-core/issues/941 进行跟踪。

干杯。

就我而言,我想摆脱使用 [AllowAnonymous] 属性创建的数据库上下文。但它不是那样工作的。因此,我必须创建自己的 AuthenticationMiddleware 替代品,并为异常添加必要的路径。

现在一步一步来。

第一。创建中间件:

public class CustomAuthenticationMiddleware
{
    private readonly RequestDelegate _nextWithoutAuth;
    private readonly AuthenticationMiddleware _nextWithAuth;

    private List<PathString> _withoutAuth = new List<PathString>
    {
        "/url/1", "/url/2"
    };

    public CustomAuthenticationMiddleware(RequestDelegate next, 
        IServiceProvider sp)
    {
        _nextWithoutAuth = next;
        _nextWithAuth = ActivatorUtilities
            .CreateInstance<AuthenticationMiddleware>(sp, next);
    }

    public async Task Invoke(HttpContext context)
    {
        var path = context.Request.Path.HasValue ? 
            context.Request.Path.Value : null;

        var withoutAuth = context.Request.Path.HasValue
            && _withoutAuth.Any(it => path.StartsWith(it, StringComparison.OrdinalIgnoreCase));

        if (withoutAuth)
        {
            await _nextWithoutAuth.Invoke(context);
        }
        else
        {
            await _nextWithAuth.Invoke(context);
        }
    }
}

第二。用所需的值填充数组 _withoutAuth

第三。在 Startup.cs 中将 app.UseAuthentication(); 替换为 app.UseMiddleware<CustomAuthenticationMiddleware>();

p.s。我使用.net core 2.1

p.s.s.我假设如果使用 [AllowAnonymous] 属性获取所有控制器及其方法并将它们添加到 _withoutAuth 数组中,您可以改进我的解决方案。