C# 如何在ASP Net Core中授权Web API控制器
我已经为C#ASP网络内核中的后端创建了一个API。我试图找到一种授权路由的方法,这样它就可以在url(如“”)中接收API密钥来验证路由并以JSON格式显示数据C# 如何在ASP Net Core中授权Web API控制器,c#,asp.net,json,asp.net-core,authorize,C#,Asp.net,Json,Asp.net Core,Authorize,我已经为C#ASP网络内核中的后端创建了一个API。我试图找到一种授权路由的方法,这样它就可以在url(如“”)中接收API密钥来验证路由并以JSON格式显示数据 我知道在ASP NET Core identity中有一种对路由进行身份验证的方法,但这需要用户首先登录。如何使用API密钥保护我的API路由?您尝试执行的操作将无法保护web API。我建议您研究OAuth/OpenID。有一个名为Identity Server 4的开源.net核心实现 但是,要回答您的问题,您可以创建一个自定义属
我知道在ASP NET Core identity中有一种对路由进行身份验证的方法,但这需要用户首先登录。如何使用API密钥保护我的API路由?您尝试执行的操作将无法保护web API。我建议您研究OAuth/OpenID。有一个名为Identity Server 4的开源.net核心实现
但是,要回答您的问题,您可以创建一个自定义属性来验证传递给您的操作的密钥,或者只需在每个操作中处理验证。在.NETCore中没有内置的方法来实现这一点,您必须手动处理api密钥,就像其他传递给web api的值一样 听上去,您试图实现的是一个替代身份验证系统和一个自定义授权系统,它使用这个
键
查询字符串参数(这可能不是最佳设计)
第一步是基于此QueryString
参数对用户进行身份验证。现在最好的方法(IMO)是使用您自己的身份验证处理程序。查看的代码可以揭示一些现有身份验证系统的内部工作原理
// 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();
}
实际上,我们要做的是尽早拦截请求,验证该密钥的存在,然后对请求进行身份验证
下面展示了这个基本系统
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"));
}
}
这是非常基本的,但只是创建一个新的QueryStringAuthHandler()
来处理身份验证请求。(我们之前创建的)。现在我们需要将这个中间件引入到管道中。因此,按照.Net约定,静态扩展类可以通过管理选项来实现这一点
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));
}
}
我们就快到了,到目前为止,我们已经有了验证请求的机制,最好是创建声明(可以扩展),以便在需要时保存更多信息。最后一步是授权请求。这很简单,我们所需要做的就是告诉默认授权处理程序您正在使用的登录模式,此外,我们还需要我们前面应用的声明。回到startup.cs中的ConfigureServices
方法中,我们只需通过一些设置添加授权
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
或
将新的策略
添加到授权系统
现在,您使用哪个选项取决于您自己。使用后一个选项需要明确告诉授权
处理程序要使用哪个授权策略
我建议你阅读以了解这些是如何工作的
要使用此授权系统(取决于上面的选项),只需使用AuthorizeAttribute()
(如果使用第二个选项,则使用策略名称)装饰控制器即可。这看起来非常有希望,我一定会尝试一下。为什么这不是一个好的设计?我遇到过许多API,它们基于用户使用键来验证url。@RushB你是对的,有很多(或曾经是)应用程序将API键嵌入url。令牌身份验证(如JWT等)提供了一种更安全的数据交换方式,这一点已经发生了很大的变化。通常,这在标题中使用,而不是在查询字符串中使用。现在,通过将其放置在URL中,这是一个公共场所(是的,SSL可能会隐藏),但可以公开分发。如果使用授权标头,则可以确保不会意外复制和粘贴此信息。@RushB刚刚偶然发现了此线程,这增加了一些要点。我知道这是一种不好的做法,您不希望密钥在url中公开,但如果我只是通过来自iOS应用程序的网络请求调用url,并且密钥将隐藏在我的代码中,该怎么办。通过Alamofire的网络请求是否仍然会留下url线索或某种线索?我也读了你发布的链接。我是否可以使用核心标识来授权路由,并在标头中提供用户名和密码凭据以使路由有效?我已经尝试过使用它,每次都会转到登录页面,而不是让我直接访问数据。
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();
}