title: .Net Core Authorization with Customized Requirement/Handler
body: <p>I asked similar question before and with others help I made some progress, but still not sure what I did wrong or missed here.</p>
  
  <p>My application is kind of simple:
  Domain users get authenticated.
  Authenticated user(author) creates a request, save in database.
  Other authenticated users can view the request only.
  Author and admin users can edit/delete the request.</p>
  
  <p>This is one of the example I followed:
  <a href="https://stackoverflow.com/questions/53186143/different-api-functionality-for-different-roles/53201936#53201936">Different API functionality for different roles</a></p>
  
  <p>And the other one PoliciesAuthApp: <a href="https://github.com/aspnet/Docs/tree/master/aspnetcore/security/authorization/policies/samples/PoliciesAuthApp1" rel="nofollow noreferrer">https://github.com/aspnet/Docs/tree/master/aspnetcore/security/authorization/policies/samples/PoliciesAuthApp1</a>
  I am not sure how the PermissionHandler is used/registered/invoked in here.</p>
  
  <p>Here is my code:</p>
  
  <p><strong>Startup.cs</strong></p>
  
  <pre><code>//  Add Authentication
  //  Global filter
  services.AddMvc(config =&gt;
  {
      var policy = new AuthorizationPolicyBuilder()
                       .RequireAuthenticatedUser()
                       .RequireRole("Role - Domain Users")
                       .Build();
      config.Filters.Add(new AuthorizeFilter(policy));
  });
  
  
  //  Add Authorization Handlers
  services.AddAuthorization(options =&gt;
  {
      options.AddPolicy("EditPolicy", policy =&gt; policy.Requirements.Add(new EditRequirement()));
  });
  
  services.AddSingleton&lt;IAuthorizationHandler, PermissionHandler&gt;();
  </code></pre>
  
  <p><strong>EditRequirement.cs</strong></p>
  
  <pre><code>public class EditRequirement : IAuthorizationRequirement
  {
  }
  </code></pre>
  
  <p><strong>PermissionHandler.cs</strong></p>
  
  <pre><code>public class PermissionHandler : IAuthorizationHandler
  {
  
      public Task HandleAsync(AuthorizationHandlerContext context)
      {
          var pendingRequirements = context.PendingRequirements.ToList();
  
          foreach (var requirement in pendingRequirements)
          {
              if (requirement is ReadRequirement)
              {
                  if (IsOwner(context.User, context.Resource) ||
                      IsAdmin(context.User, context.Resource))
                  {
                      context.Succeed(requirement);
                  }
              }
              else if (requirement is EditRequirement ||
                       requirement is DeleteRequirement)
              {
                  if (IsOwner(context.User, context.Resource) || IsAdmin(context.User, context.Resource))
                  {
                      context.Succeed(requirement);
                  }
              }
          }
          return Task.CompletedTask;
      }
  
      private bool IsAdmin(ClaimsPrincipal user, object resource)
      {
          if (user.IsInRole("Role - Administrator"))
          {
              return true;
          }
          return false;
      }
  
      private bool IsOwner(ClaimsPrincipal user, object resource)
      {
          if (resource is CreateRequestViewModel)
          {
              var ctx = (CreateRequestViewModel)resource;
  
              if (ctx.RequestEnteredBy.Equals(user.Identity.Name))
              {
                  return true;
              }
          }
          else if (resource is AuthorizationFilterContext)
          {
              var afc = (AuthorizationFilterContext)resource;
  
              //  This is not right, but I don't know how to deal with AuthorizationFilterContext 
              //  type passed into resource parameter when I click Edit button trying to edit the request
              if (afc.HttpContext.User.Identity.Name.Equals(user.Identity.Name))
              {
                  return true;
              }
          }
          else if (resource is Request)
          {
              var r = (Request)resource;
  
              if (r.RequestEnteredBy.Equals(user.Identity.Name))
              {
                  return true;
              }
          }
  
  
          return false;
      }
  
      private bool IsSponsor(ClaimsPrincipal user, object resource)
      {
          // Code omitted for brevity
  
          return true;
      }
  }
  </code></pre>
  
  <p><strong>RequestsController.cs</strong></p>
  
  <pre><code>private IAuthorizationService _authorizationService;
  
  public RequestsController(ApplicationModelContext context, IAuthorizationService authorizationService)
  {
      _context = context; 
      _authorizationService = authorizationService;
  }
  
  [Authorize(Policy = "EditPolicy")]
  public async Task&lt;IActionResult&gt; Edit(int? id)
  {
      if (id == null)
      {
          return NotFound();
      }
  
      CreateRequestViewModel crvm = new CreateRequestViewModel();
  
      var request = await _context.Request
                  .SingleOrDefaultAsync(m =&gt; m.RequestId == id);
  
      if (request == null)
      {
          return NotFound();
      }
  
      var authorizationResult = await _authorizationService.AuthorizeAsync(User, request, "EditPolicy");
  
      if (authorizationResult.Succeeded)
      {   
          //  Load request contents and return to the view
  
          return View(crvm);
      }
  
      //  This needs to be changed to redirect to a message screen saying no permission
      return RedirectToAction("Details", new { id = request.RequestId });
  }
  </code></pre>
  
  <p>When I was debugging the application, I found that:</p>
  
  <ul>
  <li>The first time when the page loads requests from database, it passes
  a CreateRequestViewModel type object to the resource parameter of
  IsOwner method in PermissionHandler.</li>
  <li>After click Edit button of the request item on page, it passes
  AuthorizationFilterContext type</li>
  <li>Then goes inside the Edit action in ReuqestController, which sends a
  Request type(in _authorizationService.AuthorizeAsync).</li>
  </ul>
  
  <p>Not sure if I did something duplicated or completely mixed with different approaches.</p>
  
  <p>Any advise would be really appreciated.</p>