Search code examples
asp.net-core-3.1asp.net-core-middlewaremicrosoft-identity-web

Capture Events From Microsoft.Identity.Web Login/Logout


I am using Microsoft's Authentication/Authorization platform to allow User Sign-ins from Azure AD. I would like to log these events into a database. Issue is, since this type of authentication leverages middleware I am not sure how to inject code to trigger a log event.

Please let me know if there exists documentation I haven't yet found and/or how to write up a custom injection to log these events.

Thanks!


Solution

  • I solved my own problem. For any potential usefulness to anyone else in the future I will add what I did below..

    I set up my database according to this documentation: https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/adding-model?view=aspnetcore-5.0&tabs=visual-studio

    I created this Middleware Class

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Identity.Web;
    using Application.Models;
    using Application.Data;
    
    namespace Application.Middleware
    {
        // You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
        public class EventLogCaptureMiddleware
        {
            private readonly RequestDelegate _next;
            private readonly EventLogContext _context;
    
            public EventLogCaptureMiddleware(RequestDelegate next, EventLogContext context)
            {
                _next = next;
                _context = context;
            }
    
            public Task Invoke(HttpContext httpContext)
            {
                var eventLogModel = new EventLogViewModel
                {
                    Timestamp = DateTime.Now,
                    Type = "TEST",
                    Method = httpContext.Request.Method,
                    Upn = httpContext.User.Identity.Name,
                    Resource = $"{httpContext.Request.Scheme}://{httpContext.Request.Host}{httpContext.Request.Path}"
                };
                _context.Add(eventLogModel);
                var tasks = new Task[] { _context.SaveChangesAsync() };
    
                Task.WaitAll(tasks);
    
                return _next(httpContext);
            }
        }
    
        // Extension method used to add the middleware to the HTTP request pipeline.
        public static class EventLogCaptureMiddlewareExtensions
        {
            public static IApplicationBuilder UseEventLogCaptureMiddleware(this IApplicationBuilder builder)
            {
                return builder.UseMiddleware<EventLogCaptureMiddleware>();
            }
        }
    }
    

    And injected into Startup.cs likeso:

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                    //Production Exception Handler ex: API connection failed will trigger exception routed to /Home/Error
                    app.UseExceptionHandler("/Home/Error");
                    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                    app.UseHsts();
                }
    
                //Handles User Error: 401, 403, 404, etc. Errors caught must land Application side. Errors occured in API with return 500 and be routed via Exception Handler
                app.UseStatusCodePagesWithReExecute("/Home/Error", "?status={0}");
    
                app.UseHttpsRedirection();
                app.UseStaticFiles();
                app.UseCookiePolicy();
    
                app.UseRouting();
    
                //Must include Authentication/Authorization under routing
                app.UseAuthentication();
                app.UseAuthorization();
    
                app.UseEventLogCaptureMiddleware();
    
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllerRoute(
                        name: "default",
                        pattern: "{controller=Home}/{action=Index}/{id?}");
                    endpoints.MapRazorPages();
                });
            }