长话短说,是否可以在我的 API 上放置基于环境的授权属性,以便在开发中关闭授权限制并在生产中重新打开?
我有一个单独的 Angular 2 项目,我希望用它调用 .NET Core API。我们创建了一个单独的项目,以便可以在 vscode 中打开 Angular 2 项目并调试打字稿。完成后,出于安全原因,我们将构建该项目并将其放置在 .NET Core 项目中。
我们的问题是,在调试阶段,我们无法连接到 API,因为它们是两个独立的项目,而且我们的 Angular 2 项目没有 Active Directory。 .NET Core 项目当前具有身份验证属性,并且不允许访问 (401) API。如果我们可以在开发期间关闭它并在生产期间重新打开它,那就太好了。
我也愿意接受有关如何最好地解决这个问题的任何其他建议。
[Authorize: (Only in Production)] <-- // something like this???
[Route("api/[controller]")]
public class TestController : Controller
{
...
ASP.NET Core 授权是基于策略的。正如您可能已经看到的,
AuthorizeAttribute
可以采用策略名称,以便它知道需要满足哪些条件才能授权请求。我建议您阅读有关该主题的优秀文档。
回到您的问题,看来您没有使用特定策略,因此它使用默认策略,默认情况下要求用户进行身份验证。
您可以在
Startup.cs
中更改该行为。如果您处于开发模式,您可以重新定义默认策略,使其没有任何要求:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthorization(x =>
{
// _env is of type IHostingEnvironment, which you can inject in
// the ctor of Startup
if (_env.IsDevelopment())
{
x.DefaultPolicy = new AuthorizationPolicyBuilder().Build();
}
});
}
im1dermike 在评论中提到,
AuthorizationPolicy
至少需要一个要求,正如我们在here 中看到的那样。该代码不是最近引入的,所以这意味着上面的解决方案一直被破坏。
为了解决这个问题,我们仍然可以利用 RequireAssertion
的
AuthorizationPolicyBuilder
方法并添加虚拟需求。这看起来像:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthorization(x =>
{
// _env is of type IHostingEnvironment, which you can inject in
// the ctor of Startup
if (_env.IsDevelopment())
{
x.DefaultPolicy = new AuthorizationPolicyBuilder()
.RequireAssertion(_ => true)
.Build();
}
});
}
这确保了我们在授权策略中至少有一项要求,并且我们知道它总是会通过。
我最终得到了这个,可能会有所帮助:
public class OnlyDebugModeAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext context)
{
base.OnActionExecuted(context);
}
public override void OnActionExecuting(ActionExecutingContext context)
{
#if DEBUG
//Ok
#else
context.Result = new ForbidResult();
return;
#endif
}
}
然后应用到控制器上
[OnlyDebugMode]
[Route("api/[controller]")]
[ApiController]
public class DebugController : ControllerBase
{
这是我的解决方案:
控制器的新属性:
[AzureADAuthorize]
AzureADAuthorize.cs:
public class AzureADAuthorize : AuthorizeAttribute
{
public AzureADAuthorize() : base(AzureADPolicies.Name)
{
}
}
AzureADPolicies.cs:
public static class AzureADPolicies
{
public static string Name => "AzureADAuthorizationRequired";
public static void Build(AuthorizationPolicyBuilder builder)
{
if (StaticRepo.Configuration.GetValue<bool>("EnableAuthorization") == true)
{
var section = StaticRepo.Configuration.GetSection($"AzureAd:AuthorizedAdGroups");
var groups = section.Get<string[]>();
builder.RequireClaim("groups", groups);
}
else if (StaticRepo.Configuration.GetValue<bool>("EnableAuthentication") == true)
{
builder.RequireAuthenticatedUser();
}else
{
builder
.RequireAssertion(_ => true)
.Build();
}
}
}
启动.cs:
//Authentication & Authorization
#region AUTHENTICATION / AUTHORICATION
StaticRepo.Configuration = Configuration;
services.AddAuthorization(options =>
{
options.AddPolicy(
AzureADPolicies.Name, AzureADPolicies.Build);
});
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
#endregion
应用程序设置.json:
"EnableAuditLogging": false,
"EnableAuthentication": true,
"EnableAuthorization": false,
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "https://MyDomain.onmicrosoft.com/",
"TenantId": "b6909603-e5a8-497d-8fdb-7f10240fdd10",
"ClientId": "6d09a1bf-4678-4aee-b67c-2d6df68d5324",
"CallbackPath": "/signin-oidc",
//Your Azure AD Security Group Object IDs that users needs to be member of to gain access
"AuthorizedAdGroups": [
"568bd325-283f-4909-9fcc-a493d19f98e8",
"eee6d366-0f4d-4fca-9965-b2bc0770506d"
]
}
(这些是随机指南)
现在如果您想要匿名访问、azure ad 身份验证、身份验证+群组授权,您可以进行条件控制。您仍然需要在 Azure 广告应用清单文件中设置一些内容才能使其正常工作,但我认为它超出了此处的范围。
如果您希望策略仅适用于特定的角色、特定的控制器,特别是环境。您可以添加新的授权策略(使用您喜欢的任何逻辑),然后在控制器的授权属性中使用它。
所以而不是以下内容在所有环境中运行:
[Authorize(Roles = "admin")]
public class AdminController : ControllerBase
将以下设置添加到您的
Program.cs
启动类中:
builder.Services.AddAuthorizationBuilder()
.AddPolicy("RequireAdminRoleInProd", policy =>
{
if (builder.Environment.IsProduction())
{
policy.RequireRole("admin");
}
else
{
policy.RequireAssertion(_ => true);
}
});
然后在您的控制器中添加授权策略:
[Authorize(Policy = "RequireAdminRoleInProd")]
public class AdminController : ControllerBase
这在 aspnet core 中运行良好,它消除了
AuthorizeAttribute
曾经工作的重载。