2

I have an ASP.NET Core 6.0 project and I use 2 authentication schemes.

One of the authencation schemes is, as default "JwtBearerDefaults.AuthenticationScheme"

and this works only for Role-based auth.

another one is "Custom"

"Custom" is used only for Policy-based auth.

.AddAuthentication(options =>
{
   options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
   options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
   options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
   .....
}
.AddJwtBearer("Custom", options =>
{
    .....
});

And after that I added some scopes to "Custom" policy.

I would like to reach the controller with;

[Authorize(AuthenticationSchemes ="Custom",Policy = "RandomPolicyName")]

OR

[Authorize(Roles="User")]

I know I cannot use both on the same controller, it cannot work because it has to pass both authorize attributes. So how can I do that ??

6
  • Hi @serhatyt, Have you tried [Authorize(Policy = "RandomPolicyName", Roles = "User")]? How do you implements policy based? The common way should be like this answer. Pls share more code for how do you implements jwt. Commented Oct 27, 2022 at 8:35
  • [Authorize(Policy = "RandomPolicyName", Roles = "User")] is not useful for my question. I would like to use Authorize for both "Custom" scheme and "JwtBearerDefaults.AuthenticationScheme" seperately. And the controller will accept the request if one of them passes not both of them. Commented Oct 27, 2022 at 8:46
  • So how do you implements the two authorization? Pls share more detailed code. Commented Oct 27, 2022 at 8:53
  • When you use - [Authorize(AuthenticationScheme="JwtBearerDefaults.AuthenticationScheme",Roles = "RoleName")] and - [Authorize(AuthenticationScheme="Custom",Policy="PolicyName")] together on a controller. It has to pass both Authorize attributes. But I would like it to pass if one of them is accepted, not both of them... Commented Oct 27, 2022 at 10:38
  • @serhatyt did you solve this? I'm trying to do something similar with AzureAD auth (roles) and IdentityServer (policy). My app is configured to use either for authentication and I have [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme + ", AzureAdBearer")] at the top of my controller. This works but the issue is how to allow either auth method access to a method that requires the admin role/policy (depending on auth type) Commented Aug 15, 2023 at 6:18

1 Answer 1

2

I solved this. This works for me, if you see any problem or have any other idea, then share with us :)

  • Authorize attribute

    public class AuthorizeMultiplePolicyAttribute : TypeFilterAttribute
    {
       public AuthorizeMultiplePolicyAttribute(string policies, bool IsAll) : base(typeof(AuthorizeMultiplePolicyFilter))
       {
           Arguments = new object[] { policies, IsAll };
       }
    }
    
  • Policy Filter

    public class AuthorizeMultiplePolicyFilter : IAsyncAuthorizationFilter
    {
        private readonly IAuthorizationService _authorization;
        public string _policies { get; private set; }
        public bool _isAll { get; set; }
        public AuthorizeMultiplePolicyFilter(string policies, bool IsAll, IAuthorizationService authorization)
        {
            _policies = policies;
            _authorization = authorization;
            _isAll = IsAll;
        }
    
        public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            var policys = _policies.Split(";").ToList();
            if (_isAll)
            {
                foreach (var policy in policys)
                {
                    var authorized = await _authorization.AuthorizeAsync(context.HttpContext.User, policy);
                    if (!authorized.Succeeded)
                    {
                        context.Result = new ForbidResult();
                        return;
                    }
                }
            }
            else
            {
                foreach (var policy in policys)
                {
                    var authorized = await _authorization.AuthorizeAsync(context.HttpContext.User, policy);
                    if (authorized.Succeeded)
                    {
                        return;
                    }
                }
                context.Result = new ForbidResult();
                return;
            }
        }
    }
    
  • Adding policies

    services.AddAuthorization(options =>
    {
    
        options.AddPolicy("CatalogReadOrWrite", policy =>
        {
              policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
              policy.RequireAuthenticatedUser();
              policy.RequireAssertion(context => context.User.HasClaim(c =>
                  (c.Type == "scope" && (c.Value == "catalog_writepermission" || c.Value == "catalog_readpermission"))
              ));
        });
    
    
        options.AddPolicy("CatalogReadUser", policy =>
        {
              policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
              policy.RequireAuthenticatedUser();
              policy.RequireAssertion(context => context.User.HasClaim(c =>
                  (
                    ((c.Type == "role" || c.Type == ClaimTypes.Role || c.Type == "Roles") && (c.Value == "User.Admin" || c.Value == "User.Normal"))
                  )
              ));
          });
      });
    }
    
  • Controller part

  • false parameter means if one of policies passes, then authorize

      [AuthorizeMultiplePolicy("CatalogWrite;CatalogReadOrWrite", false)]
      public async Task<IActionResult> BlaBlaAsync([FromBody] BlaBla model)
      {
    
      }
    
  • true parameter means if all of policies passes, then authorize

      [AuthorizeMultiplePolicy("CatalogWrite;CatalogReadOrWrite", true)]
      public async Task<IActionResult> BlaBlaAsync([FromBody] BlaBla model)
      {
    
      }
    
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.