Is there any way to know target method in a middleware of azure function isolated app

395 Views Asked by At

I have a .NET 6.0 isolated azure function app. I want to implement custom JWT token validation. I am following this blog and created Authentication middleware for validating tokens. However there is a piece of code which uses reflection to get target function information in the middleware. This blog is almost 2 years old now. Is there any better way to do it now? I wasn't able to find anything on my own.

Middleware class:

public class AuthenticationMiddleware : IFunctionsWorkerMiddleware
{
    private readonly JwtSecurityTokenHandler _tokenValidator;
    private readonly TokenValidationParameters _tokenValidationParameters;

    public AuthenticationMiddleware()
    {
        _tokenValidator = new JwtSecurityTokenHandler();
        _tokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = Environment.GetEnvironmentVariable("JWTIssuer"),
            ValidAudience = Environment.GetEnvironmentVariable("JWTAudience"),
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Environment.GetEnvironmentVariable("JWTSecretKey")))

        };
    }

    public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
    {
        var targetMethod = GetTargetFunctionMethod(context);
        var attributes = GetFunctionMethodAttribute<AuthorizeAttribute>(targetMethod);
        if (attributes != null && attributes.Count > 0)
        {
            //this section should be executed only if [Authorize] attribute is declared on Function
            //and will return 401-Unauthorized response code if token is invalid
            await next(context);
        }
        else
        {
            //anonymous access allowed
            await next(context);
        }
    }

    private static List<T> GetFunctionMethodAttribute<T>(MethodInfo targetMethod) where T : Attribute
    {
        var methodAttributes = targetMethod.GetCustomAttributes<T>();
        var classAttributes = targetMethod.DeclaringType.GetCustomAttributes<T>();
        return methodAttributes.Concat(classAttributes).ToList();
    }

    private static MethodInfo GetTargetFunctionMethod(FunctionContext context)
    {
        var assemblyPath = context.FunctionDefinition.PathToAssembly;
        var assembly = Assembly.LoadFrom(assemblyPath);
        var typeName = context.FunctionDefinition.EntryPoint.Substring(0, context.FunctionDefinition.EntryPoint.LastIndexOf('.'));
        var type = assembly.GetType(typeName);
        var methodName = context.FunctionDefinition.EntryPoint.Substring(context.FunctionDefinition.EntryPoint.LastIndexOf('.') + 1);
        var method = type.GetMethod(methodName);
        return method;
    }
}

Attribute class:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AuthorizeAttribute : Attribute
{
    public string[] UserRoles { get; set; } = Array.Empty<string>();
}

HttpTrigger functions:

    [Function("AllowAnonymous")]
    public static HttpResponseData AllowAnonymous([HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequestData req, FunctionContext context)
    {
        var response = req.CreateResponse(HttpStatusCode.OK);
        response.WriteString("AllowAnonymous succeeded");
        return response;
    }

    [Authorize]
    [Function("AllowAuthenticatedOnly")]
    public static HttpResponseData AllowAuthenticatedOnly([HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequestData req, FunctionContext context)
    {
        var response = req.CreateResponse(HttpStatusCode.OK);
        response.WriteString("AllowAuthenticatedOnly succeeded");
        return response;
    }

Program class:

public class Program
{
    public static void Main()
    {
        var host = new HostBuilder()
            .ConfigureFunctionsWorkerDefaults(builder =>
            {
                builder.UseMiddleware<AuthenticationMiddleware>();
            })
            .Build();

        host.Run();
    }
}

You can see that GetTargetFunctionMethod is being called to get target method information, which gets info using reflection.

0

There are 0 best solutions below