如何在 ASP Net Core 中授权 Web API 控制器
How do you Authorize a Web API Controller in ASP Net Core
我在 C# ASP Net Core 中为后端创建了一个 API。我试图想出一种方法来授权路由,以便它将在 url 中输入一个 API 键,例如“https://mywebsite.com/api/data/first?key=VX4HCOjtMQ6ZF978a245oLw00SfK0ahm”来验证路由并在中显示数据JSON.
我知道在 ASP NET Core 身份中有一种方法可以对路由进行身份验证,但这需要用户先登录。如何使用 API 密钥保护我的 API 路由?
您尝试执行的操作不会保护网络 api。我建议您查看 OAuth/OpenID。有一个名为 Identity Server 4 的开源 .net 核心实现。
但是,为了回答您的问题,您可以创建一个自定义属性来验证传递给您的操作的密钥,或者您可以简单地处理每个操作中的验证。在 .net core 中没有内置的方法来执行此操作,您将必须手动处理 api 键,就像传递到您的网络 api 的任何其他值一样。
从它的声音来看,您想要实现的是一个替代身份验证系统和一个使用此 key
查询字符串参数(这可能不是最佳设计)的自定义授权系统。
第一步是根据此 QueryString
参数对用户进行身份验证。现在最好的方法(IMO)是推出你自己的身份验证处理程序。查看 Aspnet Security 的代码揭示了他们现有的一些身份验证系统的内部工作原理。
实际上,我们要做的是尽早拦截请求,验证此 key
的存在,然后对请求进行身份验证。
下面显示了这个基本系统。
public class QueryStringAuthOptions : AuthenticationOptions
{
public const string QueryStringAuthSchema = "QueryStringAuth";
public const string QueryStringAuthClaim = "QueryStringKey";
public QueryStringAuthOptions()
{
AuthenticationScheme = QueryStringAuthSchema;
}
public string QueryStringKeyParam { get; set; } = "key";
public string ClaimsTypeName { get; set; } = "QueryStringKey";
public AuthenticationProperties AuthenticationProperties { get; set; } = new AuthenticationProperties();
}
public class QueryStringAuthHandler : AuthenticationHandler<QueryStringAuthOptions>
{
/// <summary>
/// Handle authenticate async
/// </summary>
/// <returns></returns>
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (Request.Query.TryGetValue(Options.QueryStringKeyParam, out StringValues value) && value.Count > 0)
{
var key = value[0];
//..do your authentication...
if (!string.IsNullOrWhiteSpace(key))
{
//setup you claim
var claimsPrinciple = new ClaimsPrincipal();
claimsPrinciple.AddIdentity(new ClaimsIdentity(new[] { new Claim(Options.ClaimsTypeName, key) }, Options.AuthenticationScheme));
//create the result ticket
var ticket = new AuthenticationTicket(claimsPrinciple, Options.AuthenticationProperties, Options.AuthenticationScheme);
var result = AuthenticateResult.Success(ticket);
return Task.FromResult(result);
}
}
return Task.FromResult(AuthenticateResult.Fail("Key not found or not valid"));
}
}
现在上面的内容非常简单,我们已经创建了一个自定义 AuthenticationOptions
class,我们将在自定义 AuthenticationHandler
中使用它。如您所见,这非常简单,但最终我们创建了一个有效的身份验证票证 (ClaimsPrinciple
) 并以 Success
结果或 Fail()
.
进行响应
接下来我们需要让身份验证系统在 .Net 管道中工作(请注意,这是 1.2,因为 2.0 已更改,请参见 Auth 2.0 Migration)。这是通过 AuthenticationMiddleware
完成的,因此在我们创建中间件的简单实现之前。
public class QueryStringAuthMiddleware : AuthenticationMiddleware<QueryStringAuthOptions>
{
public QueryStringAuthMiddleware(RequestDelegate next, IOptions<QueryStringAuthOptions> options, ILoggerFactory loggerFactory, UrlEncoder encoder)
: base(next, options, loggerFactory, encoder)
{
}
protected override AuthenticationHandler<QueryStringAuthOptions> CreateHandler()
{
return new QueryStringAuthHandler();
}
}
这非常基本,但只是创建了一个新的 QueryStringAuthHandler()
来处理身份验证请求。 (我们之前创建的那个)。现在我们需要将这个中间件放入管道中。因此,遵循 .Net 约定,静态扩展 class 可以通过管理选项的能力来做到这一点。
public static class QueryStringAuthMiddlewareExtensions
{
public static IApplicationBuilder UseQueryStringAuthentication(this IApplicationBuilder appBuilder)
{
if (appBuilder == null)
throw new ArgumentNullException(nameof(appBuilder));
var options = new QueryStringAuthOptions();
return appBuilder.UseQueryStringAuthentication(options);
}
public static IApplicationBuilder UseQueryStringAuthentication(this IApplicationBuilder appBuilder, Action<QueryStringAuthOptions> optionsAction)
{
if (appBuilder == null)
throw new ArgumentNullException(nameof(appBuilder));
var options = new QueryStringAuthOptions();
optionsAction?.Invoke(options);
return appBuilder.UseQueryStringAuthentication(options);
}
public static IApplicationBuilder UseQueryStringAuthentication(this IApplicationBuilder appBuilder, QueryStringAuthOptions options)
{
if (appBuilder == null)
throw new ArgumentNullException(nameof(appBuilder));
if (options == null)
throw new ArgumentNullException(nameof(options));
return appBuilder.UseMiddleware<QueryStringAuthMiddleware>(Options.Create(options));
}
}
到目前为止,已经有很多代码可以让身份验证系统就位,但是这是遵循 .net 核心团队提供的许多示例。
身份验证中间件工作的最后一步是修改 startup.cs
文件并添加身份验证系统。
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(); //adds the auth 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.UseQueryStringAuthentication(); //add our query string auth
//add mvc last
app.UseMvc();
}
我们就快完成了,到目前为止,我们已经有了对请求进行身份验证的机制,而且我们最好创建声明(可以扩展)以在需要时保存更多信息。最后一步是 Authorize
请求。这很简单,我们需要做的就是告诉默认授权处理程序您正在使用哪个登录模式,此外我们还需要我们之前应用的声明。回到 startup.cs
中的 ConfigureServices
方法,我们只需 AddAuthorization
进行一些设置。
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthorization(o =>
{
//override the default policy
o.DefaultPolicy = new AuthorizationPolicy(new[] { new ClaimsAuthorizationRequirement(QueryStringAuthOptions.QueryStringAuthClaim, new string[0]) }, new[] { QueryStringAuthOptions.QueryStringAuthSchema });
//or add a policy
//o.AddPolicy("QueryKeyPolicy", options =>
//{
// options.RequireClaim(QueryStringAuthOptions.QueryStringAuthClaim);
// options.AddAuthenticationSchemes(QueryStringAuthOptions.QueryStringAuthSchema);
//});
});
services.AddAuthentication(o =>
{
o.SignInScheme = QueryStringAuthOptions.QueryStringAuthSchema;
}); //adds the auth services
services.AddMvc();
}
在上面的代码片段中,我们有两个选项。
- 覆盖
DefaultPolicy
或
- 向授权系统添加新的
Policy
。
现在使用哪个选项由您决定。使用后面的选项需要您明确告诉 Authorization
处理程序要使用哪个 AuthorizationPolicy
。
我建议您阅读 Custom Policy-Based Authorization 以了解它们的工作原理。
要使用此授权系统(取决于您上面的选项),您只需使用 AuthorizeAttribute()
装饰您的控制器(如果您使用第二个选项,则使用策略名称)。
我在 C# ASP Net Core 中为后端创建了一个 API。我试图想出一种方法来授权路由,以便它将在 url 中输入一个 API 键,例如“https://mywebsite.com/api/data/first?key=VX4HCOjtMQ6ZF978a245oLw00SfK0ahm”来验证路由并在中显示数据JSON.
我知道在 ASP NET Core 身份中有一种方法可以对路由进行身份验证,但这需要用户先登录。如何使用 API 密钥保护我的 API 路由?
您尝试执行的操作不会保护网络 api。我建议您查看 OAuth/OpenID。有一个名为 Identity Server 4 的开源 .net 核心实现。
但是,为了回答您的问题,您可以创建一个自定义属性来验证传递给您的操作的密钥,或者您可以简单地处理每个操作中的验证。在 .net core 中没有内置的方法来执行此操作,您将必须手动处理 api 键,就像传递到您的网络 api 的任何其他值一样。
从它的声音来看,您想要实现的是一个替代身份验证系统和一个使用此 key
查询字符串参数(这可能不是最佳设计)的自定义授权系统。
第一步是根据此 QueryString
参数对用户进行身份验证。现在最好的方法(IMO)是推出你自己的身份验证处理程序。查看 Aspnet Security 的代码揭示了他们现有的一些身份验证系统的内部工作原理。
实际上,我们要做的是尽早拦截请求,验证此 key
的存在,然后对请求进行身份验证。
下面显示了这个基本系统。
public class QueryStringAuthOptions : AuthenticationOptions
{
public const string QueryStringAuthSchema = "QueryStringAuth";
public const string QueryStringAuthClaim = "QueryStringKey";
public QueryStringAuthOptions()
{
AuthenticationScheme = QueryStringAuthSchema;
}
public string QueryStringKeyParam { get; set; } = "key";
public string ClaimsTypeName { get; set; } = "QueryStringKey";
public AuthenticationProperties AuthenticationProperties { get; set; } = new AuthenticationProperties();
}
public class QueryStringAuthHandler : AuthenticationHandler<QueryStringAuthOptions>
{
/// <summary>
/// Handle authenticate async
/// </summary>
/// <returns></returns>
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (Request.Query.TryGetValue(Options.QueryStringKeyParam, out StringValues value) && value.Count > 0)
{
var key = value[0];
//..do your authentication...
if (!string.IsNullOrWhiteSpace(key))
{
//setup you claim
var claimsPrinciple = new ClaimsPrincipal();
claimsPrinciple.AddIdentity(new ClaimsIdentity(new[] { new Claim(Options.ClaimsTypeName, key) }, Options.AuthenticationScheme));
//create the result ticket
var ticket = new AuthenticationTicket(claimsPrinciple, Options.AuthenticationProperties, Options.AuthenticationScheme);
var result = AuthenticateResult.Success(ticket);
return Task.FromResult(result);
}
}
return Task.FromResult(AuthenticateResult.Fail("Key not found or not valid"));
}
}
现在上面的内容非常简单,我们已经创建了一个自定义 AuthenticationOptions
class,我们将在自定义 AuthenticationHandler
中使用它。如您所见,这非常简单,但最终我们创建了一个有效的身份验证票证 (ClaimsPrinciple
) 并以 Success
结果或 Fail()
.
接下来我们需要让身份验证系统在 .Net 管道中工作(请注意,这是 1.2,因为 2.0 已更改,请参见 Auth 2.0 Migration)。这是通过 AuthenticationMiddleware
完成的,因此在我们创建中间件的简单实现之前。
public class QueryStringAuthMiddleware : AuthenticationMiddleware<QueryStringAuthOptions>
{
public QueryStringAuthMiddleware(RequestDelegate next, IOptions<QueryStringAuthOptions> options, ILoggerFactory loggerFactory, UrlEncoder encoder)
: base(next, options, loggerFactory, encoder)
{
}
protected override AuthenticationHandler<QueryStringAuthOptions> CreateHandler()
{
return new QueryStringAuthHandler();
}
}
这非常基本,但只是创建了一个新的 QueryStringAuthHandler()
来处理身份验证请求。 (我们之前创建的那个)。现在我们需要将这个中间件放入管道中。因此,遵循 .Net 约定,静态扩展 class 可以通过管理选项的能力来做到这一点。
public static class QueryStringAuthMiddlewareExtensions
{
public static IApplicationBuilder UseQueryStringAuthentication(this IApplicationBuilder appBuilder)
{
if (appBuilder == null)
throw new ArgumentNullException(nameof(appBuilder));
var options = new QueryStringAuthOptions();
return appBuilder.UseQueryStringAuthentication(options);
}
public static IApplicationBuilder UseQueryStringAuthentication(this IApplicationBuilder appBuilder, Action<QueryStringAuthOptions> optionsAction)
{
if (appBuilder == null)
throw new ArgumentNullException(nameof(appBuilder));
var options = new QueryStringAuthOptions();
optionsAction?.Invoke(options);
return appBuilder.UseQueryStringAuthentication(options);
}
public static IApplicationBuilder UseQueryStringAuthentication(this IApplicationBuilder appBuilder, QueryStringAuthOptions options)
{
if (appBuilder == null)
throw new ArgumentNullException(nameof(appBuilder));
if (options == null)
throw new ArgumentNullException(nameof(options));
return appBuilder.UseMiddleware<QueryStringAuthMiddleware>(Options.Create(options));
}
}
到目前为止,已经有很多代码可以让身份验证系统就位,但是这是遵循 .net 核心团队提供的许多示例。
身份验证中间件工作的最后一步是修改 startup.cs
文件并添加身份验证系统。
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(); //adds the auth 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.UseQueryStringAuthentication(); //add our query string auth
//add mvc last
app.UseMvc();
}
我们就快完成了,到目前为止,我们已经有了对请求进行身份验证的机制,而且我们最好创建声明(可以扩展)以在需要时保存更多信息。最后一步是 Authorize
请求。这很简单,我们需要做的就是告诉默认授权处理程序您正在使用哪个登录模式,此外我们还需要我们之前应用的声明。回到 startup.cs
中的 ConfigureServices
方法,我们只需 AddAuthorization
进行一些设置。
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthorization(o =>
{
//override the default policy
o.DefaultPolicy = new AuthorizationPolicy(new[] { new ClaimsAuthorizationRequirement(QueryStringAuthOptions.QueryStringAuthClaim, new string[0]) }, new[] { QueryStringAuthOptions.QueryStringAuthSchema });
//or add a policy
//o.AddPolicy("QueryKeyPolicy", options =>
//{
// options.RequireClaim(QueryStringAuthOptions.QueryStringAuthClaim);
// options.AddAuthenticationSchemes(QueryStringAuthOptions.QueryStringAuthSchema);
//});
});
services.AddAuthentication(o =>
{
o.SignInScheme = QueryStringAuthOptions.QueryStringAuthSchema;
}); //adds the auth services
services.AddMvc();
}
在上面的代码片段中,我们有两个选项。
- 覆盖
DefaultPolicy
或 - 向授权系统添加新的
Policy
。
现在使用哪个选项由您决定。使用后面的选项需要您明确告诉 Authorization
处理程序要使用哪个 AuthorizationPolicy
。
我建议您阅读 Custom Policy-Based Authorization 以了解它们的工作原理。
要使用此授权系统(取决于您上面的选项),您只需使用 AuthorizeAttribute()
装饰您的控制器(如果您使用第二个选项,则使用策略名称)。