locked
Google Authentication - How to grant new users access and roles before they register? RRS feed

  • Question

  • User1809093284 posted

     

    Hi

    I have successfully created a standard Asp.Net MVC Core web application.

    I have managed to setup google authentication and can authenticate via existing google accounts.

    My question revolves around adding new users in advance, how can I for example add 10 users (provided they give me their gmail email addresses) and then assign them to some roles - before they log on?

    I do not want them to each first have to log on and thereafter assign roles to them individually one at a time only after they individually logged on?

    Saturday, March 9, 2019 2:28 PM

Answers

  • User1809093284 posted

    I eventually ended up using an action filter controller, which I can simply add to my other controllers by decorating them with [AuthenticateActionFilter] just above the class names:

    Here is my working code for my AuthenticateActionFilter class which works perfectly for my use case :)

         public class AuthenticateActionFilter : ActionFilterAttribute
    
         {
              public override void OnActionExecuting(ActionExecutingContext filterContext)
              {
                   string userName = filterContext.HttpContext.User.Identity.Name;
    
                   CustomDbContext customDb = filterContext.HttpContext.RequestServices.GetService<CustomDbContext>();
                   ApplicationDbContext appDb = filterContext.HttpContext.RequestServices.GetService<ApplicationDbContext>();
    
                   customDb.Database.ExecuteSqlCommand("PRAGMA journal_mode=WAL");
                   appDb.Database.ExecuteSqlCommand("PRAGMA journal_mode=WAL");
                   
                   //obtain possible roles to be mapped
                   List<AspNetUserRolesPrePopulate> roles = (from x in customDb.AspNetUserRolesPrePopulate where x.UserName.Equals(userName) select x).ToList();
    
                   try
                   {
                        if (roles.Count > 0)
                        {
                             IdentityUser user= null;
                             List<IdentityUserRole<string>> existingRoles = null;
                             List<IdentityRole> allRoles = null;
    
                             user = appDb.Users.FirstOrDefault(x => x.UserName.Equals(userName));
                             existingRoles = appDb.UserRoles.Where(x => x.UserId.Equals(user.Id)).ToList();
                             allRoles = appDb.Roles.ToList();
    
                             foreach(AspNetUserRolesPrePopulate item in roles)
                             {
                                  //does the user already have access to this role
                                  //if not, add the role and link the user to this role
                                  IdentityRole role = allRoles.FirstOrDefault(x => x.Name.Equals(item.RoleName));
                                  
                                  if (role == null)
                                  {
                                       //first create the new role - if it does not already exist ...
                                       role = new IdentityRole();
                                       role.Name = item.RoleName;
                                       role.NormalizedName = item.RoleName;
    
                                       appDb.Add(role);
                                       appDb.SaveChanges();
                                  }
    
                                  IdentityUserRole<string> userRole = existingRoles.FirstOrDefault(x => x.RoleId.Equals(role.Id));
    
                                  if (role != null && userRole == null)
                                  {
                                       IdentityUserRole<string> newRole = new IdentityUserRole<string>();
                                       newRole.UserId = user.Id;
                                       newRole.RoleId = role.Id;
                                       appDb.Add(newRole);
                                       appDb.SaveChanges();
                                  }
                                  customDb.Remove(item); 
                                  customDb.SaveChanges();                              
                             }
                        }                         
                   }
                   catch(Exception ex)
                   {
    
                        //Log the exception in the local SQLite database
                   }
    
              }
    
              public override void OnActionExecuted(ActionExecutedContext filterContext)
              {
                   //Log("OnActionExecuted", filterContext.RouteData);      
              }
    
         }
    
    }

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, March 13, 2019 6:58 PM

All replies

  • User475983607 posted

     

    Hi

    I have successfully created a standard Asp.Net MVC Core web application.

    I have managed to setup google authentication and can authenticate via existing google accounts.

    My question revolves around adding new users in advance, how can I for example add 10 users (provided they give me their gmail email addresses) and then assign them to some roles - before they log on?

    I do not want them to each first have to log on and thereafter assign roles to them individually one at a time only after they individually logged on?

    Craft a table that has an email and role column.  Lookup the user's email grab the role when the user logs in.  

    Saturday, March 9, 2019 2:42 PM
  • User1809093284 posted

    Aha, I see, where would be the best place to intercept the very first login?

    In a traditional (non asp.net core) web app i used to have access to pre-created controller methods for login / out etc. but i see none of these in asp.net core?

    Saturday, March 9, 2019 2:58 PM
  • User475983607 posted

    iwcoetzer

    Aha, I see, where would be the best place to intercept the very first login?

    There's no such thing as a "very first login" until you define one.  There's an AspNetUserLogins table that track external logins and you can use that to determine if the user logged in using Google's Auth store.  

    Otherwise delete or logically delete the custom email/role record once you've assigned the role.

    In a traditional (non asp.net core) web app i used to have access to pre-created controller methods for login / out etc. but i see none of these in asp.net core?

    Not following... are you referring to Visual Studio project templates?  If so, there are ASP.NET Core Identity templates.

    Saturday, March 9, 2019 3:06 PM
  • User1809093284 posted

    Oh dear, now i am lost.

    What I mean is if a new user logs on via google authentication - where can i write the code to lookup the email address in my custom table and programatically assign the role?

    Saturday, March 9, 2019 3:24 PM
  • User475983607 posted

    Oh dear, now i am lost.

    What I mean is if a new user logs on via google authentication - where can i write the code to lookup the email address in my custom table and programatically assign the role?

    Oh yeah, the new ASP.NET Core Identity template exposes a Razor Class Library (RCL) not the source code.  You'll need to scaffold the code which is illustrated at the following link.

    https://docs.microsoft.com/en-us/aspnet/core/security/authentication/scaffold-identity?view=aspnetcore-2.2&tabs=visual-studio

     

    Saturday, March 9, 2019 3:44 PM
  • User1809093284 posted

    Hi

    Thank you, after following the instructions to scaffold my project it failed to build ...

    So I did the following:

    In the IdentityHostingStartup.cs I had to comment out this line of code: 

    services.AddDefaultIdentity<IdentityUser>().AddEntityFrameworkStores<DbContext>();

    Now I still cannot find an event handler to do what I need to do. As soon as a user logs on I want to run some custom but i do not know where I can do this, the only "C#" files I have in project are these:

    • IdentityHostingStartup.cs (runs only once)
    • HomeController.cs
    • Program.cs
    • Startup.cs

    and some others like HomeController.cs etc.

    Where can I find - or insert - a method that I can use to detect a post - logon event?

    Sunday, March 10, 2019 8:17 PM
  • User475983607 posted

    Hi

    Thank you, after following the instructions to scaffold my project it failed to build ...

    So I did the following:

    In the IdentityHostingStartup.cs I had to comment out this line of code: 

    services.AddDefaultIdentity<IdentityUser>().AddEntityFrameworkStores<DbContext>();

    Now I still cannot find an event handler to do what I need to do. As soon as a user logs on I want to run some custom but i do not know where I can do this, the only "C#" files I have in project are these:

    • IdentityHostingStartup.cs (runs only once)
    • HomeController.cs
    • Program.cs
    • Startup.cs

    and some others like HomeController.cs etc.

    Where can I find - or insert - a method that I can use to detect a post - logon event?

    You misunderstand how ASP.NET Core MVC works.  There are no events.  MVC uses Actions; the login POST Action.

    The default Identity template exposes the Identity API and UI through a DLL.  You must scaffold the Identity as explained in my previous thread if you want to change the default behavior.

    At this point it might be better for you to go through a few tutorials first so you understand how MVC works.

    Sunday, March 10, 2019 8:45 PM
  • User1724605321 posted

    Hi iwcoetzer,

    That seems you are using the ASP.NET Identity with external login (Google as IDP). That are two scenarios you can consider :

    1. Use Google's database to manage roles . Use Google's rest api to create users ,then assign roles . 
    2. Use own database(managed by ASP.NET Identity) to mange roles .

    In each scenario , you should have admin account which have user/role CRUD permissions to manage users and roles,

    Best Regards,

    Nan Yu 

    Monday, March 11, 2019 2:14 AM
  • User1809093284 posted

    Hi

    I am using 2. (own database managed by Asp.Net identity to manage roles) I am struggling however to find a place to write code post a logon action.

    Monday, March 11, 2019 6:03 AM
  • User1724605321 posted

    Hi iwcoetzer,

    You can config the roles In "ExternalLoginCallback" function of "AccountController" .

    ASP.NET Core 2.1 and later provides ASP.NET Core Identity as a Razor Class Library.  You can scaffold Identity in ASP.NET Core projects :

    https://docs.microsoft.com/en-us/aspnet/core/security/authentication/scaffold-identity?view=aspnetcore-2.2&tabs=visual-studio 

    And modify roles in `OnGetCallbackAsync` in xxx.Areas.Identity.Pages.Account.ExternalLogin.cshtml.cs file

    Best Regards,

    Nan Yu

    Tuesday, March 12, 2019 1:39 AM
  • User1809093284 posted

    I eventually ended up using an action filter controller, which I can simply add to my other controllers by decorating them with [AuthenticateActionFilter] just above the class names:

    Here is my working code for my AuthenticateActionFilter class which works perfectly for my use case :)

         public class AuthenticateActionFilter : ActionFilterAttribute
    
         {
              public override void OnActionExecuting(ActionExecutingContext filterContext)
              {
                   string userName = filterContext.HttpContext.User.Identity.Name;
    
                   CustomDbContext customDb = filterContext.HttpContext.RequestServices.GetService<CustomDbContext>();
                   ApplicationDbContext appDb = filterContext.HttpContext.RequestServices.GetService<ApplicationDbContext>();
    
                   customDb.Database.ExecuteSqlCommand("PRAGMA journal_mode=WAL");
                   appDb.Database.ExecuteSqlCommand("PRAGMA journal_mode=WAL");
                   
                   //obtain possible roles to be mapped
                   List<AspNetUserRolesPrePopulate> roles = (from x in customDb.AspNetUserRolesPrePopulate where x.UserName.Equals(userName) select x).ToList();
    
                   try
                   {
                        if (roles.Count > 0)
                        {
                             IdentityUser user= null;
                             List<IdentityUserRole<string>> existingRoles = null;
                             List<IdentityRole> allRoles = null;
    
                             user = appDb.Users.FirstOrDefault(x => x.UserName.Equals(userName));
                             existingRoles = appDb.UserRoles.Where(x => x.UserId.Equals(user.Id)).ToList();
                             allRoles = appDb.Roles.ToList();
    
                             foreach(AspNetUserRolesPrePopulate item in roles)
                             {
                                  //does the user already have access to this role
                                  //if not, add the role and link the user to this role
                                  IdentityRole role = allRoles.FirstOrDefault(x => x.Name.Equals(item.RoleName));
                                  
                                  if (role == null)
                                  {
                                       //first create the new role - if it does not already exist ...
                                       role = new IdentityRole();
                                       role.Name = item.RoleName;
                                       role.NormalizedName = item.RoleName;
    
                                       appDb.Add(role);
                                       appDb.SaveChanges();
                                  }
    
                                  IdentityUserRole<string> userRole = existingRoles.FirstOrDefault(x => x.RoleId.Equals(role.Id));
    
                                  if (role != null && userRole == null)
                                  {
                                       IdentityUserRole<string> newRole = new IdentityUserRole<string>();
                                       newRole.UserId = user.Id;
                                       newRole.RoleId = role.Id;
                                       appDb.Add(newRole);
                                       appDb.SaveChanges();
                                  }
                                  customDb.Remove(item); 
                                  customDb.SaveChanges();                              
                             }
                        }                         
                   }
                   catch(Exception ex)
                   {
    
                        //Log the exception in the local SQLite database
                   }
    
              }
    
              public override void OnActionExecuted(ActionExecutedContext filterContext)
              {
                   //Log("OnActionExecuted", filterContext.RouteData);      
              }
    
         }
    
    }

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, March 13, 2019 6:58 PM