查看使用新的Mediatr 3.0功能管道行为进行身份验证/授权.
您通常会根据消息或处理程序进行身份验证吗?我问的原因是我在处理程序上进行身份验证(与MVC中的控制器相同)但是行为似乎没有关于处理程序的知识,因此我不确定这是否可行/适合.
我可以为每条消息添加一个IAuthorisationRequired标记接口,但如果消息是通知/事件并且有多个处理程序,那么可能有些应该运行而不是其他运行.真的感觉更好地检查执行实际工作的处理程序代码的auth.
希望能够在处理程序上放置[Authorize]属性并使用一个行为来检查它(我目前正是这样做但是使用基类而不是行为).
public class AuthenticationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
public Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next)
{
//Can't access handler class here, so how do I know the action requires authentication/authorization?
return next();
}
}
[Authorize]
public class ChangePasswordRequestHandler : IAsyncRequestHandler<ChangePassword, ReponseType>
{
protected override async Task<ReponseType> Handle(AsyncRequestBase<ChangePassword> message)
{
//change users password here
}
}
Run Code Online (Sandbox Code Playgroud)
你是对的,RequestDelegateHandler<TResponse>不会暴露接下来会运行的处理程序,这是故意的.如果你考虑一下,MediatR 2.x中的管道使用装饰器,而装饰者可以访问decoratee的实例,我建议不要基于它进行auth.原因是如果你需要你的授权装饰器来装饰处理程序的一个特定实例 - 用特定属性装饰的那个 - 那么它们是耦合的,这会破坏装饰器的目的,你应该能够将它们放在每个其他独立的.
这就是为什么我建议基于消息的授权,至少在大多数情况下.您可以使用可扩展的设计将每条消息与多个授权规则相关联,并且行为将评估所有这些规则.
public interface IAuthorizationRule<TRequest>
{
Task Evaluate(TRequest message);
}
public class AuthorizationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
private readonly IAuthorizationRule<TRequest>[] _rules;
public AuthorizationBehavior(IAuthorizationRule<TRequest>[] rules)
{
_rules = rules;
}
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next)
{
// catch it or let it bubble up depending on your strategy
await Task.WaitAll(_rules.Select(x => x.Evaluate(request)));
return next();
}
}
Run Code Online (Sandbox Code Playgroud)
对于特定情况,您提到,对于通知,某些处理程序可能会运行而其他处理程序不应运行,您始终可以使用针对该特定消息的授权行为,并将其有选择地应用于需要它们的处理程序.我想我的观点是,当你遇到这些特定场景时,你必须做一些自己的工作.