.NET Core MVC:存储当前子用户ID及默认跳转的最佳实践
问题1:存储当前查看子用户ID的最佳方案
先明确各方案的局限性:
- ViewBag:仅作用于当前请求周期,刷新即失效,完全不适合长期存储状态
- TempData:默认基于Session,仅保留到下一次请求(需手动调用
Keep()才会延长),不符合"直至主动切换"的持久需求 - Cookie/Session:是更合适的选择——Cookie适合客户端持久存储,Session则在服务器端存数据(仅客户端保留SessionId),安全性更高
Cookie实现示例(适合非敏感场景)
设置当前子用户ID
在切换子用户的Action中:
public IActionResult SwitchChild(string childId) { // 先校验该子用户是否属于当前家长(省略权限逻辑) Response.Cookies.Append( "CurrentChildId", childId, new CookieOptions { Expires = DateTimeOffset.Now.AddDays(7), HttpOnly = true, // 禁止前端JS读取,降低XSS风险 Secure = true, // 生产环境启用,仅HTTPS传输 SameSite = SameSiteMode.Strict }); return RedirectToAction("ChildDashboard"); }
读取当前子用户ID
// Controller中读取 var currentChildId = Request.Cookies["CurrentChildId"]; // 视图中读取 @{ var currentChildId = Context.Request.Cookies["CurrentChildId"]; }
Session实现示例(适合敏感场景)
首先在Program.cs中启用Session:
builder.Services.AddSession(options => { options.IdleTimeout = TimeSpan.FromHours(2); options.Cookie.HttpOnly = true; options.Cookie.Secure = true; }); app.UseSession(); // 需放在UseRouting之后、UseAuthorization之前
设置Session
public IActionResult SwitchChild(string childId) { // 权限校验 HttpContext.Session.SetString("CurrentChildId", childId); return RedirectToAction("ChildDashboard"); }
读取Session
var currentChildId = HttpContext.Session.GetString("CurrentChildId");
问题2:首个子用户ID的存储与默认跳转策略
核心逻辑:家长登录后,自动查询其名下子用户,若存在则选中第一个并存储状态,跳转至对应视图;若无子用户则引导创建。
登录时直接处理的示例
public async Task<IActionResult> Login(string returnUrl = null) { // 完成登录逻辑(省略) var parentId = User.FindFirstValue(ClaimTypes.NameIdentifier); // 查询当前家长的所有子用户(假设存在ParentChild关联表) var children = await _dbContext.ParentChildren .Where(pc => pc.ParentId == parentId) .Select(pc => pc.ChildId) .ToListAsync(); if (children.Any()) { var firstChildId = children.First(); // 用Cookie或Session存储(复用问题1的方法) HttpContext.Session.SetString("CurrentChildId", firstChildId); return RedirectToAction("ChildDashboard", new { childId = firstChildId }); } else { // 无子女则跳转创建页面 return RedirectToAction("CreateChild"); } }
全局过滤器自动处理(避免重复代码)
创建全局过滤器:
public class DefaultChildFilter : IActionFilter { private readonly IHttpContextAccessor _httpContextAccessor; private readonly ApplicationDbContext _dbContext; public DefaultChildFilter(IHttpContextAccessor httpContextAccessor, ApplicationDbContext dbContext) { _httpContextAccessor = httpContextAccessor; _dbContext = dbContext; } public async void OnActionExecuting(ActionExecutingContext context) { var user = _httpContextAccessor.HttpContext.User; if (user.IsInRole("Parent") && string.IsNullOrEmpty(_httpContextAccessor.HttpContext.Session.GetString("CurrentChildId"))) { var parentId = user.FindFirstValue(ClaimTypes.NameIdentifier); var firstChildId = await _dbContext.ParentChildren .Where(pc => pc.ParentId == parentId) .Select(pc => pc.ChildId) .FirstOrDefaultAsync(); if (!string.IsNullOrEmpty(firstChildId)) { _httpContextAccessor.HttpContext.Session.SetString("CurrentChildId", firstChildId); context.Result = new RedirectToActionResult("ChildDashboard", "Child", new { childId = firstChildId }); } else { context.Result = new RedirectToActionResult("CreateChild", "Child", null); } } } public void OnActionExecuted(ActionExecutedContext context) { } }
注册过滤器到Program.cs:
builder.Services.AddScoped<DefaultChildFilter>(); builder.Services.AddControllersWithViews(options => { options.Filters.Add<DefaultChildFilter>(); });
内容的提问来源于stack exchange,提问作者lbrettsinclair
相关产品推荐
相关产品推荐

