Как добавить новую роль к существующему пользователю Microsoft Identity с контроллера MVC C# с помощью .net5

#c# #asp.net-mvc #azure-active-directory #.net-5 #microsoft-identity-web

Вопрос:

У меня есть приложение, в котором пользователь входит в систему с помощью Azure AD, сведения о котором затем сохраняются в базе данных. Теперь, если пользователь существует в базе данных, ему назначается роль. Эта роль добавляется в утверждения в файле startup.cs, и все в порядке. Однако, когда пользователь не хранится в базе данных и его необходимо создать. Вопрос в том, как мне тогда обновить файл cookie с ролью пользователя из UserController.cs

Это мой сервис конфигурации startup.cs()

 services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)  .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"));   services.AddControllersWithViews(options =gt;  {  var policy = new AuthorizationPolicyBuilder()  .RequireAuthenticatedUser()  .Build();  options.Filters.Add(new AuthorizeFilter(policy));  });  services.AddRazorPages()  .AddMicrosoftIdentityUI();  

Для пользователей, которые хранятся в базе данных, именно здесь роль добавляется в утверждения

 app.Use((context, next) =gt;  {  var userId = context.User.Identity.Name;  if (userId == null)  {  return next();  }   var userService = context.RequestServices.GetRequiredServicelt;IUserServicegt;();   if (!userService.DoesUserExist())  return next();   var roles = userService.GetUser().Role.Type;   if (!string.IsNullOrEmpty(roles))  {  context.User.Identities.FirstOrDefault().AddClaim(new Claim(ClaimTypes.Role, roles));  }   return next();  });  

Конечной точкой приложения является

 [HttpGet]  public IActionResult SignInRequest()  {  if (_userService.DoesUserExist())  {  return RedirectToAction(nameof(Index), "Bookings");  }   return RedirectToAction(nameof(Create));  }  

Для пользователей, которые в настоящее время не хранятся в базе данных, они отображаются в режиме создания, где им необходимо заполнить некоторую дополнительную информацию перед сохранением в базе данных. Этот Вид

 [HttpGet]  public IActionResult Create()  {  return View(GetNewUser());  }  

Get New User

 private UserVM GetNewUser()  {  return new UserVM()  {  Id = Guid.NewGuid(),  Firstname = _claimsPrincipal.Claims.FirstOrDefault(c =gt; c.Type == ClaimTypes.GivenName).Value,  Lastname = _claimsPrincipal.Claims.FirstOrDefault(c =gt; c.Type == ClaimTypes.Surname).Value,  Oid = _claimsPrincipal.Claims.FirstOrDefault(c =gt; c.Type == "http://schemas.microsoft.com/identity/claims/objectidentifier").Value,  Roles = _rolesService.GetRoles().Select(s =gt; new SelectListItem(s.Type, s.Id.ToString())).ToList(),  Locations = _locationService.GetAllLocations().Select(s =gt; new SelectListItem(s.Name, s.Id.ToString())).ToList(),  SelectedRole = UserRoles.EmployeeOnly  };  }  

Once the new user has completed the additional information. It is here I would like to update the identity and cookie with the roles claim WITHOUT needing the user to log out and log back in again.

 [HttpPost]  [ValidateAntiForgeryToken]  public IActionResult Create(UserVM user)  {  //here is where I would like to update the cookie and identity claims  return RedirectToAction(nameof(Index), "Bookings");  }  

This is my user model for my views

 public class UserVM {  public Guid Id { get; set; }  public string Firstname { get; set; }  public string Lastname { get; set; }  public int RoleId { get; set; }  public Guid? LocationId { get; set; }  public string Oid { get; set; }   public RolesVM Role { get; set; }   public LocationVM Location { get; set; }   [DisplayName("Name")]  public string FullName   {  get { return $"{Firstname} {Lastname}"; }  set { FullName = ""; }   }   public Listlt;SelectListItemgt; Locations { get; set; }  public Listlt;SelectListItemgt; Roles { get; set; }   public string SelectedLocation { get; set; }  public string SelectedRole { get; set; } }  

Также будет страница редактирования пользователя, на которой пользователь может изменить свои роли пользователем более высокого уровня. Существует четыре основные роли «Суперпользователь, Руководство, Администратор, Сотрудник». Всем новым пользователям будет предоставлена роль сотрудника до тех пор, пока она не будет изменена на более высокую.

Я попытался поискать в Google несколько убедительных примеров того, как это происходит, и мне указали в направлении UserManager и RoleManager, но на сегодняшний день я не смог заставить это работать в основном из-за отсутствия знаний об использовании любого из них раньше. Я видел, как некоторые используют IClaimTransformation, но опять же я не смог заставить это работать с единственным примером, который я нашел. Я был бы благодарен, если бы кто-нибудь мог помочь указать на необходимые шаги или указать мне на хороший пример, который я мог бы использовать в качестве ориентира.

Комментарии:

1. Используете ли вы app.UseCookieAuthentication(новые функции проверки подлинности cookiea()); или схему аутентификации по умолчанию в качестве файла cookie при запуске ?

2. Привет @kavyasaraboju-MT Я просто использую приложение схемы аутентификации по умолчанию. Использование аутентификации();

Ответ №1:

После долгих исследований я наткнулся на метод, который уже существует в ControllerBase.cs, называемый SignIn(принципал ClaimsPrincipal). Я взглянул на репозиторий github для MVC и обнаружил, что это будет спускаться в стек для вызова HttpContext.SignInAsync(). Это был метод, к которому я хотел подключиться, чтобы разрешить обновление файлов cookie, и я обновил требуемый метод в своем пользовательском контроллере следующим образом. Примечание: я изменил название метода

 public IActionResult Welcome(UserVM user)  {  if (!ModelState.IsValid)  {  user.Locations = GetLocations();  return View(user);  }   user.RoleId = Convert.ToInt32(user.SelectedRole);  user.LocationId = new Guid(user.SelectedLocation);   if (!_userService.CreateNewUser(_mapper.Maplt;Usersgt;(user)))  {  ModelState.AddModelError("", "Error creating user");  user.Locations = GetLocations();  return View(user);  }   var result = SignIn(_claimsPrincipal); //THIS WAS ALL THAT WAS NEEDED   return RedirectToAction(nameof(Index), "Bookings");  }