15

In my ASP.NET Core MVC app, I have a class that inherits from AuthorizeAttribute and implements IAuthorizationFilter.

namespace MyProject.Attributes
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
    public class AllowGroupsAttribute : AuthorizeAttribute, IAuthorizationFilter
    {
        private readonly List<PermissionGroups> groupList = null;
        public AllowGroupsAttribute(params PermissionGroups[] groups)
        {
            groupList = groups.ToList();
        }

        public void OnAuthorization(AuthorizationFilterContext context)
        {
            var executingUser = context.HttpContext.User;

            //If the user is not authenticated then prevent execution
            if (!executingUser.Identity.IsAuthenticated)
            {
                context.Result = new StatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
            }
        }
    }
}

This allows me to decorate a controller method with something like [AllowGroups(PermissionGroups.Admin, PermissionGroups.Level1]

What I plan to do, is retreive group names from appsettings.json based on the enum values listed and check that the user is a member of those groups.

My question is, what is the correct way to access the app settings from within my attribute class?

GarethPN
  • 432
  • 4
  • 11
  • configure settings on startup either via options or concrete object model and then resolve them through the `HttpContext.RequestServices` – Nkosi Oct 24 '18 at 12:27

2 Answers2

18

Configure settings on startup,

Either via options

services.Configure<MySettings>(Configuration.GetSection("groups"));

Or concrete object model

MySettings settings = Configuration.GetSection("groups").Get<MySettings>();
services.AddSingleton(settings);

And then resolve them through the HttpContext.RequestServices within the filter

//...

IServiceProvider services = context.HttpContext.RequestServices;

MySettings settings = services.GetService<MySettings>();
//-- OR --
//MySettings settings = services.GetService<IOptions<MySettings>>().Value;

//...

while a more service locator approach, it should allow for access to the desired configuration.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • 1
    Thank you. I think I am a bit closer to getting this implemented now, I have implemented a class with a dictionary to pull the section from settings, no errors there. But I have a build error on the line `var settings = services.GetService();`. The error reads _CS0308 The non-generic method 'IServiceProvider.GetService(Type)' cannot be used with type arguments_ – GarethPN Oct 24 '18 at 13:32
  • 2
    @GarethPN `GetSrvice` is an extension method. You are most likely missing a `using` name space for dependency injection. – Nkosi Oct 24 '18 at 13:36
  • 11
    Ah ha! I added `using Microsoft.Extensions.DependencyInjection;` to get access to the generic method which resolved my error. Thank you for your help :) – GarethPN Oct 24 '18 at 13:37
-2

I had the same problem and so you solve it

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class AllowGroupsAttribute : AuthorizeAttribute, IAuthorizationFilter
{
    IConfigurationBuilder builder = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);

            IConfigurationRoot configuration = builder.Build();
            var user = configuration.GetSection("AppConfig").GetSection("user").Value;
            var pass = configuration.GetSection("AppConfig").GetSection("pass").Value;

..........

}

in appsettings.json

"AppConfig": {
    "user": "hola",
    "pass": "mundo"
  },