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

时间:2016-05-10 14:59:14

标签: entity-framework-6 asp.net-web-api2 asp.net-core

ASP.Net Core noob here ...我正在使用ASP.Net Core WebAPI核心项目,使用DNX451和EF 6.

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

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

的AuthenticationHandler

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);
}

以下是验证服务

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的实例成员   和相关的类不保证是线程安全的。

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

有人可以给我一个想法吗?有更好的解决方案吗?

1 个答案:

答案 0 :(得分:6)

要在中间件(根据定义必须是单例)中使用作用域依赖项,最好的方法是将其作为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" });
    }
}