マルチテナントのブログ アプリケーションがあるとします。アプリケーションの各ユーザーは、サービスによってホストされている多数のブログを持っている場合があります。
私たちの API では、ブログ投稿の読み取りと書き込みの両方が可能です。場合によっては、BlogId の指定が省略可能です。たとえば、ASP.NET でタグ付けされたすべての投稿を取得します。
/api/posts?tags=aspnet
特定のブログで ASP.NET でタグ付けされたすべての投稿を表示する場合は、次のように要求できます。
/api/posts?blogId=10&tags=aspnet
新しいブログ投稿を作成する場合など、一部の API メソッドには有効な BlogIdが必要です。
POST: /api/posts
{
"blogid" : "10",
"title" : "This is a blog post."
}
BlogId が現在の (認証された) ユーザーに属していることを確認するには、サーバーで検証する必要があります。また、リクエストで指定されていない場合は、ユーザーのデフォルトの blogId を推測したいと思います (簡単にするために、デフォルトはユーザーの最初のブログであると想定できます)。
IAccountContext
現在のユーザーに関する情報を含むオブジェクトがあります。これは、必要に応じて注入できます。
{
bool ValidateBlogId(int blogId);
string GetDefaultBlog();
}
ASP.NET Web API では、次の推奨されるアプローチは次のとおりです。
- メッセージ本文または uri で BlogId が指定されている場合は、それを検証して、現在のユーザーに属していることを確認します。そうでない場合は、400 エラーをスローします。
- リクエストで BlogId が指定されていない場合は、からデフォルトの BlogId を取得
IAccountContext
し、コントローラー アクションで使用できるようにします。コントローラーにこのロジックを認識させたくないためIAccountContext
、アクションから直接呼び出したくないのです。
[アップデート]
Twitter での議論に続いて、@Aliostad のアドバイスを考慮して、ブログをリソースとして扱い、それを私の Uri テンプレートの一部にすることにしました (したがって、常に必要です)。
GET api/blog/1/posts -- get all posts for blog 1
PUT api/blog/1/posts/5 -- update post 5 in blog 1
単一のアイテムをロードするためのクエリ ロジックは、投稿 ID とブログ ID によってロードするように更新されました (テナントが他の人の投稿をロード/更新するのを避けるため)。
あとは、BlogId を検証するだけです。Uri パラメーターで検証属性を使用できないのは残念です。そうしないと、@alexanderb の推奨事項が機能していたはずです。代わりに、ActionFilter を使用することにしました。
public class ValidateBlogAttribute : ActionFilterAttribute
{
public IBlogValidator Validator { get; set; }
public ValidateBlogAttribute()
{
// set up a fake validator for now
Validator = new FakeBlogValidator();
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
var blogId = actionContext.ActionArguments["blogId"] as int?;
if (blogId.HasValue && !Validator.IsValidBlog(blogId.Value))
{
var message = new HttpResponseMessage(HttpStatusCode.BadRequest);
message.ReasonPhrase = "Blog {0} does not belong to you.".FormatWith(blogId);
throw new HttpResponseException(message);
}
base.OnActionExecuting(actionContext);
}
}
public class FakeBlogValidator : IBlogValidator
{
public bool IsValidBlog(int blogId)
{
return blogId != 999; // so we have something to test
}
}
blogId の検証は、コントローラー/アクションを[ValidateBlog]
.
事実上すべての人の回答が解決策に役立ちましたが、コントローラー内の検証ロジックを結合しなかったため、@alexanderb を回答としてマークしました。