Web APIでASP.Net Core 2.0を使用しています。
私の最初の方法の1つはログインです:
/// <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);
}
}
DataAnnotationsを使用する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を返す最良の方法は何ですか?
もちろん、ヘルパーメソッドですべて自分で書くこともできます。しかし、フィルターについて考えたのでしょうか。
モデルの状態を確認する方法は?
アクションでコントローラーのModelState
を確認して、モデルの状態を取得します。
すべてのエラーから読み取り可能な文字列を取得し、このエラーでBadRequestを返しますか?
BadRequest(ModelState)
を使用して、モデルの状態を検査し、エラーを使用してメッセージを作成するHTTP bad request responseを返します。
完成したコード
/// <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);
}
}
または、モデルの状態を確認する必要があるすべての要求に適用されるグローバルに追加されます。
[ApiController]
およびWeb APIベースのプロジェクトでの検証を容易にするその他の属性を使用することを強くお勧めします。
[ApiController]
この属性は、メソッドに入る前にモーダルのすべての基本的な検証を行います。したがって、何らかの形式のカスタム検証を行いたい場合にのみ、モーダルを検査する必要があります。
モデルの状態が有効かどうかを確認するには、ModelStateプロパティを使用します(Controllerクラスが継承するControllerBaseクラスによって公開されます)
ModelState.IsValid
ModelStateからエラーを取得するには、ディクショナリからエラーを除外し、それらをリストとして返すことができます
var errors = ModelState
.Where(a => a.Value.Errors.Count > 0)
.SelectMany(x => x.Value.Errors)
.ToList();
1つのオプションは、すべてのメソッド/コントローラーで状態を検証することですが、モデルを検証する基本クラスで検証を実装することをお勧めします
このような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);
}
}
}