Authentication 对一个特定端点使用不同的授权.net core

Authentication 对一个特定端点使用不同的授权.net core,authentication,authorization,asp.net-core-webapi,Authentication,Authorization,Asp.net Core Webapi,我已使用Identity Server 4的承载方案为我的Web API启用了Authentication 在ConfigureServices中,我有: services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => {

我已使用Identity Server 4的承载方案为我的Web API启用了Authentication

在ConfigureServices中,我有:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
            {
                options.Authority = identitySetttings.Authority;
                options.Audience = identitySetttings.ApiScope;
                options.RequireHttpsMetadata = false;
在配置中,我有:

app.UseAuthentication();
app.UseAuthorization();

现在我想排除一个特定的端点是而不是通过这种方式进行身份验证的,但我不希望它是[AllowAnonymous]。我想限制对此端点的特定IP地址的请求,并为经过身份验证的请求添加自定义声明。如何实现它?

首先,您需要删除
app.UseAuthentication()原因在您的情况下,这将始终调用默认的身份验证方案
JwtBearerDefaults.AuthenticationScheme
。然后,您可以使特定的授权策略依赖于特定的身份验证方案。它可能是这样的:

services
    .AddAuthentication()
    .AddScheme<AuthenticationSchemeOptions, Auth1>("Auth1", _ => { })
    .AddScheme<AuthenticationSchemeOptions, Auth2>("Auth2", _ => { });

services.AddAuthorization(c =>
{
    c.AddPolicy("Auth1Policy", policy =>
    {
        policy.AuthenticationSchemes.Add("Auth1");
        policy.RequireAuthenticatedUser();
    });

    c.AddPolicy("Auth2Policy", policy =>
    {
        policy.AuthenticationSchemes.Add("Auth2");
        policy.RequireAuthenticatedUser();
    });
});
服务
.AddAuthentication()
.AddScheme(“Auth1”,{})
.AddScheme(“Auth2”,_=>{});
services.AddAuthorization(c=>
{
c、 AddPolicy(“Auth1Policy”,策略=>
{
policy.AuthenticationSchemes.Add(“Auth1”);
policy.RequireAuthenticatedUser();
});
c、 AddPolicy(“Auth2Policy”,策略=>
{
policy.AuthenticationSchemes.Add(“Auth2”);
policy.RequireAuthenticatedUser();
});
});
现在,使用策略名称注释控制器将仅调用该策略的身份验证方案。以下是您在控制器上选择授权策略的方式:

[HttpGet]
[Authorize(Policy = "Auth1Policy")]
public IEnumerable<WeatherForecast> Get()
    [HttpPost]
    [Authorize(AuthenticationSchemes = "IPOnly")]
    [Route("type/sms/changeStatus")]
    public async Task<IActionResult> Foo(Bar model)
[HttpGet]
[授权(Policy=“Auth1Policy”)]
公共IEnumerable Get()

但是,如果您将该端点从此服务中移除,并将其放置在更安全的网络环境中的其他API中,则限制特定IP地址将更容易实现,因为公众不应访问它。

谢谢您的建议,但我不想添加[授权]属性,该属性用于每个已存在的控制器。 我只是添加了IPAuthentication的新方案:

.AddScheme<IPOnlyAuthenticationOptions, IPOnlyAuthenticationHandler>("IPOnly", op => { });
.AddScheme(“IPOnly”,op=>{});
然后在AuthenticationHandler中:

public class IPOnlyAuthenticationOptions : AuthenticationSchemeOptions { }

public class IPOnlyAuthenticationHandler : AuthenticationHandler<IPOnlyAuthenticationOptions>
{
    private readonly IEnumerable<IPAddress> validIPs= new[]
    {
       "xxx"
    }.Select(o => IPAddress.Parse(o));

    public IPOnlyAuthenticationHandler(IOptionsMonitor<IPOnlyAuthenticationOptions> options,
        ILoggerFactory logger,
        UrlEncoder encoder,
        ISystemClock clock)
        : base(options, logger, encoder, clock) { }

    protected override Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        var ipAddress = Request.HttpContext.Connection.RemoteIpAddress;
        var identity = GetIdentityFromIPAddress(ipAddress);
        if (identity != null)
        {
            var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), this.Scheme.Name);
            return Task.FromResult(AuthenticateResult.Success(ticket));
        }
        return Task.FromResult(AuthenticateResult.Fail($"Request not authenticated for ip address: {ipAddress}"));
    }


    private ClaimsIdentity GetIdentityFromIPAddress(IPAddress ipAddress)
    {
        if (smsApiIPs.Contains(ipAddress))
        {
            var claims = new[] { new Claim(ClaimTypes.NameIdentifier, "id of my integration user") };
            return new ClaimsIdentity(claims, nameof(IPOnlyAuthenticationHandler));
        }
        return null;
    }
公共类IPOnlyAuthenticationOptions:AuthenticationSchemeOptions{}
公共类IPOnlyAuthenticationHandler:AuthenticationHandler
{
私有只读IEnumerable validIPs=new[]
{
“xxx”
}.Select(o=>IPAddress.Parse(o));
公共IPOnlyAuthenticationHandler(IOptionsMonitor选项,
iLogger工厂记录器,
URL编码器,
ISystemClock(系统时钟)
:base(选项、记录器、编码器、时钟){}
受保护的覆盖任务handleAuthenticateAync()
{
var ipAddress=Request.HttpContext.Connection.RemoteIpAddress;
var identity=GetIdentityFromIPAddress(ipAddress);
如果(标识!=null)
{
var ticket=新的身份验证ticket(新的ClaimsPrincipal(identity),this.Scheme.Name);
返回Task.FromResult(AuthenticateResult.Success(票证));
}
返回Task.FromResult(AuthenticateResult.Fail($“请求未对ip地址进行身份验证:{ipAddress}”);
}
private ClaimSideEntity GetIdentityFromIPAddress(IPAddress IPAddress)
{
if(smsApiIPs.Contains(ipAddress))
{
var claims=new[]{new claims(ClaimTypes.NameIdentifier,“我的集成用户的id”)};
返回新的索赔实体(索赔,名称(IPOnlyAuthenticationHandler));
}
返回null;
}
最后,我可以在控制器中使用它:

[HttpGet]
[Authorize(Policy = "Auth1Policy")]
public IEnumerable<WeatherForecast> Get()
    [HttpPost]
    [Authorize(AuthenticationSchemes = "IPOnly")]
    [Route("type/sms/changeStatus")]
    public async Task<IActionResult> Foo(Bar model)
[HttpPost]
[授权(AuthenticationSchemes=“IPOnly”)]
[路线(“类型/短信/变更状态”)]
公共异步任务Foo(条形模型)