代码之家  ›  专栏  ›  技术社区  ›  PassionateDeveloper

在web api.core中,如何在每个方法中进行模型验证?

  •  8
  • PassionateDeveloper  · 技术社区  · 6 年前

    我正在使用Web API进入ASP.NET核心2.0。

    我的第一个方法是登录:

    /// <summary>
    /// API endpoint to login a user
    /// </summary>
    /// <param name="data">The login data</param>
    /// <returns>Unauthorizied if the login fails, The jwt token as string if the login succeded</returns>
    [AllowAnonymous]
    [Route("login")]
    [HttpPost]
    public IActionResult Login([FromBody]LoginData data)
    {
        var token = _manager.ValidateCredentialsAndGenerateToken(data);
        if (token == null)
        {
            return Unauthorized();
        }
        else
        {
            return Ok(token);
        }
    }
    

    我的 LoginData 使用数据注释:

    public class LoginData
    {
        [Required]
        [MaxLength(50)]
        public string Username { get; set; }
    
        [Required]
        public string Password { get; set; }
    
        [Required]
        [MaxLength(16)]
        public string IpAddress { get; set; }
    }
    

    所以我的 ModelState 当登录发生时自动填充良好,例如密码为空(当然,在客户端,稍后也应该对其进行验证)。

    我的问题是:
    最好的方法是什么a)检查模型状态,b)从所有错误中获取可读字符串,c)返回包含此错误的badRequest?

    当然,我可以用一个辅助方法把它全部写下来…但我想了一个过滤器?

    3 回复  |  直到 5 年前
        1
  •  15
  •   Nkosi    6 年前

    如何检查模型状态?

    检查控制器 ModelState 在获取模型状态的操作中。

    从所有错误中获取可读字符串并返回包含此错误的badRequest?

    使用 BadRequest(ModelState) 返回HTTP BAD请求响应,该响应将检查模型状态并使用错误构造消息。

    已完成代码

    /// <summary>
    /// API endpoint to login a user
    /// </summary>
    /// <param name="data">The login data</param>
    /// <returns>Unauthorizied if the login fails, The jwt token as string if the login succeded</returns>
    [AllowAnonymous]
    [Route("login")]
    [HttpPost]
    public IActionResult Login([FromBody]LoginData data) {
        if(ModelState.IsValid) {
            var token = _manager.ValidateCredentialsAndGenerateToken(data);
            if (token == null) {
                return Unauthorized();
            } else {
                return Ok(token);
            }
        }
        return BadRequest(ModelState);
    }
    

    当然,我可以用一个辅助方法把它全部写下来…但我想了一个过滤器?

    为了避免重复 ModelState.IsValid 在需要模型验证的每个操作中,您可以创建一个过滤器来检查模型状态并使请求短路。

    例如

    public class ValidateModelAttribute : ActionFilterAttribute {
        public override void OnActionExecuting(ActionExecutingContext context) {
            if (!context.ModelState.IsValid) {
                context.Result = new BadRequestObjectResult(context.ModelState);
            }
        }
    }
    

    可以直接应用于操作

    [ValidateModel] //<-- validation
    [AllowAnonymous]
    [Route("login")]
    [HttpPost]
    public IActionResult Login([FromBody]LoginData data) {
        var token = _manager.ValidateCredentialsAndGenerateToken(data);
        if (token == null) {
            return Unauthorized();
        } else {
            return Ok(token);
        }    
    }
    

    或全局添加以应用于应检查模型状态的所有请求。

    参考 Model validation in ASP.NET Core MVC

        2
  •  1
  •   Marcus Höglund    6 年前

    要检查模型状态是否有效,请使用ModelState属性(由控制器类继承的ControllerBase类公开)

    ModelState.IsValid
    

    要从ModelState中获取错误,可以从字典中筛选出错误并将其作为列表返回。

    var errors = ModelState
        .Where(a => a.Value.Errors.Count > 0)
        .SelectMany(x => x.Value.Errors)
        .ToList();
    

    一个选项是验证每个方法/控制器中的状态,但我建议您在基类中实现验证,该基类在
    这样的OnActionExecuting方法

    public class ApiController : Controller
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            if (!ModelState.IsValid)
            {
                var errors = ModelState
                    .Where(a => a.Value.Errors.Count > 0)
                    .SelectMany(x => x.Value.Errors)
                    .ToList();
                context.Result = new BadRequestObjectResult(errors);
            }
            base.OnActionExecuting(context);
        }
    }
    

    然后,应该具有自动模型状态验证的每个控制器只继承自基类

    public class TokenController : ApiController
    {
        /// <summary>
        /// API endpoint to login a user
        /// </summary>
        /// <param name="data">The login data</param>
        /// <returns>Unauthorizied if the login fails, The jwt token as string if the login succeded</returns>
        [AllowAnonymous]
        [Route("login")]
        [HttpPost]
        public IActionResult Login([FromBody]LoginData data)
        {
            var token = _manager.ValidateCredentialsAndGenerateToken(data);
            if (token == null)
            {
                return Unauthorized();
            }
            else
            {
                return Ok(token);
            }
        }
    }
    
        3
  •  1
  •   Hawkzey    5 年前

    我强烈推荐使用 [ApiController] 以及其他有助于在基于Web API的项目中简化验证的属性。

    [顶端控制器] 这个属性在进入方法之前为您对模式进行所有基本验证。因此,如果您想进行某种形式的自定义验证,那么只需要检查模式。