在 ASP.Net Core 中间件中调用服务/存储库方法

问题描述 投票:0回答:1

ASP.Net Core 新手...我正在使用 ASP.Net Core WebAPI 核心项目,该项目使用 DNX451 和 EF 6。

我需要在我们的服务中实现 API 密钥身份验证。为此,我创建了中间件,该中间件从请求中获取信息并继续进行身份验证。应该去数据库,获取匹配的密钥,然后返回并进行验证。

这是实现查看上下文并获取 APIKey 的中间件

身份验证处理程序

public class AuthorizationHandler
{
    private readonly RequestDelegate _next;
    private IAuthenticationService _authenticationService;

    public AuthorizationHandler(RequestDelegate next, IAuthenticationService authService)
    {
        _authenticationService = authService;
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        try
        {
            var apiKey = context.Request.Headers["Key"];
            var location = context.Request.Headers["Host"];
            var locationKey = _authenticationService.GetApiKey(location);

            if (apiKey == locationKey)
                await _next(context);


            context.Response.StatusCode = 403;
            context.Response.Headers.Add("WWW-Authenticate",
                new[] { "Basic" });

        }
        catch (Exception ex)
        {
            context.Response.StatusCode = 500;
            context.Response.Headers.Add("WWW-Authenticate",
                new[] { "Basic" });
        }
    }
}

这里是带有上下文和中间件注册的启动类

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json")
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);


        builder.AddEnvironmentVariables();
        Configuration = builder.Build();
    }

    public IConfiguration Configuration { get; set; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddScoped(k => new DbContext(Configuration["Data:Context:ConnectionString"]));


        // Add framework services.
        services.AddMvc();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        app.UseIISPlatformHandler();

        app.UseStaticFiles();

        app.RegisterAuthorizationHeader();
        app.RegisterAuthorization();

        app.UseMvc();
    }

    // Entry point for the application.
    public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}

这里是Auth服务

public interface IAuthenticationService
{
    string GetApiKey(string location);
}

public class AuthenticationService: IAuthenticationService
{
    private IApiKeyRepository _apiKeyRepository;
    public AuthenticationService(IApiKeyRepository repo)
    {
        _apiKeyRepository= repo;
    }

    public string GetApiKey(string location)
    {
        return _apiKeyRepository.GetApiKeyByLocation(location);
    }
}

回购协议

public interface IApiRepository
{
    string GetApiKeyByLocation(string location);
}

public class ApiRepository: IApiRepository
{
    private DbContext _context;

    public ApiRepository(DbContext context)
    {
        _context = context;
    }

    public string GetApiKeyByLocation(string location)
    {
        var apiRow = _context.ApiKeyStore.FirstOrDefault(a => a.Location == location);

        return apiRow == null ? string.Empty : apiRow.APIKey;
    }
}

尝试此操作时,我收到以下错误:

创建模型时无法使用上下文。这 如果在内部使用上下文,则可能会抛出异常 OnModelCreating 方法或如果访问相同的上下文实例 多个线程并发。请注意,DbContext 的实例成员 以及相关类不保证线程安全。

现在,当我调试这个时,每个断点都会被击中两次。我相信我理解为什么这个问题发生,但不知道如何解决它。

有人可以给我一个主意吗?有更好的解决思路吗?

entity-framework-6 asp.net-web-api2 asp.net-core
1个回答
9
投票

要在中间件中使用作用域依赖项(根据定义,这必然是单例),最好的方法是将其作为

InvokeAsync
的参数进行流动,而不是通过构造函数进行流动:

public async Task Invoke(HttpContext context, IAuthenticationService authenticationService)
{
    try
    {
        var apiKey = context.Request.Headers["Key"];
        var location = context.Request.Headers["Host"];
        var locationKey = authenticationService.GetApiKey(location);

        if (apiKey == locationKey)
            await _next(context);


        context.Response.StatusCode = 403;
        context.Response.Headers.Add("WWW-Authenticate",
            new[] { "Basic" });

    }
    catch (Exception ex)
    {
        context.Response.StatusCode = 500;
        context.Response.Headers.Add("WWW-Authenticate",
            new[] { "Basic" });
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.