React异步调用两次Axios Post遇401及.NET Core JWT中间件问题
问题排查:React + .NET Core 二次请求鉴权异常
场景说明
React项目通过Axios在useEffect异步函数中先后发起两个POST请求:
- 先调用
getBookId接口获取书籍ID - 再用该ID调用
getBookDetail接口获取书籍详情
两个请求均携带Auth0生成的Authorization Token。
现象:第一个请求成功,第二个请求返回401;后端JwtMiddleware能触发并设置HttpContext.User,但无法进入控制器逻辑,抛出500内部错误。
尝试过两种中间件顺序:
- 将
UseMiddleware<JwtMiddleware>放在UseAuthorization之后、MapControllers之前:出现上述异常 - 将其放在
UseAuthentication之前:控制器中HttpContext.User无法被正确设置
相关代码
React前端代码
const BookStore = () => { useEffect(() => { const getBook = async() => { const {data: bookId} = await getBookId('testName') const {data: bookDetails} = await getBookDetails(bookId) } getBook() }, []) } export function getBookId(name:string) { return axios.post<string>('/api/getBookId', {name}, { headers: { "content-type": "application/json", Authorization: `Bearer ${token}` } }) } export function getBookDetail(id:string) { return axios.post<string>('/api/getBookDetail', {id}, { headers: { "content-type": "application/json", Authorization: `Bearer ${token}` } }) }
.NET Core JwtMiddleware代码
public class JwtMiddleware { private readonly RequestDelegate _next; public JwtMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext context) { try { context.Request.Headers.TryGetValue("Authorization", out var headerAuth); var jwtToken = headerAuth.First()?.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries)[1]; var handler = new JwtSecurityTokenHandler(); var jwtSecurityToken = handler.ReadJwtToken(jwtToken); var userName = jwtSecurityToken.Claims.First(c => c.Type == "userName").Value; // 此处存在未定义变量sub的错误 var userId = sub.Split(new[] {'|'}, StringSplitOptions.RemoveEmptyEntries)[1]; var claims = new List<Claim> { new("userName", userName), new("userId", userId), }; var userIdentity = new ClaimsIdentity(claims, "AppUser"); var userPrincipal = new ClaimsPrincipal(userIdentity); context.User = userPrincipal; await _next(context); } catch (Exception e) { Console.WriteLine("JwtMiddleware error: {0}", e); throw; } } }
Program.cs中间件配置
app.UseAuthentication(); app.UseAuthorization(); app.UseMiddleware<JwtMiddleware>(); app.MapControllers(); app.Run();
问题分析与解决方案
1. JwtMiddleware代码致命错误
Invoke方法中var userId = sub.Split(...)的sub变量未定义,会直接抛出异常,导致第二个请求进入中间件时触发500错误,前端感知为401(可能是后端异常处理返回了错误状态码)。
修复:从JWT Claims中正确获取sub字段:
var sub = jwtSecurityToken.Claims.First(c => c.Type == "sub").Value; var userId = sub.Split(new[] {'|'}, StringSplitOptions.RemoveEmptyEntries)[1];
2. 中间件顺序错误
.NET Core中间件执行顺序决定了鉴权逻辑的生效时机:
UseAuthentication负责验证Token并初始化HttpContext.UserUseAuthorization基于HttpContext.User完成权限校验- 自定义
JwtMiddleware若用于扩展/覆盖鉴权逻辑,必须放在UseAuthentication之后、UseAuthorization之前
正确配置顺序:
app.UseAuthentication(); // 自定义中间件放在鉴权初始化后、权限校验前 app.UseMiddleware<JwtMiddleware>(); app.UseAuthorization(); app.MapControllers(); app.Run();
原因:
- 若放在
UseAuthorization之后,权限校验已完成,修改HttpContext.User不会生效,且中间件异常会直接终止请求 - 若放在
UseAuthentication之前,默认鉴权逻辑会覆盖自定义设置的HttpContext.User
3. 前端潜在问题
检查两次请求中token是否一致,是否在第一个请求后过期或被意外修改,可在两个请求函数中打印token确认。
补充说明
自定义JwtMiddleware可以用来设置HttpContext.User,但必须严格遵循中间件执行顺序,同时确保代码逻辑无异常,否则会导致请求中断。
内容的提问来源于stack exchange,提问作者viscroad
相关产品推荐
相关产品推荐

