验证当前密码的最佳方法是哪种?

时间:2018-10-17 18:03:05

标签: asp.net asp.net-core

我创建了一个表单,用户可以在其中更新他的数据帐户。通过这种形式,用户还可以更改帐户密码,在执行此操作之前,我先询问他当前的密码,这是字段:

<div class="form-group">
    <label>Current Password</label>
    <input class="form-control" id="oldPassword"
            asp-for="@Model.ExistingPassword" type="password" />
    <div class="invalid-feedback"></div>
</div>

您可以看到oldPassword输入绑定到属性ExistingPassword,该属性是该ViewModel的{​​{1}}的一部分,并具有以下声明:

View

提交表单后,我将调用以下[Required, MinLength(6), MaxLength(50), DataType(DataType.Password)] public string ExistingPassword { get; set; } 函数:

ajax

函数的参数采用形式,特别是:

  • URL:$.post(url, user, function (response) { //Some stuff }).done(function (response) { alert("Updated executed"); }).fail(function (jqXHR, textStatus, errorThrown) { alert("Error happened!"); });
  • 用户:$(this).attr('action');

该表单的操作将调用以下控制器:$(this).serialize();。 在User\UpdateUser方法内部,执行以下检查:

UpdateUser

基本上,条件检查当前密码是否正确,否则,将引发异常。

现在,我的问题是:我怎么知道该方法生成了哪种类型的异常?

我需要知道方法public async Task<UserProfileViewModel> UpdateUserAsync(UserProfileViewModel updatedUser) { if (!await _userManager.CheckPasswordAsync(originalUser, updatedUser.ExistingPassword)) throw new Exception("Invalid password"); 生成了哪种类型的异常,因为该方法中存在不同的异常。

假设引发了UpdateUser异常,我需要在Invalid Password旁边的invalid-feedback div中显示一条消息,以便用户知道更新失败的原因。

在此先感谢您的帮助。

3 个答案:

答案 0 :(得分:1)

通常,除实际例外情况外,我建议不要使用例外,但是考虑到您设计例外的方式,您可以有一些选择。

我建议创建一个可引发的自定义“ UpdateUserException”,其中将包含其他信息,这些信息可以由枚举或仅由字符串提供。

public class UpdateUserException : Exception {
    public UpdateUserError ErrorCondition;

    public UpdateUserException(UpdateUserError error, string message)
    {
        ErrorCondition = error;
        Message = message;
    }
}

然后您将其扔掉

throw new UpdateUserException(UpdateUserError.BadPassword, "Invalid Password");

那么你会抓住它

try {}
catch (UpdateUserException e)
{
    if (e.ErrorCondition == UpdateUserException.BadPassword)
    {
        // handle your exception.
    }
}

答案 1 :(得分:0)

看看UserManager ChangePassword方法。

您可以像这样(在Startup.cs中)将UserManager绑定为使用DependencyInjection

public async void Configure(IApplicationBuilder app, IHostingEnvironment env)
      {
           ...

            app.UseAuthentication();
            app.UseMvc();

            var scopeFactory = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>();
            using (var scope = scopeFactory.CreateScope())
            {
                UserManager<User> userManager = scope.ServiceProvider.GetRequiredService<UserManager<User>>();
            }

        }

然后在您的Controller的构造函数中

    private readonly UserManager<User> _userManager;

    public AccountController(UserManager<User> userManager)
    {
        _userManager = userManager;
    }

最后是端点:

    [HttpPost("ChangePassword")]
    public async Task<IActionResult> ChangePassword([FromBody]ChangePasswordRequest changePasswordParams)
    {
        if (changePasswordParams == null)
            return BadRequest($"{nameof(changePasswordParams)} must not be null!");

        if (string.IsNullOrWhiteSpace(changePasswordParams.OldPassword) || string.IsNullOrWhiteSpace(changePasswordParams.NewPassword))
            return BadRequest("old and new passwords have to be provided, but they both are empty.");

        var userId = User.Claims.FirstOrDefault(c => c.Type == "id")?.Value;
        var user = await _userManager.FindByIdAsync(userId);
        var result = await _userManager.ChangePasswordAsync(user, changePasswordParams.OldPassword, changePasswordParams.NewPassword);

        if (result.Succeeded)
            return NoContent();

        return BadRequest(result.Errors);
    }

之后,您可以在switch语句中处理the errors

答案 2 :(得分:0)

不建议将异常用于处理的错误,因为它们通常最终会导致内部服务器错误,而实际上这超出了其目的。

最好的方法是按照@maerlin的说明发送BadRequest。

但是,如果您坚持要在应用程序中使用异常,或者您的应用程序被设计为以这种方式工作。我建议您从ApplicationException继承新的CustomApplcationException类,然后从CustomApplicationException类继承UpdateUserException和vs。之后,建议您在ErrorHandlingMiddleware中处理异常,并至少使用BadRequest(400)状态代码返回HandledExceptions。

示例代码为

public class ExceptionMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILoggerManager _logger;

    public ExceptionMiddleware(RequestDelegate next, ILoggerManager logger)
    {
        _logger = logger;
        _next = next;
    }

    public async Task InvokeAsync(HttpContext httpContext)
    {
        try
        {
            await _next(httpContext);
        }
        catch (CustomApplicationException cae)
        { 
            await HandleCustomExceptionAsync(httpContext, cae);
        }
        catch (Exception ex)
        {
            _logger.LogError($"Something went wrong: {ex}");
            await HandleExceptionAsync(httpContext, ex);
        }
    }

    private static Task HandleExceptionAsync(HttpContext context, Exception exception)
    {
        context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

        return context.Response.WriteAsync(new ErrorDetails()
        {
            StatusCode = context.Response.StatusCode,
            Message = "Internal Server Error from the custom middleware."
        }.ToString());
    }

    private static Task HandleCustomExceptionAsync(HttpContext context, Exception exception)
    {
        context.Response.StatusCode = 400;

        return context.Response.WriteAsync(new ErrorDetails()
        {
            StatusCode = context.Response.StatusCode,
            Message = exception.Message
        }.ToString());
    }
}

然后您需要在Startup.cs中重新注册中间件

 app.UseMiddleware<ExceptionMiddleware>();

请参阅https://code-maze.com/global-error-handling-aspnetcore/http://www.talkingdotnet.com/global-exception-handling-in-aspnet-core-webapi/了解更多详细信息。