title: ASP.NET Core Windows Authentication and Application Roles
body: <p>I'm trying to create a fairly simple intranet application that will use Active Directory for authentication, and will use the AspNetRoles table to check if the user is in a certain application role. This app is just an in-house lottery where some users can create events/contests that other users can then submit an entry to the contest. I'm thinking of starting out with 2 basic roles:</p>
  
  <ul>
  <li>Administrator - Can perform CRUD operations on "Event" or
  "Contest" entities</li>
  <li>Contestant - Can perform GET operations on
  "Contest" entities, and can create new "Entry" entities.</li>
  </ul>
  
  <p>Here's where I'm stuck: I've got Windows Authentication working in the sense that from a controller, I can do a <code>User.Identity.Name</code> and see my domain login name. Furthermore, I can verify that an account belongs to a domain group by doing <code>User.IsInRole("Domain Users")</code>. If I want to avoid creating new AD groups for each role in my application (let's say design changes down the road require additional roles), how can I use Authorization on controllers to check against Application Roles?</p>
  
  <p>Here's an example controller I want to use:</p>
  
  <pre class="lang-cs prettyprint-override"><code>[Route("api/[controller]")]
  [Authorize(Roles = "Contestant")]
  public class EventTypesController : Controller
  {
      private IRaffleRepository _repository;
      private ILogger&lt;EventTypesController&gt; _logger;
  
      public EventTypesController(IRaffleRepository repository, ILogger&lt;EventTypesController&gt; logger)
      {
          _repository = repository;
          _logger = logger;
      }
  
      [HttpGet("")]
      public IActionResult Get()
      {
          try
          {
              var results = _repository.GetAllEventTypes();
              return Ok(Mapper.Map&lt;IEnumerable&lt;EventTypeViewModel&gt;&gt;(results));
          }
          catch (Exception ex)
          {
              _logger.LogError($"Failed to get all event types: {ex}");
              return BadRequest("Error occurred");
          }
      }
  }
  </code></pre>
  
  <p>In my Startup.cs, in ConfigureServices, I'm wiring up Identity as follows:</p>
  
  <pre class="lang-cs prettyprint-override"><code>services.AddIdentity&lt;RaffleUser, ApplicationRole&gt;()
              .AddEntityFrameworkStores&lt;RaffleContext&gt;();
  </code></pre>
  
  <p>My RaffleUser class is really just the default implementation of IdentityUser:</p>
  
  <pre class="lang-cs prettyprint-override"><code>public class RaffleUser : IdentityUser
  {
  
  }
  </code></pre>
  
  <p>My ApplicationRole class is also just the default implementation of IdentityRole. I also tried seeding some data in a seed class:</p>
  
  <pre class="lang-cs prettyprint-override"><code>if (!await _roleManager.RoleExistsAsync("Administrator"))
  {
      var adminRole = new ApplicationRole()
      {
          Name = "Administrator"
      };
      await _roleManager.CreateAsync(adminRole);
      await _context.SaveChangesAsync();
  }
  
  if (await _userManager.FindByNameAsync("jmoor") == null)
  {
      using (var context = new PrincipalContext(ContextType.Domain))
      {
          var principal = UserPrincipal.FindByIdentity(context, "DOMAIN\\jmoor");
          if (principal != null)
          {
              var user = new RaffleUser()
              {
                  Email = principal.EmailAddress,
                  UserName = principal.SamAccountName
              };
  
              await _userManager.CreateAsync(user);
              await _context.SaveChangesAsync();
  
              var adminRole = await _roleManager.FindByNameAsync("Administrator");
              if (adminRole != null)
              {
                  await _userManager.AddToRoleAsync(user, adminRole.Name);
                  await _context.SaveChangesAsync();
              }
          }
      }
  }
  </code></pre>
  
  <p>The data makes it to the tables, but it just seems like at the controller level, I need to convert the authenticated user to an IdentityUser. Do I need some middleware class to do this for me? Would that be the best way to make authorization reusable on all controllers?</p>