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

Gora LEYE

I'm a microsoft most valuable professional (MVP) .NET Architect and Technical Expert skills located in Paris (FRANCE). The purpose of this blog is mainly to post general .NET tips and tricks, www.masterconduite.com Gora LEYE

Support us

BMC logoBuy me a coffee