.net core 3.0 证书认证
.net core 3.0 Certificate authentication
最近我将 API 从 .net core 2.2 迁移到 .net core 3.0,以便使用证书实施身份验证。
我已按照此 Microsoft 文档:https://docs.microsoft.com/en-us/aspnet/core/security/authentication/certauth?view=aspnetcore-3.0 来完成我的工作。但我面临一个问题:
当我调用用 [Authorize] 属性修饰的控制器方法时,从不执行证书验证。如果请求的 header 中没有证书,我会得到一个 403,这是必需的行为,但是如果我放置证书,则假定的行为应该是通过指纹验证,但什么都没有...
这是我的证书验证服务:
public class CertificateValidationService
{
public bool ValidateCertificate(X509Certificate2 clientCertificate, string thumbprintToChek) =>
clientCertificate.Thumbprint.Equals(thumbprintToChek);
}
如文档中所述,在 StartUp.cs 中,我在 ConfigureServices 方法
中设置了以下代码行
services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options => // code from ASP.NET Core sample
{
options.AllowedCertificateTypes = CertificateTypes.All;
options.Events = new CertificateAuthenticationEvents
{
OnCertificateValidated = context =>
{
var validationService = context.HttpContext.RequestServices.GetService<CertificateValidationService>();
if (validationService.ValidateCertificate(context.ClientCertificate, Configuration.GetValue<string>("Apim:CertificateThumbprint")))
{
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, context.ClientCertificate.Subject, ClaimValueTypes.String, context.Options.ClaimsIssuer),
new Claim(ClaimTypes.Name, context.ClientCertificate.Subject, ClaimValueTypes.String, context.Options.ClaimsIssuer)
};
context.Principal = new ClaimsPrincipal(new ClaimsIdentity(claims, context.Scheme.Name));
context.Success();
}
else
{
context.Fail("Invalid certificate.");
}
return Task.CompletedTask;
}
};
options.Events = new CertificateAuthenticationEvents
{
OnAuthenticationFailed = context =>
{
context.Fail("Certificate not valid.");
return Task.CompletedTask;
}
};
});
services.AddCertificateForwarding(options =>
{
options.CertificateHeader = "X-ARR-ClientCert";
options.HeaderConverter = (headerValue) =>
{
X509Certificate2 clientCertificate = null;
if (!string.IsNullOrWhiteSpace(headerValue))
{
byte[] bytes = headerValue.ToByteArray();
clientCertificate = new X509Certificate2(bytes);
}
return clientCertificate;
};
});
我还使用以下代码填充了 Configure 方法:
app.UseCertificateForwarding();
app.UseAuthentication();
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
所以当我向 API 发出请求时,CertificateForwarding 委托被称为很好,但身份验证委托,从来没有。
但是,我已经尝试在一个全新的项目(仅用于测试)中实现此身份验证,它运行良好。
您对 options.Events
的分配已完成两次。这样 OnCertificateValidated
的默认实现会覆盖您的事件处理程序,并且您的 CertificateValidationService
将永远不会被调用。
组合这两个事件处理程序应该会得到预期的结果:
options.Events = new CertificateAuthenticationEvents
{
OnCertificateValidated = context =>
{
// Your implementation here.
},
OnAuthenticationFailed = context =>
{
// Your implementation here.
}
};
最近我将 API 从 .net core 2.2 迁移到 .net core 3.0,以便使用证书实施身份验证。
我已按照此 Microsoft 文档:https://docs.microsoft.com/en-us/aspnet/core/security/authentication/certauth?view=aspnetcore-3.0 来完成我的工作。但我面临一个问题: 当我调用用 [Authorize] 属性修饰的控制器方法时,从不执行证书验证。如果请求的 header 中没有证书,我会得到一个 403,这是必需的行为,但是如果我放置证书,则假定的行为应该是通过指纹验证,但什么都没有...
这是我的证书验证服务:
public class CertificateValidationService
{
public bool ValidateCertificate(X509Certificate2 clientCertificate, string thumbprintToChek) =>
clientCertificate.Thumbprint.Equals(thumbprintToChek);
}
如文档中所述,在 StartUp.cs 中,我在 ConfigureServices 方法
中设置了以下代码行services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options => // code from ASP.NET Core sample
{
options.AllowedCertificateTypes = CertificateTypes.All;
options.Events = new CertificateAuthenticationEvents
{
OnCertificateValidated = context =>
{
var validationService = context.HttpContext.RequestServices.GetService<CertificateValidationService>();
if (validationService.ValidateCertificate(context.ClientCertificate, Configuration.GetValue<string>("Apim:CertificateThumbprint")))
{
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, context.ClientCertificate.Subject, ClaimValueTypes.String, context.Options.ClaimsIssuer),
new Claim(ClaimTypes.Name, context.ClientCertificate.Subject, ClaimValueTypes.String, context.Options.ClaimsIssuer)
};
context.Principal = new ClaimsPrincipal(new ClaimsIdentity(claims, context.Scheme.Name));
context.Success();
}
else
{
context.Fail("Invalid certificate.");
}
return Task.CompletedTask;
}
};
options.Events = new CertificateAuthenticationEvents
{
OnAuthenticationFailed = context =>
{
context.Fail("Certificate not valid.");
return Task.CompletedTask;
}
};
});
services.AddCertificateForwarding(options =>
{
options.CertificateHeader = "X-ARR-ClientCert";
options.HeaderConverter = (headerValue) =>
{
X509Certificate2 clientCertificate = null;
if (!string.IsNullOrWhiteSpace(headerValue))
{
byte[] bytes = headerValue.ToByteArray();
clientCertificate = new X509Certificate2(bytes);
}
return clientCertificate;
};
});
我还使用以下代码填充了 Configure 方法:
app.UseCertificateForwarding();
app.UseAuthentication();
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
所以当我向 API 发出请求时,CertificateForwarding 委托被称为很好,但身份验证委托,从来没有。
但是,我已经尝试在一个全新的项目(仅用于测试)中实现此身份验证,它运行良好。
您对 options.Events
的分配已完成两次。这样 OnCertificateValidated
的默认实现会覆盖您的事件处理程序,并且您的 CertificateValidationService
将永远不会被调用。
组合这两个事件处理程序应该会得到预期的结果:
options.Events = new CertificateAuthenticationEvents
{
OnCertificateValidated = context =>
{
// Your implementation here.
},
OnAuthenticationFailed = context =>
{
// Your implementation here.
}
};