Learn More, Pay Less!
Limited Time Offer!
Open Closed

How to add logic when a user signs out or exits the application #8733


User avatar
0
roberto.fiocchi created
  • ABP Framework version: v8.3.2
  • UI Type: Blazor WASM
  • Database System: EF Core (SQL Server)
  • Tiered (for MVC) or Auth Server Separated (for Angular): no

Hi, I have an ABP 8.3.2 blazor wasm solution. I need to implement some additional logic when a user signs out or when a user exits the application. What is the best way to implement such logic using the ABP Framework?


15 Answer(s)
  • User Avatar
    0
    EngincanV created
    Support Team .NET Developer

    Hi, you need to create a custom event handler for that purpose. Please apply the following steps:

    1. Create a custom event handler as follows (doc: https://kevinchalet.com/2018/07/02/implementing-advanced-scenarios-using-the-new-openiddict-rc3-events-model/):
    using System.Threading.Tasks;
    using OpenIddict.Server;
    
    namespace MySolution;
    
    public class SignOutEventHandler : IOpenIddictServerHandler<OpenIddictServerEvents.ProcessSignOutContext>
    {
        public static OpenIddictServerHandlerDescriptor Descriptor { get; }
            = OpenIddictServerHandlerDescriptor.CreateBuilder<OpenIddictServerEvents.ProcessSignOutContext>()
                .UseSingletonHandler<SignOutEventHandler>()
                .SetOrder(100_000)
                .SetType(OpenIddictServerHandlerType.Custom)
                .Build();
        
        public ValueTask HandleAsync(OpenIddictServerEvents.ProcessSignOutContext context)
        {
            //your logic...
            
            return ValueTask.CompletedTask;
        }
    }
    
    1. Then register the event handler in the module class:
    
    public class MySolutionHttpApiHostModule : AbpModule
    {
        public override void PreConfigureServices(ServiceConfigurationContext context)
        {
            //...
            
            PreConfigure<OpenIddictServerBuilder>(serverBuilder =>
            {
                serverBuilder.AddEventHandler(SignOutEventHandler.Descriptor);
            });
            
            //...
        }
    }
    
    1. After these steps, your SignOutEventHandler class's HandleAsync method trigger after every signout request.
  • User Avatar
    0
    roberto.fiocchi created

    Hi, Thanks for the reply! This solution only works when a user correctly signs out of the application, which is a partial answer to my question. Is there no way to do the same also when a user closes the browser window or leaves the application website?

  • User Avatar
    0
    EngincanV created
    Support Team .NET Developer

    Hi, Thanks for the reply! This solution only works when a user correctly signs out of the application, which is a partial answer to my question. Is there no way to do the same also when a user closes the browser window or leaves the application website?

    Hi, there is not an event for that purpose on the OpenIddict side. You may consider using SignalR, and when the user disconnects, apply your logic. (however, sometimes signalr connection terminates because of numerous reasons, so you should check it accordingly)

    Regards.

  • User Avatar
    0
    roberto.fiocchi created

    Hi,

    Can you provide me with a code example of the SignalR approach you are suggesting?

  • User Avatar
    0
    EngincanV created
    Support Team .NET Developer

    Hi,

    Can you provide me with a code example of the SignalR approach you are suggesting?

    Hi, you can create a Hub, and then use the DisconnectAsync() method to control the disconnections (https://abp.io/docs/latest/framework/real-time/signalr):

    1-) Create a Hub:

    public class UserConnectionHub : AbpHub
    {
        public override async Task OnDisconnectedAsync(Exception exception)
        {
            await HandleUserLogout(Context.ConnectionId); //or your custom logic...
            
            await base.OnDisconnectedAsync(exception);
        }
    }
    

    2-) In your blazor side (connect):

            var connection = new HubConnectionBuilder()
                .WithUrl("/userConnectionHub")
                .WithAutomaticReconnect()
                .Build();
            
            try
            {
                await connection.StartAsync();
                Console.WriteLine("SignalR Connected.");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"SignalR Connection Failed: {ex.Message}");
            }
    

    You can call the code above, in a constructor of your blazor pages (in the base class).

  • User Avatar
    0
    roberto.fiocchi created

    Hi,

    Thanks for the example! I have a couple questions:

    1. With SignalR automated reconnect turned on in the HUB connection, how can i know when a user has disconnected from the application rather then having lost connection and trying to reconnect?
    2. How do you handle hub connection in the Chat Module, is there any standard you use in Blazor WASM?
    3. If multiple hubs are registered, would they interfere with each others or live independetly without problems?

    Thanks in advance.

  • User Avatar
    0
    EngincanV created
    Support Team .NET Developer
    1. With SignalR automated reconnect turned on in the HUB connection, how can i know when a user has disconnected from the application rather then having lost connection and trying to reconnect?

    Frankly speaking, I'm not sure you can do this with 100% correctness. However, you may create a temporary table/queue, push the current disconnected user to the queue, then read from the queue in a specific time interval, and check if there is an audit log there is related to the user after adding it to the queue. So, you can check if its really leave the application or temporarily disconnected.

    1. How do you handle hub connection in the Chat Module, is there any standard you use in Blazor WASM?

    You can download the chat module's source code and use its hub by your needs or you can follow the approach I suggested above.

    1. If multiple hubs are registered, would they interfere with each others or live independetly without problems?

    They should live independently without problems.


    Using SignalR might be hard to maintain and ensure user leaved the application or not. Maybe you can search for another approach for your use case. For example, you might use beforeunload event on the JS side (https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event), or use a similar approach for the Blazor WASM.

    Regards.

  • User Avatar
    0
    roberto.fiocchi created

    Hi,

    I can't seem to be able to download the Chat Module source code, could you kindly send it to my email or explain the approach you used in the module?

    Thanks.

  • User Avatar
    0
    EngincanV created
    Support Team .NET Developer

    Hi,

    I can't seem to be able to download the Chat Module source code, could you kindly send it to my email or explain the approach you used in the module?

    Thanks.

    In the chat module, there is a hub class called ChatHub and we simply use it to trigger a socket connection (for sending a message, deleting a conversation, and deleting a message on the server side, and on the client side doing the receiving events). Creating a new hub and using its DisconnectAsync is what comes to my mind as the first solution.

    However, investigating the other options can be better, because it might be hard to maintain and understand if the user really disconnected temporarily or permanently. Since this is not related to ABP, I'm sorry to not being able to answer with a concrete solution.

    Regards.

  • User Avatar
    0
    roberto.fiocchi created

    Hi,

    Thanks for the help anyway. One last question regarding the logout: How can i redirect a user to the homepage after logout rather then the "You have been logged out" page?

  • User Avatar
    0
    EngincanV created
    Support Team .NET Developer

    How can i redirect a user to the homepage after logout rather then the "You have been logged out" page?

    There should be an OpenIddictDataSeedContributor class under your domain project, you should open it and update the postLogoutRedirectUri:

                    // postLogoutRedirectUri: $"{blazorRootUrl}/authentication/logout-callback",
                    postLogoutRedirectUri: $"{blazorRootUrl}",
    

    Then, run the dbmigrator project to update your database. (since you already have a database, this change will not be applied, so you can manually update in database for now - or delete the OpenIddictApplication table records and run the dbmigrator)

  • User Avatar
    0
    roberto.fiocchi created

    Hi,

    I have done as you explained but when i press the logout button now it gives me the following error:

    error:invalid_request
    error_description:The specified 'post_logout_redirect_uri' is invalid.
    error_uri:https://documentation.openiddict.com/errors/ID2052
    

    It looks like in the url 'post_logout_redirect_uri' is still the old PostLoginRedirectUrl. How can i fix this?

  • User Avatar
    0
    EngincanV created
    Support Team .NET Developer

    Hi,

    I have done as you explained but when i press the logout button now it gives me the following error:

    error:invalid_request 
    error_description:The specified 'post_logout_redirect_uri' is invalid. 
    error_uri:https://documentation.openiddict.com/errors/ID2052 
    

    It looks like in the url 'post_logout_redirect_uri' is still the old PostLoginRedirectUrl. How can i fix this?

    You should also configure the OpenIddictServerBuilder in the *HttpApi.Host module (add the following code in your preconfigureservices method):

            PreConfigure<OpenIddictServerBuilder>(serverBuilder =>
            {
                serverBuilder.SetLogoutEndpointUris("<your-blazor-root-url>");
            });
    
  • User Avatar
    0
    roberto.fiocchi created

    Hi,

            PreConfigure<OpenIddictServerBuilder>(serverBuilder =>
            {
                serverBuilder.SetLogoutEndpointUris("<your-blazor-root-url>");
            });
    

    Seems to change the "Logout Url" (the url you go to when logging out) rather then "Post Logout Url" (the url you go to after having logged out).

  • User Avatar
    0
    EngincanV created
    Support Team .NET Developer

    Hi,

            PreConfigure<OpenIddictServerBuilder>(serverBuilder => 
            { 
                serverBuilder.SetLogoutEndpointUris("<your-blazor-root-url>"); 
            }); 
    

    Seems to change the "Logout Url" (the url you go to when logging out) rather then "Post Logout Url" (the url you go to after having logged out).

    Hi sorry, you are right. After the change you made in the OpenIddictDataSeedContributor, the only thing you need to do is to open the *BlazorModule class and make the following change:

            builder.Services.AddOidcAuthentication(options =>
            {
                builder.Configuration.Bind("AuthServer", options.ProviderOptions);
                options.UserOptions.NameClaim = OpenIddictConstants.Claims.Name;
                options.UserOptions.RoleClaim = OpenIddictConstants.Claims.Role;
    
                options.ProviderOptions.DefaultScopes.Add("AbpSolution5");
                options.ProviderOptions.DefaultScopes.Add("roles");
                options.ProviderOptions.DefaultScopes.Add("email");
                options.ProviderOptions.DefaultScopes.Add("phone");
                
                //add this line
                options.ProviderOptions.PostLogoutRedirectUri = "https://localhost:44353";
            });
    
Made with ❤️ on ABP v9.2.0-preview. Updated on February 13, 2025, 10:35