C# ASP.NET核心Web API,如何在启动类中访问HttpContext

C# ASP.NET核心Web API,如何在启动类中访问HttpContext,c#,api,asp.net-core,.net-core,C#,Api,Asp.net Core,.net Core,我正在尝试访问HttpContext以获取RemoteIpAddress和用户代理,但在Startup.cs内 public class Startup { public Startup(IConfiguration configuration, IHttpContextAccessor httpContextAccessor) { Configuration = configuration;

我正在尝试访问
HttpContext
以获取
RemoteIpAddress
用户代理
,但在Startup.cs内

 public class Startup
        {
            public Startup(IConfiguration configuration, IHttpContextAccessor httpContextAccessor)
            {
                Configuration = configuration;
                _httpContextAccessor = httpContextAccessor;
            }

            public IConfiguration Configuration { get; }
            public IHttpContextAccessor _httpContextAccessor { get; }

            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                IdentityModelEventSource.ShowPII = true;

                var key = Encoding.ASCII.GetBytes(Configuration.GetValue<string>("claveEncriptacion"));
                var ip = _httpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString();
                var userAgent = _httpContextAccessor.HttpContext.Request.Headers["User-Agent"].ToString();

services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(x =>
            {
                //x.Audience = ip + "-" + userAgent;
                x.RequireHttpsMetadata = false;
                x.SaveToken = true;
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = false,
                    ValidateAudience = true
                };
            });
根据,在使用通用主机(IHostBuilder)时,只能将以下服务类型注入到
启动
构造函数中:

因此,无法将
IHttpContextAccessor
注入
启动
构造函数

但是,您可以在
Startup
类的
ConfigureServices
方法中获得DI解析服务,如下所示:

public void ConfigureServices(IServiceCollection services)
{

    services.AddScoped<IYourService, YourService>();

    // Build an intermediate service provider
    var serviceProvider = services.BuildServiceProvider();

    // Resolve the services from the service provider
    var yourService = serviceProvider.GetService<IYourService>();

}
public class YourCustomMiddleMiddleware
{
    private readonly RequestDelegate _requestDelegate;

    public YourCustomMiddleMiddleware(RequestDelegate requestDelegate)
    {
        _requestDelegate = requestDelegate;
    }

    public async Task Invoke(HttpContext context)
    {

      // Your HttpContext related task is in here.

      await _requestDelegate(context);
    }
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
   app.UseMiddleware(typeof(YourCustomMiddleMiddleware));
}
然后在
启动
类的
配置
方法中,如下所示:

public void ConfigureServices(IServiceCollection services)
{

    services.AddScoped<IYourService, YourService>();

    // Build an intermediate service provider
    var serviceProvider = services.BuildServiceProvider();

    // Resolve the services from the service provider
    var yourService = serviceProvider.GetService<IYourService>();

}
public class YourCustomMiddleMiddleware
{
    private readonly RequestDelegate _requestDelegate;

    public YourCustomMiddleMiddleware(RequestDelegate requestDelegate)
    {
        _requestDelegate = requestDelegate;
    }

    public async Task Invoke(HttpContext context)
    {

      // Your HttpContext related task is in here.

      await _requestDelegate(context);
    }
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
   app.UseMiddleware(typeof(YourCustomMiddleMiddleware));
}

我终于找到了一个可能的解决方案,使用
中间件
验证令牌。 我创建了一个类
ValidationHandler
,这个类可以使用
HttpContext

public class ValidationRequirement : IAuthorizationRequirement
    {
        public string Issuer { get; }
        public string Scope { get; }

        public HasScopeRequirement(string scope, string issuer)
        {
            Scope = scope ?? throw new ArgumentNullException(nameof(scope));
            Issuer = issuer ?? throw new ArgumentNullException(nameof(issuer));
        }
    }


    public class ValidationHandler : AuthorizationHandler<ValidationRequirement>
    {
        IHttpContextAccessor _httpContextAccessor;

        public HasScopeHandler(IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
        }

        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, HasScopeRequirement requirement)
        {

            var ip = _httpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString();
            var userAgent = _httpContextAccessor.HttpContext.Request.Headers["User-Agent"].ToString();

            //context.Succeed(requirement);

            return Task.CompletedTask;
        }
    }

谢谢你,维德加加。我想投票,但我有一个新帐户。你的回答对我的项目有帮助。我来自f#land,因此我将为任何需要此解决方案的FSharper提供我的实现

type HasScopeHandler() =
    inherit AuthorizationHandler<HasScopeRequirement>()
        override __.HandleRequirementAsync(context, requirement) =
            let scopeClaimFromIssuer = Predicate<Claim>(fun (c: Claim) -> c.Type = "scope" && c.Issuer = requirement.Issuer)
            let userDoesNotHaveScopeClaim = not (context.User.HasClaim(scopeClaimFromIssuer))
            let isRequiredScope s = (s = requirement.Scope)
            let claimOrNull = context.User.FindFirst(scopeClaimFromIssuer)

            if (userDoesNotHaveScopeClaim) then
                Task.CompletedTask
            else
                match claimOrNull with
                | null -> Task.CompletedTask
                | claim ->
                    let scopes = claim.Value.Split(' ')
                    let hasRequiredScope = scopes.Any(fun s -> isRequiredScope s)
                    if (hasRequiredScope) then
                      context.Succeed(requirement)
                      Task.CompletedTask
                    else
                     Task.CompletedTask
type HasScopeHandler()=
继承AuthorizationHandler()
重写_uu.HandleRequirementAsync(上下文、需求)=
让scopeClaimFromIssuer=谓词(fun(c:Claim)->c.Type=“scope”&&c.Issuer=requirement.Issuer)
让userDoesNotHaveScopeClaim=not(context.User.HasClaim(scopeClaimFromIssuer))
让isRequiredScope s=(s=requirement.Scope)
让claimOrNull=context.User.FindFirst(scopeClaimFromIssuer)
如果(用户未声明)则
Task.CompletedTask
其他的
将claimOrNull与
|null->Task.CompletedTask
|索赔->
让scopes=claim.Value.Split(“”)
让hasRequiredScope=scopes.Any(乐趣s->isRequiredScope s)
如果(需要示波器),则
成功(要求)
Task.CompletedTask
其他的
Task.CompletedTask

您想要实现什么目标?您无法在启动时访问
HttpContext
,因为startup.cs中没有发出任何请求。我需要获取RemoteIpAddress和User agent启动时您试图获取的IP和User agent是什么?它们仅在请求IP和用户代理添加x时可用。访问群体,因为令牌的访问群体是dinamicI。我已经测试了您的代码,并且我有空引用的_httpContextAccessorOkay!明白原因了!我将很快更新答案,解释解决问题的原因和方法!请告诉我您想从HttpContext获得什么。我需要创建一个令牌,然后仅从创建该令牌的同一浏览器和pc调用该令牌。为了实现这一区别,我使用了IP和用户代理。但是我需要在ConfigureServices中使用它,因为令牌是经过验证的inside@vidgarga您应该能够从自定义中间件执行完全相同的操作。在
Startup
类的
Configure
方法中注册中间件。