ASP.NET WEB API自定义过滤器Session Token获取为Null问题求助
问题
我正在为ASP.NET Web API做JWT令牌的POC验证:
- 实现学生登录API,生成JWT令牌并存入Session
- 学生登录后请求个人资料接口时,需通过自定义
StudentAttribute过滤器验证身份 - 调试发现过滤器中从Session获取的Token值为Null,但通过请求头能正常获取该令牌
- 相同逻辑在MVC Core项目中可正常运行,求问题原因及解决办法
登录API代码
[HttpPost] public JsonResult AuthenticateStudent(string emailId, string password) { try { if(studBLObj.AuthenticateStudent(emailId, password)) { HttpContext.Session.SetString("email_ID", emailId); HttpContext.Session.SetString("studentRole", "Student"); string token = GenerateToken(); HttpContext.Session.SetString("Token", token); return new JsonResult(new { Success = true, message = "Login Succesful", token = token }); } else { return new JsonResult(new { Success = false, message = "Error! Please contact admin" }); } } catch (Exception e) { return new JsonResult(new { Success = false, message = e.Message }); } }
个人资料接口代码
[Student] [HttpGet] public string GetStudentProfile(int rollNo) { try { var studentsProfile = studentBLObj.GetStudentProfile(rollNo); JsonResult jsonResult = new JsonResult(studentsProfile); var jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(jsonResult.Value); return jsonString; } catch (Exception e) { throw e; } }
自定义StudentAttribute过滤器代码
public class StudentAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext context) { base.OnActionExecuting(context); // 此处无法获取Token,值为Null string sessionToken = context.HttpContext.Session.GetString("Token"); // 通过请求头可正常获取Token var req = context.HttpContext.Request.Headers["Authorization"]; if (sessionToken==null || sessionToken != req) { context.Result = new RedirectToRouteResult(new RouteValueDictionary { { "action", "UnauthorizedAccess" }, { "controller", "Student" } }); return; } else { return; } } }
原因分析
- Web API与MVC的Session依赖差异:MVC项目基于浏览器运行,浏览器会自动保存并在后续请求中携带Session对应的Cookie(如
.AspNetCore.Session);但Web API的客户端(如Postman、前端AJAX请求)默认不会自动处理Cookie,导致后续请求无法携带Session标识,服务器无法识别会话,因此Session中取不到值。 - JWT与Session的设计冲突:JWT的核心是无状态认证,令牌本身包含所有用户信息,不需要依赖服务器端Session存储;当前设计既用JWT又存Session,违背了JWT的无状态特性,也放大了Session在API场景中的局限性。
解决方案
方案1:修正Session使用方式(不推荐,仅适配API场景)
如果一定要保留Session验证逻辑,需确保客户端携带Session Cookie:
- 配置API允许Cookie传递:在
Program.cs中完善Session和Cookie政策配置
builder.Services.AddSession(options => { options.IdleTimeout = TimeSpan.FromMinutes(30); options.Cookie.HttpOnly = true; options.Cookie.IsEssential = true; }); builder.Services.Configure<CookiePolicyOptions>(options => { options.MinimumSameSitePolicy = SameSiteMode.None; options.HttpOnly = HttpOnlyPolicy.Always; options.Secure = CookieSecurePolicy.Always; // 生产环境启用,需HTTPS });
- 客户端设置:
- Postman:开启请求的「Send cookies」选项
- 前端AJAX:设置
withCredentials: true,同时后端需配置CORS允许凭证
方案2:遵循JWT无状态认证设计(推荐)
放弃Session存储Token,直接通过请求头验证JWT令牌,这是API场景的标准做法:
- 修改过滤器逻辑,直接解析验证请求头中的JWT令牌:
public class StudentAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext context) { base.OnActionExecuting(context); if (!context.HttpContext.Request.Headers.TryGetValue("Authorization", out var authHeader)) { context.Result = new UnauthorizedResult(); return; } var token = authHeader.ToString().Replace("Bearer ", string.Empty); try { var claimsPrincipal = ValidateToken(token); var roleClaim = claimsPrincipal.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Role); if (roleClaim?.Value != "Student") { context.Result = new ForbidResult(); return; } } catch (Exception) { context.Result = new UnauthorizedResult(); return; } } private ClaimsPrincipal ValidateToken(string token) { var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.ASCII.GetBytes("你的JWT密钥"); // 建议从配置文件读取 tokenHandler.ValidateToken(token, new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(key), ValidateIssuer = false, // 根据实际配置调整 ValidateAudience = false, ClockSkew = TimeSpan.Zero }, out SecurityToken validatedToken); return new ClaimsPrincipal(tokenHandler.ReadJwtToken(token).Claims); } }
- 登录API无需存储Session,直接返回JWT令牌即可:
[HttpPost] public JsonResult AuthenticateStudent(string emailId, string password) { try { if(studBLObj.AuthenticateStudent(emailId, password)) { string token = GenerateToken(); // 确保生成的Token包含Student角色声明 return new JsonResult(new { Success = true, message = "Login Successful", token = token }); } else { return new JsonResult(new { Success = false, message = "Error! Please contact admin" }); } } catch (Exception e) { return new JsonResult(new { Success = false, message = e.Message }); } }
内容的提问来源于stack exchange,提问作者Varun Gupta
相关产品推荐
相关产品推荐

