在ASP.NET Core 2.0管道中拦截401错误的技术问询
搞懂ASP.NET Core 2.0管道中401响应的拦截逻辑
先给你理清ASP.NET Core管道的核心规则:请求按中间件注册的顺序依次向前传递,响应则按反向顺序向后返回。这是理解所有中间件问题的关键。
先看你的两个核心中间件谁会返回401
app.UseIdentityServer():这个中间件负责处理身份验证、授权相关的逻辑(比如验证请求的token是否有效、处理授权端点)。如果请求的身份验证不通过,它会在请求阶段直接短路管道,返回401响应,不会继续调用后面的Mvc中间件。app.UseMvc():只有当请求进入Mvc框架后,才可能通过动作方法、过滤器返回401(比如自定义授权过滤器验证失败)。这种场景下的401是在Mvc内部生成的。
你的自定义中间件的问题
你现在的中间件代码有个致命的bug——没有调用await next.Invoke(),这会导致管道直接短路,请求无法继续向后传递。你能在UseIdentityServer()之后触发拦截,是因为IdentityServer已经在之前的步骤中设置了响应的401状态码,你的中间件只是在这个阶段读取了状态码而已,但这种写法完全不符合管道的正常逻辑。
正确的自定义中间件写法应该是这样的:
app.Use(async (httpContext, next) => { // 1. 先让请求继续向后传递到后续中间件 await next.Invoke(); // 2. 响应返回时,再检查状态码 if (httpContext.Response.StatusCode == StatusCodes.Status401Unauthorized) { Console.WriteLine("intercept!"); } });
不同位置的拦截效果
基于正确的中间件写法,我们来看不同注册位置的效果:
- 放在
app.UseIdentityServer()之前:请求先经过你的中间件,然后到IdentityServer;如果IdentityServer返回401,响应会按反向顺序回到你的中间件,此时能拦截到401。 - 放在
app.UseIdentityServer()之后、app.UseMvc()之前:如果IdentityServer返回401,响应会直接从IdentityServer返回,不会走到你的中间件(因为响应是反向顺序,IdentityServer在你的中间件前面),所以拦截不到;但如果是Mvc返回的401,响应会回到你的中间件,能拦截到。 - 放在
app.UseMvc()之后:只有当请求经过了所有前面的中间件(IdentityServer、Mvc)都没有返回401,才会走到你的中间件,这种情况下几乎不会拦截到任何401。
总结
如果你想拦截所有来源的401响应(包括IdentityServer和Mvc的),正确的做法是把修正后的自定义中间件注册在所有中间件的最前面,这样不管哪个中间件返回401,响应都会经过你的中间件,从而实现拦截。
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

