我正在尝试在ASP.NET Core中创建自定义身份验证筛选器。需要在控制器中使用它来验证提供给我的JWT并创建Claim Principal。但是,当我将身份验证标签放置在控制器上方时,什么也没发生,并且在没有身份验证的情况下对控制器进行了处理。
以下是已完成的步骤:
Configure(IApplicationBuilder app, IHostingEnvironment env)
{
......
......
app.UseAuthentication();
}
public class ProcessAuth : Attribute, IAuthenticationFilter
{
public bool AllowMultiple { get { return false; } }
public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
HttpRequestMessage request = context.Request;
AuthenticationHeaderValue authorization = request.Headers.Authorization;
// More code to be added for validating the JWT
}
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
throw new NotImplementedException(); //sample code
}
}
[ProcessAuth]
[Route("api/[controller]")]
[ApiController]
更多信息:
如果我将[Authorize]
添加到控制器,Postman只会返回一个401 Unauthorized error
也检查了this URL,但找不到问题。
更新:我检查了类似的Stack Overflow问题的答案,并遵循相同的问题,但问题仍然相同。
已安装Nuget软件包: Microsoft.AspNet.WebApi.Core以及Microsoft.AspNet.WebApi
使用的命名空间:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Filters;
using System.Web.Http.Controllers;
如何使它工作?我想念什么吗?
答案 0 :(得分:0)
根据您的代码,我发现您已在asp.net核心应用程序中使用过asp.net身份验证筛选器。这是行不通的。
在asp.net核心中,我们应该使用JWT熊身份验证中间件来满足您的要求。
您可以创建自定义OnChallenge来验证jwt令牌,并创建OnTokenValidated来添加声明。
更多详细信息,您可以参考以下代码:
services.AddAuthentication(auth =>
{
auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
auth.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(token =>
{
token.RequireHttpsMetadata = false;
token.SaveToken = true;
token.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
//Same Secret key will be used while creating the token
IssuerSigningKey = new SymmetricSecurityKey(SecretKey),
ValidateIssuer = true,
//Usually, this is your application base URL
ValidIssuer = "http://localhost:45092/",
ValidateAudience = true,
//Here, we are creating and using JWT within the same application.
//In this case, base URL is fine.
//If the JWT is created using a web service, then this would be the consumer URL.
ValidAudience = "http://localhost:45092/",
RequireExpirationTime = true,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
token.Events = new JwtBearerEvents {
OnChallenge = async ctx => {
},
OnTokenValidated = async ctx =>
{
//Get the calling app client id that came from the token produced by Azure AD
string clientId = ctx.Principal.FindFirstValue("appid");
//Get EF context
//var db = ctx.HttpContext.RequestServices.GetRequiredService<AuthorizationDbContext>();
//Check if this app can read confidential items
bool canReadConfidentialItems = await db.Applications.AnyAsync(a => a.ClientId == clientId && a.ReadConfidentialItems);
if (canReadConfidentialItems)
{
//Add claim if yes
var claims = new List<Claim>
{
new Claim("ConfidentialAccess", "true")
};
var appIdentity = new ClaimsIdentity(claims);
ctx.Principal.AddIdentity(appIdentity);
}
}
};
});
编辑:
您可以如下创建AuthenticationHandler和AuthenticationSchemeOptions类,然后在startup.cs中注册该类。然后,您可以使用[Authorize(AuthenticationSchemes = "Test")]
来设置特殊的AuthenticationSchemes。
更多详细信息,您可以参考以下代码示例:
public class ValidateHashAuthenticationSchemeOptions : AuthenticationSchemeOptions
{
}
public class ValidateHashAuthenticationHandler
: AuthenticationHandler<ValidateHashAuthenticationSchemeOptions>
{
public ValidateHashAuthenticationHandler(
IOptionsMonitor<ValidateHashAuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock)
: base(options, logger, encoder, clock)
{
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
//TokenModel model;
// validation comes in here
if (!Request.Headers.ContainsKey("X-Base-Token"))
{
return Task.FromResult(AuthenticateResult.Fail("Header Not Found."));
}
var token = Request.Headers["X-Base-Token"].ToString();
try
{
// convert the input string into byte stream
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(token)))
{
// deserialize stream into token model object
//model = Serializer.Deserialize<TokenModel>(stream);
}
}
catch (System.Exception ex)
{
Console.WriteLine("Exception Occured while Deserializing: " + ex);
return Task.FromResult(AuthenticateResult.Fail("TokenParseException"));
}
//if (model != null)
//{
// // success case AuthenticationTicket generation
// // happens from here
// // create claims array from the model
// var claims = new[] {
// new Claim(ClaimTypes.NameIdentifier, model.UserId.ToString()),
// new Claim(ClaimTypes.Email, model.EmailAddress),
// new Claim(ClaimTypes.Name, model.Name) };
// // generate claimsIdentity on the name of the class
// var claimsIdentity = new ClaimsIdentity(claims,
// nameof(ValidateHashAuthenticationHandler));
// // generate AuthenticationTicket from the Identity
// // and current authentication scheme
// var ticket = new AuthenticationTicket(
// new ClaimsPrincipal(claimsIdentity), this.Scheme.Name);
// // pass on the ticket to the middleware
// return Task.FromResult(AuthenticateResult.Success(ticket));
//}
return Task.FromResult(AuthenticateResult.Fail("Model is Empty"));
}
}
public class TokenModel
{
public int UserId { get; set; }
public string Name { get; set; }
public string EmailAddress { get; set; }
}
Startup.cs将以下代码添加到ConfigureServices方法中:
services.AddAuthentication(options =>
{
options.DefaultScheme
= "Test";
})
.AddScheme<ValidateHashAuthenticationSchemeOptions, ValidateHashAuthenticationHandler>
("Test", null);
控制器:
[Authorize(AuthenticationSchemes = "Test")]