diff --git a/Source/Euonia.Bus.Abstract/DefaultIdentityProvider.cs b/Source/Euonia.Bus.Abstract/DefaultIdentityProvider.cs new file mode 100644 index 0000000..b1501b7 --- /dev/null +++ b/Source/Euonia.Bus.Abstract/DefaultIdentityProvider.cs @@ -0,0 +1,18 @@ +using System.Security.Principal; + +namespace Nerosoft.Euonia.Bus; + +internal class DefaultIdentityProvider : IIdentityProvider +{ + private readonly IdentityAccessor _accessor; + + public DefaultIdentityProvider(IdentityAccessor accessor) + { + _accessor = accessor; + } + + public IPrincipal GetIdentity(string authorization) + { + return _accessor(authorization); + } +} diff --git a/Source/Euonia.Bus.Abstract/IIdentityProvider.cs b/Source/Euonia.Bus.Abstract/IIdentityProvider.cs new file mode 100644 index 0000000..ee34d17 --- /dev/null +++ b/Source/Euonia.Bus.Abstract/IIdentityProvider.cs @@ -0,0 +1,16 @@ +using System.Security.Principal; + +namespace Nerosoft.Euonia.Bus; + +/// +/// Defines the identity provider. +/// +public interface IIdentityProvider +{ + /// + /// Get the identity from authorization header. + /// + /// + /// + IPrincipal GetIdentity(string authorization); +} \ No newline at end of file diff --git a/Source/Euonia.Bus.Abstract/IMessageContext.cs b/Source/Euonia.Bus.Abstract/IMessageContext.cs index 20daab1..bd4b4c5 100644 --- a/Source/Euonia.Bus.Abstract/IMessageContext.cs +++ b/Source/Euonia.Bus.Abstract/IMessageContext.cs @@ -1,4 +1,6 @@ -namespace Nerosoft.Euonia.Bus; +using System.Security.Principal; + +namespace Nerosoft.Euonia.Bus; /// /// Interface IMessageContext @@ -35,6 +37,11 @@ public interface IMessageContext : IDisposable /// string Authorization { get; set; } + /// + /// Gets the current user. + /// + IPrincipal User { get; } + /// /// Gets the message request headers. /// diff --git a/Source/Euonia.Bus.Abstract/IdentityAccessor.cs b/Source/Euonia.Bus.Abstract/IdentityAccessor.cs new file mode 100644 index 0000000..f6098d2 --- /dev/null +++ b/Source/Euonia.Bus.Abstract/IdentityAccessor.cs @@ -0,0 +1,10 @@ +using System.Security.Principal; + +namespace Nerosoft.Euonia.Bus; + +/// +/// The request context accessor. +/// +/// +/// +public delegate IPrincipal IdentityAccessor(string authorization); \ No newline at end of file diff --git a/Source/Euonia.Bus.Abstract/MessageContext.cs b/Source/Euonia.Bus.Abstract/MessageContext.cs index 4fece29..d33e993 100644 --- a/Source/Euonia.Bus.Abstract/MessageContext.cs +++ b/Source/Euonia.Bus.Abstract/MessageContext.cs @@ -1,4 +1,6 @@ -namespace Nerosoft.Euonia.Bus; +using System.Security.Principal; + +namespace Nerosoft.Euonia.Bus; /// /// The message context. @@ -31,7 +33,8 @@ public MessageContext(object message) /// Initializes a new instance of the class. /// /// - public MessageContext(IRoutedMessage pack) + /// + public MessageContext(IRoutedMessage pack, IdentityAccessor identity = null) : this(pack.Data) { MessageId = pack.MessageId; @@ -39,6 +42,7 @@ public MessageContext(IRoutedMessage pack) ConversationId = pack.ConversationId; RequestTraceId = pack.RequestTraceId; Authorization = pack.Authorization; + User = identity?.Invoke(pack.Authorization); } /// @@ -106,6 +110,9 @@ public string Authorization set => _headers[nameof(Authorization)] = value; } + /// + public IPrincipal User { get; } + /// public IReadOnlyDictionary Headers => _headers; @@ -136,7 +143,7 @@ public void Failure(Exception exception) { _events.HandleEvent(this, exception, nameof(Failed)); } - + /// /// Called after the message has been handled. /// This operate will raised up the event. diff --git a/Source/Euonia.Bus.InMemory/InMemoryDispatcher.cs b/Source/Euonia.Bus.InMemory/InMemoryDispatcher.cs index 28123bb..bbb220a 100644 --- a/Source/Euonia.Bus.InMemory/InMemoryDispatcher.cs +++ b/Source/Euonia.Bus.InMemory/InMemoryDispatcher.cs @@ -1,4 +1,6 @@ -namespace Nerosoft.Euonia.Bus.InMemory; +using Microsoft.Extensions.DependencyInjection; + +namespace Nerosoft.Euonia.Bus.InMemory; /// /// @@ -8,11 +10,22 @@ public class InMemoryDispatcher : DisposableObject, IDispatcher /// public event EventHandler Delivered; + private readonly IIdentityProvider _identity; + + /// + /// Initialize a new instance of + /// + /// + public InMemoryDispatcher(IServiceProvider provider) + { + _identity = provider.GetService(); + } + /// public async Task PublishAsync(RoutedMessage message, CancellationToken cancellationToken = default) where TMessage : class { - var context = new MessageContext(message); + var context = new MessageContext(message, authorization => _identity?.GetIdentity(authorization)); var pack = new MessagePack(message, context) { Aborted = cancellationToken @@ -26,7 +39,7 @@ public async Task PublishAsync(RoutedMessage message, Cancel public async Task SendAsync(RoutedMessage message, CancellationToken cancellationToken = default) where TMessage : class { - var context = new MessageContext(message); + var context = new MessageContext(message, authorization => _identity?.GetIdentity(authorization)); var pack = new MessagePack(message, context) { Aborted = cancellationToken @@ -60,7 +73,7 @@ public async Task SendAsync(RoutedMessage message, Cancellat public async Task SendAsync(RoutedMessage message, CancellationToken cancellationToken = default) where TMessage : class { - var context = new MessageContext(message); + var context = new MessageContext(message, authorization => _identity?.GetIdentity(authorization)); var pack = new MessagePack(message, context) { Aborted = cancellationToken diff --git a/Source/Euonia.Bus.RabbitMq/RabbitMqQueueConsumer.cs b/Source/Euonia.Bus.RabbitMq/RabbitMqQueueConsumer.cs index a205f69..77cf52e 100644 --- a/Source/Euonia.Bus.RabbitMq/RabbitMqQueueConsumer.cs +++ b/Source/Euonia.Bus.RabbitMq/RabbitMqQueueConsumer.cs @@ -9,6 +9,8 @@ namespace Nerosoft.Euonia.Bus.RabbitMq; /// public class RabbitMqQueueConsumer : RabbitMqQueueRecipient, IQueueConsumer { + private readonly IIdentityProvider _identity; + /// /// Initializes a new instance of the class. /// @@ -20,6 +22,19 @@ public RabbitMqQueueConsumer(IPersistentConnection connection, IHandlerContext h { } + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// + public RabbitMqQueueConsumer(IPersistentConnection connection, IHandlerContext handler, IOptions options, IIdentityProvider identity) + : this(connection, handler, options) + { + _identity = identity; + } + /// public string Name => nameof(RabbitMqQueueConsumer); @@ -61,7 +76,7 @@ protected override async void HandleMessageReceived(object sender, BasicDeliverE var props = args.BasicProperties; - var context = new MessageContext(); + var context = new MessageContext(message, authorization => _identity?.GetIdentity(authorization)); OnMessageReceived(new MessageReceivedEventArgs(message.Data, context)); diff --git a/Source/Euonia.Bus.RabbitMq/RabbitMqTopicSubscriber.cs b/Source/Euonia.Bus.RabbitMq/RabbitMqTopicSubscriber.cs index d61e243..32209b4 100644 --- a/Source/Euonia.Bus.RabbitMq/RabbitMqTopicSubscriber.cs +++ b/Source/Euonia.Bus.RabbitMq/RabbitMqTopicSubscriber.cs @@ -9,6 +9,8 @@ namespace Nerosoft.Euonia.Bus.RabbitMq; /// public class RabbitMqTopicSubscriber : RabbitMqQueueRecipient, ITopicSubscriber { + private readonly IIdentityProvider _identity; + /// /// Initializes a new instance of the class. /// @@ -20,6 +22,19 @@ public RabbitMqTopicSubscriber(IPersistentConnection connection, IHandlerContext { } + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// + public RabbitMqTopicSubscriber(IPersistentConnection connection, IHandlerContext handler, IOptions options, IIdentityProvider identity) + : this(connection, handler, options) + { + _identity = identity; + } + /// public string Name => nameof(RabbitMqTopicSubscriber); @@ -68,7 +83,7 @@ protected override async void HandleMessageReceived(object sender, BasicDeliverE var message = DeserializeMessage(args.Body.ToArray(), type); - var context = new MessageContext(); + var context = new MessageContext(message, authorization => _identity?.GetIdentity(authorization)); OnMessageReceived(new MessageReceivedEventArgs(message.Data, context)); diff --git a/Source/Euonia.Bus/BusConfigurator.cs b/Source/Euonia.Bus/BusConfigurator.cs index b89c76f..5dba645 100644 --- a/Source/Euonia.Bus/BusConfigurator.cs +++ b/Source/Euonia.Bus/BusConfigurator.cs @@ -168,4 +168,27 @@ public BusConfigurator SetConventions(Action configure configure?.Invoke(ConventionBuilder); return this; } + + /// + /// Register the message identity provider. + /// + /// + /// + public BusConfigurator SetIdentityProvider(IdentityAccessor accessor) + { + Service.TryAddSingleton(_ => new DefaultIdentityProvider(accessor)); + return this; + } + + /// + /// Register the message identity provider. + /// + /// + /// + public BusConfigurator SetIdentityProvider() + where T : class, IIdentityProvider + { + Service.TryAddSingleton(); + return this; + } } \ No newline at end of file diff --git a/Source/Euonia.Bus/Core/HandlerContext.cs b/Source/Euonia.Bus/Core/HandlerContext.cs index ec1c6c3..7615fae 100644 --- a/Source/Euonia.Bus/Core/HandlerContext.cs +++ b/Source/Euonia.Bus/Core/HandlerContext.cs @@ -159,7 +159,7 @@ private void ConcurrentDictionarySafeRegister(TKey key, TValue val } } - private static Expression[] GetArguments(MethodBase method, object message, MessageContext context, CancellationToken cancellationToken) + private static Expression[] GetArguments(MethodInfo method, object message, MessageContext context, CancellationToken cancellationToken) { var parameterInfos = method.GetParameters(); var arguments = new Expression[parameterInfos.Length]; diff --git a/Source/Euonia.Bus/Core/ServiceBus.cs b/Source/Euonia.Bus/Core/ServiceBus.cs index 95ae1a8..e4fadf4 100644 --- a/Source/Euonia.Bus/Core/ServiceBus.cs +++ b/Source/Euonia.Bus/Core/ServiceBus.cs @@ -54,6 +54,7 @@ public Task PublishAsync(TMessage message, PublishOptions options, Act { MessageId = options.MessageId ?? Guid.NewGuid().ToString(), RequestTraceId = context?.TraceIdentifier ?? options.RequestTraceId ?? Guid.NewGuid().ToString("N"), + Authorization = context?.Authorization, }; metadataSetter?.Invoke(pack.Metadata); return _dispatcher.PublishAsync(pack, cancellationToken); diff --git a/Source/Euonia.Hosting/Middlewares/ExceptionHandlingMiddleware.cs b/Source/Euonia.Hosting/Middlewares/ExceptionHandlingMiddleware.cs index 10895cf..fe6a305 100644 --- a/Source/Euonia.Hosting/Middlewares/ExceptionHandlingMiddleware.cs +++ b/Source/Euonia.Hosting/Middlewares/ExceptionHandlingMiddleware.cs @@ -45,7 +45,7 @@ private static Task HandleExceptionAsync(HttpContext httpContext, Exception exce var response = new { status = statusCode, - message = exception.Message, + message = exception is AggregateException ex ? ex.InnerException.Message : exception.Message, details = GetErrors(exception) }; diff --git a/project.props b/project.props index fdaadce..d16b777 100644 --- a/project.props +++ b/project.props @@ -1,6 +1,6 @@ - 8.1.5 + 8.1.8 damon Nerosoft Ltd. Euonia