ASP.NetFrameworkからASP.NetCoreに移行しています。
Web API2プロジェクトを使用するASP.NetFrameworkでは、次のようにAuthorizeAttributeをカスタマイズできます。
public class ApiAuthorizeAttribute : AuthorizationFilterAttribute
{
#region Methods
/// <summary>
/// Override authorization event to do custom authorization.
/// </summary>
/// <param name="httpActionContext"></param>
public override void OnAuthorization(HttpActionContext httpActionContext)
{
// Retrieve email and password.
var accountEmail =
httpActionContext.Request.Headers.Where(
x =>
!string.IsNullOrEmpty(x.Key) &&
x.Key.Equals("Email"))
.Select(x => x.Value.FirstOrDefault())
.FirstOrDefault();
// Retrieve account password.
var accountPassword =
httpActionContext.Request.Headers.Where(
x =>
!string.IsNullOrEmpty(x.Key) &&
x.Key.Equals("Password"))
.Select(x => x.Value.FirstOrDefault()).FirstOrDefault();
// Account view model construction.
var filterAccountViewModel = new FilterAccountViewModel();
filterAccountViewModel.Email = accountEmail;
filterAccountViewModel.Password = accountPassword;
filterAccountViewModel.EmailComparision = TextComparision.Equal;
filterAccountViewModel.PasswordComparision = TextComparision.Equal;
// Find the account.
var account = RepositoryAccount.FindAccount(filterAccountViewModel);
// Account is not found.
if (account == null)
{
// Treat the account as unthorized.
httpActionContext.Response = httpActionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
return;
}
// Role is not defined which means the request is allowed.
if (_roles == null)
return;
// Role is not allowed
if (!_roles.Any(x => x == account.Role))
{
// Treat the account as unthorized.
httpActionContext.Response = httpActionContext.Request.CreateResponse(HttpStatusCode.Forbidden);
return;
}
// Store the requester information in action argument.
httpActionContext.ActionArguments["Account"] = account;
}
#endregion
#region Properties
/// <summary>
/// Repository which provides function to access account database.
/// </summary>
public IRepositoryAccount RepositoryAccount { get; set; }
/// <summary>
/// Which role can be allowed to access server.
/// </summary>
private readonly byte[] _roles;
#endregion
#region Constructor
/// <summary>
/// Initialize instance with default settings.
/// </summary>
public ApiAuthorizeAttribute()
{
}
/// <summary>
/// Initialize instance with allowed role.
/// </summary>
/// <param name="roles"></param>
public ApiAuthorizeAttribute(byte[] roles)
{
_roles = roles;
}
#endregion
}
カスタマイズしたAuthorizeAttributeで、アカウントが有効かどうかを確認し、メッセージ付きのHttpStatusCodeをクライアントに返すことができます。
ASP.Net Coreで同じことをしようとしていますが、オーバーライドするOnAuthorizationがありません。
ASP.Net Frameworkと同じことをどのように達成できますか?
ありがとうございました、
あなたはこれに間違ってアプローチしています。このためのカスタム属性を作成したり、既存の属性を拡張したりすることは、実際には推奨されませんでした。 ASP.NET Coreを使用すると、下位互換性のために役割はシステムの一部になりますが、現在は推奨されていません。
いくつかの駆動アーキテクチャの変更と、これがどのように利用されるべきかについての素晴らしい2部構成のシリーズがあります ここ 。それでもロールに依存したい場合はそうすることができますが、ポリシーを使用することをお勧めします。
ポリシーを配線するには、次のようにします。
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthorization(options =>
{
options.AddPolicy(nameof(Policy.Account),
policy => policy.Requirements.Add(new AccountRequirement()));
});
services.AddSingleton<IAuthorizationHandler, AccountHandler>();
}
便宜上、Policy
列挙型を作成しました。
public enum Policy { Account };
エントリポイントを次のように装飾します。
[
HttpPost,
Authorize(Policy = nameof(Policy.Account))
]
public async Task<IActionResult> PostSomething([FromRoute] blah)
{
}
AccountRequirement
は単なるプレースホルダーであり、IAuthorizationRequirement
インターフェースを実装する必要があります。
public class AccountRequirement: IAuthorizationRequirement { }
ここで、ハンドラーを作成し、これをDIに接続する必要があります。
public class AccountHandler : AuthorizationHandler<AccountRequirement>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
AccountRequirement requirement)
{
// Your logic here... or anything else you need to do.
if (context.User.IsInRole("fooBar"))
{
// Call 'Succeed' to mark current requirement as passed
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
追加リソース
私のコメントはコメントとして見栄えが悪いので、回答を投稿しますが、MVCを使用する場合にのみ役立ちます。
// don't forget this
services.AddSingleton<IAuthorizationHandler, MyCustomAuthorizationHandler>();
services
.AddMvc(config => { var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser() .AddRequirements(new[] { new MyCustomRequirement() })
.Build(); config.Filters.Add(new AuthorizeFilter(policy)); })
また、質問コードの「HandleRequirementAsync」署名にはasyncキーワードが不要であることに気付きました。そして、Task.CompletedTaskを返すのは良いことだと思います。