Building micro services through Event Driven Architecture part19 : Building and Securing Real Time Communications using SignalR and Azure Active Directory
Building micro services through Event Driven Architecture part19 : Building and Securing Real Time Communications using SignalR and Azure Active Directory
This tutorial is the 19th part of a series : Building microservices through Event Driven Architecture.
The previous step is about Building micro services through Event Driven Architecture part18 : Securing Query HTTP API using Azure Active Directory B2C
The command HTTP API store events to the event store but not publish them directly to the Kafka service bus. This scenario can be considered but I do not want the command Api to act also as a producer.
The other reason is that the frontend SPA should get push notification . It should also be informed that the commands it posted were successful.
So I need a notification system like SignalR.
The scenario is :
- The front SPA starts and subscribe to a SignalR group (subject )
- The front SPA post data to the command HTTP API
- The command HTTP API convert data it received from post/put/delete requests as events and store these events to the event store
- The command HTTP API push notifications to the SignalR group (subject ) .
- A producer service subscribed to the SignalR group receive notification and then publish events to the Kafka service bus.
- A consumer subscribed to the Kafka Service bus receive events from the Kafka service bus and then build a read model and store it to a non SQL database (Elasticsearch) and send a notification to a SignalR group
- The Front SPA get notified that the Elasticsearch index is updated and then refresh the view.
The push notification system therefore plays an essential role in this architecture.
What happens if a piece of the architecture is down (SignalR Hub, Kafka, database, API)? We will see it in a future tutorial.
In this tutorial, I will show how to build a SignalR Hub notification system and use an identity provider to secure the SignalR Hub notification system by enabling Oauth2 and OpenID Connect using Azure AD B2C.
Azure Active Directory B2C provides business-to-customer identity as a service. Your customers use their preferred social, enterprise, or local account identities to get single sign-on access to your applications and APIs.
Learn more about Azure AD B2C in What is Azure Active Directory B2C?
Azure Active Directory B2C
To setup Azure AD B2C as an identity provider , I need to create a B2C tenant which is different from a Azure AD tenant
Azure AD B2C is a separate service from Azure Active Directory (Azure AD). It is built on the same technology as Azure AD but for a different purpose – to allow businesses build customer facing application and then allow anyone to sign up into those applications with no restrictions on user account.
Learn more about Azure AD in What is Azure Active Directory?
Building a SignalR Hub Notification
ASP.NET Core SignalR is an open-source library that simplifies adding real-time web functionality to apps. Real-time web functionality enables server-side code to push content to clients instantly.
https://docs.microsoft.com/en-us/aspnet/core/signalr/introduction?WT.mc_id=DOP-MVP-5003013
To build a SignalR Hub , you should define a class that inherits from Hub like this
using Microsoft.AspNetCore.SignalR;
namespace SignalRChat.Hubs
{
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync(“ReceiveMessage”, user, message);
}
}
}
To send a message to all connected clients, you have should use the SendMessage function and to receive a message, a connected client shoul listen on ReceiveMessage
You can use the following the link to get started using SignalR: https://docs.microsoft.com/en-us/aspnet/core/tutorials/signalr?view=aspnetcore-6.0&tabs=visual-studio
SendMessage and ReceiveMessage are used and invoked as string , So I will not proceed in the same way but rather use a strongly typed way
So I create a IHubInvoker interface to invoke the Hub :
- Publish : to publish a message of type T to the hub
- PublishToTopic : to publish a message of type T on a specific topic to the hub
- Subscribe : to subscribe to a topic
- UnSubscribe : to unsubscribe from a topic
I created a IHubNotifier interface to listen to messages coming from the hub.
And the SignalR Hub should inherit from Hub<IHubNotifier<T>>, IHubInvoker<T>
In startup.cs ( configure method) class associate an endpoitn with the connection
I created a ISignalRPublisher inerface to subscribe to a topic or publish message to the hub.
So to subscribe to a topic , I should invoke nameof(IHubInvoker<string>.Subscribe) and to publish to a topic I invoke nameof(IHubInvoker<Message>.PublishToTopic)
I created A ISignalRNotifier interface to Sart a client connection, Stop a cient connection and listen to messages
So to listen to and process the messages sent to the hub, I registers a handler that will be invoked when the hub method with the specified method name is invoked : nameof(IHubNotifier<string>.OnPublish)
The ISignalRNotifier should be used as the following
public interface ISignalRNotifier
{
event Action<string, object> ReceivedOnPublishToTopic;
Task StartAsync();
Task OnPublish();
Task OnPublish(string topic);
Task StopAsync();
}
To publish a message to the hub, I should use the ISignalRPublisher interface. I a disconnected client try to send a message to the hub, I connect it automatically before sending the message
Securing SignalR HUB
To protect the hub Hub notification server, I need to register an application in the azure AD B2C tenant, expose an endpoint
Azure AD B2C Application Registration
Go to the tenant and click app registration and fill in the form accordingly : provide an application name, the supported account types. Here I do not need a redirect URI because it is a web api.
Click on Expose an api and set the application ID URI (in my case https://workshopb2clogcorner.onmicrosoft.com/signalr/hub)
Configure SignalR Hub
Open the startup.cs class and add the following to register services required by authentication services and protects the hub with Microsoft identity platform
Open appsettings.Development.json and add the folllowing
Replace [ClientID] with the identifier of the application you registered ealier and [TenantName] with the name of your tenant in my case workshopb2clogcorner.
The user flows B2C_1_SignUpIn, B2C_1_PasswordReset and B2C_1_ProfileEdit was configured in the step 16 Building micro services through Event Driven Architecture part16 : Azure Active Directory B2C : https://logcorner.com/building-micro-services-through-event-driven-architecture-part16-azure-active-directory-b2c/
To enable authentication use the flag “isAuthenticationEnabled”: true in appSettings.json file.
To disable authentication use the flag “isAuthenticationEnabled”: false in appSettings.json file.
In startup.cs class it is managed like this :
bool.TryParse(Configuration[“isAuthenticationEnabled”], out var isAuthenticationEnabled);
if (!isAuthenticationEnabled)
{
endpoints.MapHub<LogCornerHub<object>>(“/logcornerhub”);
}
else
{
endpoints.MapHub<LogCornerHub<object>>(“/logcornerhub”).RequireAuthorization();
}
Testing
Run the application and navigate to http://localhost:5000/logcornerhub OR https://localhost:5001/logcornerhub
http://localhost:5000/logcornerhub
https://localhost:5001/logcornerhub
You can see that the hub is ready for client connection
Code source is available here :
Thanks for reading, if you have any feedback, feel free to post it
Regards