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

未授权用户提交表单后登录参数丢失问题求助

问题分析与修复方案

这个问题的核心在于:默认的AuthorizeAttribute拦截未授权的POST请求时,只会保存跳转的ReturnUrl,但不会保留表单里的提交数据。当用户登录成功后重定向回原Action时,原POST请求的表单数据已经丢失,导致model.Restaurant和NewComment.Body都为null,同时用户之前输入的评论内容也没了。

下面给你两种可行的修复思路,你可以根据自己的需求选择:


方案一:服务器端保存表单数据(适合传统页面跳转场景)

1. 自定义授权过滤器,保存POST表单数据

我们需要重写默认的授权过滤器,把用户提交的表单数据临时存在TempData里,这样登录后还能取回来:

public class SaveFormAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        // 只处理POST请求的表单数据
        if (filterContext.HttpContext.Request.HttpMethod == HttpMethod.Post.Method)
        {
            // 将表单数据和原跳转地址存入TempData
            filterContext.Controller.TempData["PostedForm"] = filterContext.HttpContext.Request.Form;
            filterContext.Controller.TempData["OriginalReturnUrl"] = filterContext.HttpContext.Request.Url.PathAndQuery;
        }
        base.HandleUnauthorizedRequest(filterContext);
    }
}

然后把全局过滤器里的new AuthorizeAttribute()替换成这个自定义过滤器。

2. 调整登录Action,重定向时携带上下文

在登录成功后,检查TempData里是否有保存的表单数据,如果有,就跳转到原提交地址:

[HttpPost]
public ActionResult Login(LoginViewModel model, string returnUrl)
{
    if (ModelState.IsValid && ValidateUser(model.Username, model.Password))
    {
        FormsAuthentication.SetAuthCookie(model.Username, model.RememberMe);
        
        // 优先处理保存的表单请求
        if (TempData["OriginalReturnUrl"] != null)
        {
            return Redirect(TempData["OriginalReturnUrl"].ToString());
        }
        
        if (!string.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl))
        {
            return Redirect(returnUrl);
        }
        return RedirectToAction("Index", "Home");
    }
    
    ModelState.AddModelError("", "用户名或密码错误");
    return View(model);
}

3. 修改AddComment Action,恢复表单数据

当用户登录后回到AddComment时,从TempData里取出之前保存的表单数据,填充到ViewModel中,这样用户能看到之前输入的评论内容,再次提交就能正常绑定参数:

[HttpPost]
public ActionResult AddComment(RestaurantViewModel model, Comment newComment)
{
    // 如果参数为空,尝试从TempData恢复表单数据
    if (model == null || newComment == null)
    {
        var savedForm = TempData["PostedForm"] as NameValueCollection;
        if (savedForm != null)
        {
            // 重建ViewModel和Comment对象
            model = new RestaurantViewModel();
            model.Restaurant = _context.Restaurants.Find(int.Parse(savedForm["Restaurant.Id"]));
            newComment = new Comment { Body = savedForm["NewComment.Body"] };
        }
        else
        {
            // 没有数据的话直接跳回详情页
            return RedirectToAction("Details", new { id = model?.Restaurant.Id ?? 0 });
        }
    }
    
    // 原有的评论保存逻辑
    var userId = User.Identity.GetUserId();
    var user = _context.Users.FirstOrDefault(u => u.Id == userId);
    
    newComment.RestaurantId = model.Restaurant.Id;
    newComment.AuthorId = Guid.Parse(userId);
    newComment.AuthorName = user.UserName;
    newComment.DateTime = DateTime.Now;
    
    _context.Comments.Add(newComment);
    _context.SaveChanges();
    
    return RedirectToAction("Details", "Restaurants", new { id = model.Restaurant.Id });
}

4. 优化ViewModel初始化

确保RestaurantViewModel里的NewComment是初始化好的,避免视图里出现空引用:

public class RestaurantViewModel
{
    public Restaurant Restaurant { get; set; }
    public Comment NewComment { get; set; }

    public RestaurantViewModel()
    {
        // 初始化空Comment,确保TextBoxFor能正常渲染
        NewComment = new Comment();
    }
}

方案二:客户端Ajax提交(用户体验更优)

这种方式不需要页面跳转,当用户未登录时弹出登录模态框,登录成功后自动重新提交评论,全程保留用户输入的内容:

1. 修改视图为Ajax表单

@using (Ajax.BeginForm("AddComment", "Restaurants", new AjaxOptions { 
    HttpMethod = "POST",
    OnSuccess = "onCommentSuccess",
    OnFailure = "onCommentFailure"
})) {
    @Html.TextBoxFor(c => c.NewComment.Body)
    @Html.HiddenFor(m => m.Restaurant.Id)
    <button type="submit">Add comment</button>
}

<!-- 登录模态框(示例) -->
<div class="modal fade" id="loginModal">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-body">
                <input type="text" id="loginUsername" placeholder="用户名">
                <input type="password" id="loginPassword" placeholder="密码">
                <button id="submitLogin">登录</button>
            </div>
        </div>
    </div>
</div>

<script>
// 评论提交成功后的处理
function onCommentSuccess(result) {
    window.location.href = result.redirectUrl;
}

// 评论提交失败(未授权)的处理
function onCommentFailure(xhr) {
    if (xhr.status === 401) {
        // 保存当前表单数据,登录后重新提交
        var formData = $('form').serialize();
        $('#submitLogin').data('pendingForm', formData);
        // 弹出登录框
        $('#loginModal').modal('show');
    }
}

// 登录按钮点击事件
$('#submitLogin').click(function() {
    var username = $('#loginUsername').val();
    var password = $('#loginPassword').val();
    
    $.post('/Account/Login', { username: username, password: password }, function(res) {
        if (res.success) {
            $('#loginModal').modal('hide');
            // 重新提交之前的评论表单
            var pendingForm = $('#submitLogin').data('pendingForm');
            $.post('/Restaurants/AddComment', pendingForm, function() {
                window.location.href = '/Restaurants/Details/@Model.Restaurant.Id';
            });
        } else {
            alert('登录失败,请重试');
        }
    });
});
</script>

2. 调整AddComment Action返回Json结果

[HttpPost]
public ActionResult AddComment(RestaurantViewModel model, Comment newComment)
{
    if (!User.Identity.IsAuthenticated)
    {
        // 返回未授权状态码
        return new HttpStatusCodeResult(HttpStatusCode.Unauthorized);
    }
    
    var userId = User.Identity.GetUserId();
    var user = _context.Users.FirstOrDefault(u => u.Id == userId);
    
    newComment.RestaurantId = model.Restaurant.Id;
    newComment.AuthorId = Guid.Parse(userId);
    newComment.AuthorName = user.UserName;
    newComment.DateTime = DateTime.Now;
    
    _context.Comments.Add(newComment);
    _context.SaveChanges();
    
    return Json(new { success = true, redirectUrl = Url.Action("Details", "Restaurants", new { id = model.Restaurant.Id }) });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 06:31:17