.NET Core如何识别JWT请求来自Postman还是浏览器并实现鉴权
识别Postman请求与浏览器请求的核心方法
首先明确:不存在100%不可绕过的识别方案,所有请求头都可以被人为伪造,但常规场景下以下方案可以拦截绝大多数直接复制Token用Postman调用的行为:
- 校验
User-Agent请求头:Postman默认发送的User-Agent会携带PostmanRuntime关键字,普通浏览器的UA不会包含该字段 - 校验
Referer/Origin请求头:浏览器发起同站业务请求时会自动携带对应站点的Referer/Origin值,直接用Postman发请求默认不会携带正确的业务站点域名的对应字段 - 校验绑定用户身份的安全Cookie:可以在用户首次访问业务站点时,下发一个和当前用户身份绑定的HttpOnly加密Cookie,JWT校验通过的同时还要校验该Cookie的有效性,Postman就算复制到了Token也无法获取浏览器端的HttpOnly Cookie
.NET Core 实现鉴权逻辑的步骤
第一步:创建自定义授权规则
// 自定义授权要求 public class BrowserOnlyRequirement : IAuthorizationRequirement { } // 授权要求的处理逻辑 public class BrowserOnlyHandler : AuthorizationHandler<BrowserOnlyRequirement> { protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, BrowserOnlyRequirement requirement) { if (context.Resource is not HttpContext httpContext) { context.Fail(); return Task.CompletedTask; } var request = httpContext.Request; // 1. 拦截Postman默认UA请求 var userAgent = request.Headers.UserAgent.ToString(); if (userAgent.Contains("PostmanRuntime", StringComparison.OrdinalIgnoreCase)) { context.Fail(); return Task.CompletedTask; } // 2. 校验Origin是否为业务域名,替换为你自己的站点域名 var allowedOrigin = "https://你的业务站点域名.com"; if (request.Headers.TryGetValue("Origin", out var origin) && origin != allowedOrigin) { context.Fail(); return Task.CompletedTask; } // 3. 校验绑定用户身份的安全Cookie if (!request.Cookies.TryGetValue("BizAuthCookie", out var bizCookie) || !ValidateBizCookie(bizCookie, context.User)) { context.Fail(); return Task.CompletedTask; } context.Succeed(requirement); return Task.CompletedTask; } // Cookie校验逻辑:需要和JWT中的用户身份绑定,比如解密Cookie后和JWT携带的用户ID做匹配 private bool ValidateBizCookie(string cookieValue, ClaimsPrincipal user) { var userIdFromJwt = user.FindFirstValue(ClaimTypes.NameIdentifier); if (string.IsNullOrEmpty(userIdFromJwt)) return false; // 替换为你自己的Cookie解密逻辑,推荐用.NET自带的IDataProtector实现加密解密 var userIdFromCookie = DecryptBizCookie(cookieValue); return userIdFromCookie == userIdFromJwt; } private string DecryptBizCookie(string cookieValue) { // 实现你的解密逻辑 return string.Empty; } }
第二步:注册授权服务
在Program.cs中注册自定义的授权规则和处理程序,确保你已经完成了常规的JWT鉴权配置:
builder.Services.AddAuthorization(options => { options.AddPolicy("BrowserOnly", policy => { policy.AddRequirements(new BrowserOnlyRequirement()); policy.RequireAuthenticatedUser(); // 要求JWT校验通过 }); }); // 注册自定义授权处理程序 builder.Services.AddScoped<IAuthorizationHandler, BrowserOnlyHandler>();
第三步:应用授权策略
在需要保护的接口Controller或者Action上添加授权特性即可:
[Authorize(Policy = "BrowserOnly")] [ApiController] [Route("api/[controller]")] public class BusinessController : ControllerBase { // 你的业务接口 }
注意事项
以上方案只能拦截未篡改请求头的普通Postman调用,无法阻止攻击者手动伪造浏览器请求头、复制对应Cookie发起请求的情况。如果需要更高的安全等级,可以额外叠加前端JS生成的动态请求签名、接口请求频率限制等策略,多层防护降低风险。
内容的提问来源于stack exchange,提问作者Aswin Moothedath
相关产品推荐
相关产品推荐

