【发布时间】:2020-02-26 07:16:29
【问题描述】:
当 API 收到消息时,我的 .NET CORE API 自定义中间件被忽略。此中间件旨在对任何给定请求执行一些标头验证。
我希望标头验证中间件作为请求的一部分被调用,以便 header.isValid 显示此验证的结果。当我在控制器中放置断点时,标头变量为空。
我是否误解了中间件在期望它与控制器通信时可以做什么?我需要它做的就是充当对不良请求的看门人,因此我愿意让它终止不良请求并允许好的请求通过作为结果。
这就是我所拥有的
public interface IHeaderIsValid
{
bool isValid { get; set; }
bool fromCMDS { get; set; }
bool fromLocal { get; set; }
Int16 transmittingInstallationID { get; set; }
}
public class HeaderIsValid : IHeaderIsValid
{
public bool isValid { get; set; }
public bool fromCMDS { get; set; }
public bool fromLocal { get; set; }
public Int16 transmittingInstallationID { get; set; }
}
public static class RequestHeaderMiddlewareExtensions
{
public static IApplicationBuilder UseHeaderValidation(this IApplicationBuilder app)
{
return app.UseMiddleware<RequestHeaderMiddleware>();
}
}
public class RequestHeaderMiddleware
{
#region CONSTRUCTORS
/// <summary>
/// The Request header middleware constructor
/// </summary>
/// <param name="next">navigation parameter to pass the request to the next pipeline item</param>
public RequestHeaderMiddleware(RequestDelegate next)
{
_next = next;
}
#endregion
#region PUBLIC METHJODS
/// <summary>
/// Invoke the middleware to validate the request header
/// </summary>
/// <param name="context">the context of the request</param>
/// <returns>true or throws an exception</returns>
public async Task Invoke(HttpContext context, IHeaderIsValid header)
{
try
{
header.isValid = false;
bool hasInstallationID = Int16.TryParse(context.Request.Headers.FirstOrDefault(x => x.Key == "InstallationID").Value.ToString(), out this.transmittingInstallationID);
if (!hasInstallationID)
{
throw new NoInstallationIDOnHeaderException("No Installation ID on the Request Header");
}
string fromLocalHeader = context.Request.Headers.FirstOrDefault(x => x.Key == "FromLocal").Value.ToString();
if (fromLocalHeader != string.Empty)
{
bool.TryParse(fromLocalHeader, out this.fromLocal);
}
else
{
this.fromLocal = false;
}
bool hasFromCMDS = bool.TryParse(context.Request.Headers.FirstOrDefault(x => x.Key == "FromCMDS").Value.ToString(), out this.fromCMDS);
if (!hasFromCMDS)
{
this.fromCMDS = false;
}
if (this.fromCMDS && this.fromLocal)
{
throw new FromCMDSAndFromLocalSetException("The FromLocal and FromCMDS indicators are both set on the request header");
}
if (!this.fromCMDS && !this.fromLocal)
{
throw new NoOriginSetException("One of The FromLocal and FromCMDS indicators must be set on the request header");
}
}
catch (Exception ex)
{
throw ex;
}
header.isValid = true;
await _next(context);
}
#endregion
#region PRIVATE VARIABLES
private readonly RequestDelegate _next;
#endregion
#region PUBLIC VARIABLES
public Int16 transmittingInstallationID;
public bool fromCMDS;
public bool fromLocal;
#endregion
}
然后在 startup.cs 中(为简洁起见,对 ConfigurationServices 进行了修剪)
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IHeaderIsValid, HeaderIsValid>();
services.AddMvcCore()
.AddAuthorization()
.AddJsonFormatters();
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
loggerFactory.AddLog4Net();
app.UseCors("default");
app.UseAuthentication();
app.UseMvc();
// My custom middleware to validate the header
app.UseHeaderValidation();
}
}
}
这是来自控制器的 sn-p:
[Route("LDH/[controller]")]
[ApiController]
public class SalesController : ControllerBase
{
[Authorize]
[HttpPost("ProcessPayment")]
public async Task<ActionResult> ProcessPayment(WorkingTicket ticketDetails)
{
if (!header.isValid)
{
ModelState.AddModelError("BadHeader", "Request header is invalid");
return BadRequest(ModelState);
}
Return OK();
}
private IHeaderIsValid header;
}
【问题讨论】:
-
在您的 Configure 方法中,您定义了一个管道,目前是 HTTP 请求 -> Cors -> Auth -> MVC(完成所有控制器的工作)-> 响应模型 -> Auth -> Cors - > HTTP 响应。管道中的每个中间件都可以选择不调用下一个委托,例如当凭据不匹配并且 MVC 永远不会调用下一个委托时进行身份验证。因此,您需要将中间件放在 MVC 之前。
-
通过在
Configure()method 顺序中设置管道很重要。所以你应该在UseMvc()之前移动UseHeaderValidation()。根据您的期望,您可能还应该在UseAuthentication()之前移动它。 -
就是这样。非常赞赏。
标签: c# asp.net-mvc asp.net-web-api