You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ASP.NET Identity的Account控制器Login方法中添加额外参数?

解决登录后跳转丢失评分参数的问题

这个问题我之前也碰到过,核心原因是未登录用户提交POST表单时,被[Authorize]拦截并重定向到Login页面,而重定向是GET请求,原POST表单里的newRate参数没法被自动带到跳转URL里,导致登录成功后调用RateRestaurant时缺少必要参数。下面给你几个实用的解决方案:

方案一:扩展Login方法接收参数,用TempData暂存

首先修改Login的GET方法,让它能接收newRate和restaurantId参数,然后把这些参数存到TempData里(TempData在跨请求时能临时保存数据):

// GET: /Account/Login
[AllowAnonymous]
public ActionResult Login(string returnUrl, int? newRate, int? restaurantId)
{
    ViewBag.ReturnUrl = returnUrl;
    // 把评分参数暂存到TempData,登录成功后取用
    TempData["NewRate"] = newRate;
    TempData["RestaurantId"] = restaurantId;
    return View();
}

接着在Login的POST方法里,登录成功后检查TempData里的参数,如果存在就直接跳转到带参数的RateRestaurant:

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }

    // 执行登录逻辑
    var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
    switch (result)
    {
        case SignInStatus.Success:
            // 检查是否有暂存的评分参数
            if (TempData.TryGetValue("NewRate", out var newRateObj) && 
                TempData.TryGetValue("RestaurantId", out var restaurantIdObj) &&
                int.TryParse(newRateObj.ToString(), out int newRate) &&
                int.TryParse(restaurantIdObj.ToString(), out int restaurantId))
            {
                // 跳转到评分方法,带上完整参数
                return RedirectToAction("RateRestaurant", "Restaurants", new { newRate, restaurantId });
            }
            // 没有参数的话,正常跳转到原returnUrl
            return RedirectToLocal(returnUrl);
        case SignInStatus.LockedOut:
            return View("Lockout");
        case SignInStatus.RequiresVerification:
            return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
        default:
            ModelState.AddModelError("", "Invalid login attempt.");
            return View(model);
    }
}

方案二:自定义AuthorizeAttribute保存POST参数

因为原表单是POST提交,默认的[Authorize]只会把请求的路径作为returnUrl,不会携带POST参数。我们可以自定义一个AuthorizeAttribute,在拦截时把POST参数存到Session里:

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Request.HttpMethod == HttpMethod.Post.Method)
        {
            // 保存POST表单数据到Session
            var formData = filterContext.HttpContext.Request.Form;
            filterContext.HttpContext.Session["PendingPostData"] = formData;
            // 保存目标Action和Controller名称
            filterContext.HttpContext.Session["TargetAction"] = filterContext.ActionDescriptor.ActionName;
            filterContext.HttpContext.Session["TargetController"] = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
        }
        base.HandleUnauthorizedRequest(filterContext);
    }
}

然后把RateRestaurant方法上的[Authorize]替换成[CustomAuthorize]:

[CustomAuthorize]
public ActionResult RateRestaurant(int newRate, int restaurantId)
{
    // 原方法逻辑不变
    var stringUserId = User.Identity.GetUserId();
    var userId = new Guid(stringUserId);
    var rate = new Rate()
    {
        Rating = newRate,
        UserId = userId,
        RestaurantId = restaurantId
    };
    _context.Ratings.Add(rate);
    _context.SaveChanges();
    return RedirectToAction("Details", "Restaurants", new { id = restaurantId });
}

最后在Login的POST方法里,登录成功后检查Session里的暂存数据,如果存在就重新提交到目标Action:

case SignInStatus.Success:
    // 检查是否有暂存的POST请求数据
    if (Session["PendingPostData"] is NameValueCollection postData &&
        Session["TargetAction"] is string targetAction &&
        Session["TargetController"] is string targetController)
    {
        // 解析参数
        if (int.TryParse(postData["newRate"], out int newRate) &&
            int.TryParse(postData["restaurantId"], out int restaurantId))
        {
            // 清除Session里的临时数据
            Session.Remove("PendingPostData");
            Session.Remove("TargetAction");
            Session.Remove("TargetController");
            // 跳转到评分方法
            return RedirectToAction(targetAction, targetController, new { newRate, restaurantId });
        }
    }
    return RedirectToLocal(returnUrl);

方案三:将表单改为GET提交(不推荐)

如果业务允许,你可以把表单提交方式改成GET,这样提交时的URL会自动带上newRate和restaurantId参数,重定向到Login时returnUrl会包含这些参数,登录成功后直接跳转就能正常调用RateRestaurant:

using (Html.BeginForm("RateRestaurant", "Restaurants", new { restaurantId = Model.Restaurant.Id }, FormMethod.Get))
{
    <div>
        @Html.LabelFor(m => m.NewRate)
        @Html.DropDownListFor(m => m.NewRate, new SelectList(Model.RatesForDropDownList))
        <button type="submit">Rate</button>
    </div>
}

不过这种方式不推荐,因为评分属于用户操作,用POST更符合REST规范,也能避免参数在URL里暴露的问题。

内容的提问来源于stack exchange,提问作者bobeq

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:24:22