【问题标题】:ASP.NET MVC Why doesn't this post action get called from the view?ASP.NET MVC 为什么不从视图中调用此发布操作?
【发布时间】:2016-08-22 17:50:30
【问题描述】:

在一个使用Identity框架进行身份验证的系统中,我分别有以下Model、Controller action和View来实现密码修改功能(我看了很多文章学习如何重设密码,但不知道如何修改密码)密码,即使当前密码是已知的):

型号:

public class ChangePasswordBindingModel
    {
        [Required]
        [DataType(DataType.Password)]
        public string OldPassword { get; set; }

        [Required]
        [DataType(DataType.Password)]
        [Display(Name = "New password")]
        public string NewPassword { get; set; }

        [Required]
        [DataType(DataType.Password)]
        [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }
}

AccountController.cs 中的控制器操作:

[HttpPost]
public async Task<ActionResult> ChangePassword(ChangePasswordBindingModel loginChange)
{

    IdentityResult fffx = await UserManager.ChangePasswordAsync("userId", loginChange.OldPassword, loginChange.NewPassword);
    return View("Index");
}

查看密码更改表单,名为ChangePassword.cshtml

@model IdentityDevelopment.Models.ChangePasswordBindingModel
@{ ViewBag.Title = "ChangePassword";}
<h2>Change Password</h2>


@using (Html.BeginForm("ChangePassword","Account", FormMethod.Post))
{
    //@Html.AntiForgeryToken();
    <input type="hidden" name="returnUrl" value="@ViewBag.returnUrl" />

    <div class="form-group">
        <label>Current Password</label>
        @Html.PasswordFor(x => x.OldPassword, new { @class = "form-control" })
    </div>

    <div class="form-group">
        <label>New Password</label>
        @Html.PasswordFor(x => x.NewPassword, new { @class = "form-control" })
    </div>


    <div class="form-group">
        <label>Re-enter New Password</label>
        @Html.PasswordFor(x => x.ConfirmPassword, new { @class = "form-control" })
    </div>

    <button class="btn btn-primary" type="submit">Save</button>
}

为什么点击表单上的“保存”按钮不会调用 post 操作方法?

编辑 1:

我包括用于登录的控制器方法,其中一个场景会导致出现 ChangePassword 表单。也许这里有什么问题?

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginModel details, string returnUrl)
{
  if (ModelState.IsValid)
    {
       AppUser user = await UserManager.FindAsync(details.Name,
                    details.Password);
        if (user == null)
         {
                    ModelState.AddModelError("", "Invalid name or password.");
          }
      else
       {

    //Check if this is initial login of user, force password change if so
                    PasswordChangeChecker PassCheck = new PasswordChangeChecker();
                    string userId = user.Id.ToString();
                    bool proceed = PassCheck.IsPasswordChangedFromInitial(userId);
                    if (proceed)
                    {
                        ClaimsIdentity ident = await UserManager.CreateIdentityAsync(user,
                                             DefaultAuthenticationTypes.ApplicationCookie);
                        ident.AddClaims(LocationClaimsProvider.GetClaims(ident));
                        ident.AddClaims(ClaimsRoles.CreateRolesFromClaims(ident));
                        AuthManager.SignOut();
                        AuthManager.SignIn(new AuthenticationProperties
                        {
                            IsPersistent = false
                        }, ident);


                        //persist login into db
                        Loginobject login = new Loginobject();
                        login.Username = user.UserName;
                        login.SessionId = HttpContext.Session.SessionID;
                        Session["sessionid"] = HttpContext.Session.SessionID;
                        login.Date = DateTime.Now;
                        SQLLoginrecord sqlLogin = new SQLLoginrecord();
                        sqlLogin.PutOrPostLogin(login);

                        TempData["LoginMsg"] = "Any existing sessions are now deactivated.";

                        return Redirect(returnUrl);
                    }
                    else
                    {
                        return View("ChangePassword", new ChangePasswordBindingModel());
                    }
                }
            }
            ViewBag.returnUrl = returnUrl;
            return View(details);
        }

编辑 2:

看起来问题的原因是一个全局自定义授权过滤器(感谢 stephen.vakil 的评论)[AuthorizeSingleLogin],我已经把 AccountController.cs 的定义放在了上面

AuthorizeSingleLogin.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace IdentityDevelopment.Infrastructure
{
    public class AuthorizeSingleLogin : AuthorizeAttribute
    {
        private AppIdentityDbContext db = new AppIdentityDbContext();
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            bool isAuthorized = base.AuthorizeCore(httpContext);

            string user = httpContext.User.Identity.Name;

            string access = httpContext.Session.SessionID;

            if (String.IsNullOrEmpty(user) || String.IsNullOrEmpty(access))
            {
                return isAuthorized;
            }

            SQLLoginrecord sqlLogin = new SQLLoginrecord();

            return sqlLogin.IsLoggedIn(user, access);
        }
    }
}

SQLLoginrecord.cs

using IdentityDevelopment.Models;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
using static IdentityDevelopment.Models.Loginobject;

namespace IdentityDevelopment.Infrastructure
{
    public class SQLLoginrecord
    {

        private LoginobjectDBContext db = new LoginobjectDBContext();
        private bool PriorSessionActive = false;
        public void PutOrPostLogin(Loginobject login)
        {
            var logins = db.Loginobjects.Where(l => l.Username == login.Username);

            if (logins.Any())
            {
                Loginobject tempLogin = logins.First();
                tempLogin.SessionId = login.SessionId;
                tempLogin.Date = login.Date;
                db.Entry(tempLogin).State = EntityState.Modified;
                PriorSessionActive = true;
            }
            else
            {
                db.Loginobjects.Add(login);
            }
            db.SaveChanges();


        }

        public bool IsLoggedIn(string user, string session)
        {
            var logins = db.Loginobjects.Where(l => l.Username == user && l.SessionId == session);

            if (logins.Any())
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public bool PriorSessionUpdated()
        {
            return this.PriorSessionActive;
        }


    }

}

谢谢。

【问题讨论】:

  • 那么,当按钮被点击时会发生什么?你调试了吗?
  • 您的代码看起来不错。你有没有拦截提交按钮的js代码。
  • @BviLLe_Kid 是的,我已经通过在控制器的 post 方法中放置断点进行了调试。当我点击按钮时,我被重定向到索引页面,但这不是因为在这个 post 方法中调用了索引,而是来自其他地方。
  • @Shyju 不,任何地方的按钮都没有 javascript 干扰。
  • 您是否有全局身份验证过滤器或一些不寻常的路由表可以解释这种行为?

标签: c# asp.net asp.net-mvc asp.net-identity


【解决方案1】:

如果您的操作没有在帖子中被击中,而是转到其他地方,那会让我相信正在发生以下两种情况之一:

  1. 您的路由表配置不正确

  2. 您有一个全局过滤器(尤其是全局授权过滤器),它通过拦截请求并禁止或覆盖它来干扰您的预期行为。

通过调试和试错,你应该能够确定这两种情况的罪魁祸首。

【讨论】:

    【解决方案2】:

    你的

    <button class="btn btn-primary" type="submit">Save</button>
    

    元素必须是一个

    <input class="btn btn-primary" type="submit" value="Save"/>
    

    元素。

    【讨论】:

    • 是否有任何文档说明为什么两种类型都提交但行为不同?
    • 我试过了,但它也没有达到 post 方法的断点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多