替换操作过滤器中的参数

Replace parameter in an action filter

我正在尝试从我的操作过滤器中删除参数中捕获的密码,并将其替换为单词 "Removed",以便将参数存储在数据库中以供记录。密码存储在 ViewModel 中(取决于操作)。下面是关于我想要实现的目标的 "pseudo-code"。

我该如何处理 masking/replacing 将密码保存在数据库中?我遇到的主要问题是我不知道如何访问密码参数并更改它。我尝试使用 actionParams.TryGetValue("model, out value) 获取它,但问题是我不知道值的类型并且它会根据操作而变化。此外,我无法调用 actionParams["model"] 上的许多方法(例如包含)

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {

        var actionParam = filterContext.ActionParameters;

        // Remove the password from the parameters
        if (actionParam.ContainsKey("model") && actionParam["model"] != null)
        {           
            // If actionParam["model"].ToLower().Contains("password")
            // actionParam["model"]["password"] = "Removed";

            // If actionParam["model"].ToLower().Contains("confirm password")
            // actionParam["model"]["confirm password"] = "Removed";
        }

        string str = Json.Encode(filterContext.ActionParameters).Trim();

        string par = string.Empty;

        if (str.Length > 2)
        {
            par = str.Substring(1, str.Length - 2).Replace("\"", string.Empty);
        }

        ActionLog log = new ActionLog()
        {
            SessionId = filterContext.HttpContext.Session.SessionID,
            UserName = (request.IsAuthenticated) ? filterContext.HttpContext.User.Identity.Name : "Anonymous",
            Controller = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName,
            Action = filterContext.ActionDescriptor.ActionName,
            ActionParameters = par,
            IsPost = request.HttpMethod.ToLower() == "post" ? true : false,
            IPAddress = request.ServerVariables["HTTP_X_FORWARDED_FOR"] ?? request.UserHostAddress,
            UserAgent = request.UserAgent,
            ActionDate = filterContext.HttpContext.Timestamp
        };

         //Store the Audit into the Database
        ActionLogContext context = new ActionLogContext();
        context.ActionLogs.Add(log);
        context.SaveChanges();

        // Finishes executing the Action as normal
        base.OnActionExecuting(filterContext);

    }

可能的视图模型示例

public class LoginViewModel
{

    [Required]
    [Display(Name = "User ID")]
    [RegularExpression("^[a-zA-Z0-9]+$", ErrorMessage="Letters and Numbers Only")]
    public string UserName { get; set; }

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

}
public class ResetPasswordViewModel
{
    [Required]
    [EmailAddress]
    [Display(Name = "Email")]
    public string Email { get; set; }

    [Required]
    [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

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

    public string Code { get; set; }
}

可能的操作参数示例

        public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)

一种方法是使用接口作为抽象,这样您就不会直接处理 ViewModel。首先,为动作过滤器创建一些交互接口。

public interface IPassword
{
    string Password { get; set; }
}

public interface IConfirmPassword
{
    string ConfirmPassword { get; set; }
}

接下来,让您的 ViewModel 类 实现这些接口。

public class LoginViewModel : IPassword
{

    [Required]
    [Display(Name = "User ID")]
    [RegularExpression("^[a-zA-Z0-9]+$", ErrorMessage = "Letters and Numbers Only")]
    public string UserName { get; set; }

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

}
public class ResetPasswordViewModel : IPassword, IConfirmPassword
{
    [Required]
    [EmailAddress]
    [Display(Name = "Email")]
    public string Email { get; set; }

    [Required]
    [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

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

    public string Code { get; set; }
}

那么只需更新您的过滤器代码即可。除了它实现了 IPasswordIConfirmPassword 之外,过滤器不需要知道任何关于您的模型的更多信息,它可以通过强制转换进行检查。

当然,要使其正常工作,您必须在执行操作方法之前恢复原始值(或者在操作 运行 之后进行日志记录),以便操作方法具有正确的值。

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
    var actionParam = filterContext.ActionParameters;
    IPassword password = null;
    IConfirmPassword confirmPassword = null;

    string originalPassword;
    string originalConfirmPassword;

    // Remove the password from the parameters
    if (actionParam.ContainsKey("model") && actionParam["model"] != null)
    {
        // If the model doesn't implement the interface, the result
        // here will be null.
        password = actionParam["model"] as IPassword;
        confirmPassword = actionParam["model"] as IConfirmPassword;
    }

    if (password != null)
    {
        // Store the original value so it can be restored later
        originalPassword = password.Password;
        password.Password = "Removed";
    }

    if (confirmPassword != null)
    {
        // Store the original value so it can be restored later
        originalConfirmPassword = confirmPassword.ConfirmPassword;
        confirmPassword.ConfirmPassword = "Removed";
    }

    string str = Json.Encode(filterContext.ActionParameters).Trim();

    string par = string.Empty;

    if (str.Length > 2)
    {
        par = str.Substring(1, str.Length - 2).Replace("\"", string.Empty);
    }

    ActionLog log = new ActionLog()
    {
        SessionId = filterContext.HttpContext.Session.SessionID,
        UserName = (request.IsAuthenticated) ? filterContext.HttpContext.User.Identity.Name : "Anonymous",
        Controller = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName,
        Action = filterContext.ActionDescriptor.ActionName,
        ActionParameters = par,
        IsPost = request.HttpMethod.ToLower() == "post" ? true : false,
        IPAddress = request.ServerVariables["HTTP_X_FORWARDED_FOR"] ?? request.UserHostAddress,
        UserAgent = request.UserAgent,
        ActionDate = filterContext.HttpContext.Timestamp
    };

    //Store the Audit into the Database
    ActionLogContext context = new ActionLogContext();
    context.ActionLogs.Add(log);
    context.SaveChanges();

    // Restore the original values
    if (password != null)
    {
        password.Password = originalPassword;
    }

    if (confirmPassword != null)
    {
        confirmPassword.ConfirmPassword = originalConfirmPassword;
    }

    // Finishes executing the Action as normal
    base.OnActionExecuting(filterContext);

}