Comments (3)
It's not straightforward forward, but you could use reflection to get access to the attribute on the invoked function.
file static class FunctionContextExtensions
{
public static MethodInfo GetTargetFunctionMethod(this FunctionContext context)
{
var entryPoint = context.FunctionDefinition.EntryPoint;
var assemblyPath = context.FunctionDefinition.PathToAssembly;
var assembly = Assembly.LoadFrom(assemblyPath);
var typeName = entryPoint[..entryPoint.LastIndexOf('.')];
var type = assembly.GetType(typeName);
var methodName = entryPoint[(entryPoint.LastIndexOf('.') + 1)..];
var method = type?.GetMethod(methodName);
return method ?? throw new Exception("Could not get target function from the context");
}
}
from azure-functions-dotnet-worker.
We have a set of APIs that were recently introduced that may help here.
We'll flag this for review and provide more information when that is available.
from azure-functions-dotnet-worker.
@stevendarby, similar to @SeanFeldman's suggestion, i also use reflection. however, i do it differently. i highly recommend that you separate out the reflection code from the run-time execution of your function. you can also cache (or, in my case, load the results as a singleton in a container) and initialize the attribute analysis at app start time (or lazily on first function hit).
i use this technique to manage authentication (jwt
validation) and authorization (scope
validation).
public class FunctionAuthRules
{
private readonly HashSet<string> _anonymousFunctions = new(){"RenderSwaggerUI","RenderSwaggerDocument"};
private readonly Dictionary<string, string> _scopedFunctions = new();
public FunctionAuthRules() : this(GetAppDomainMethods())
{
}
protected FunctionAuthRules(IEnumerable<MethodInfo> methods)
{
foreach (var method in methods)
{
var functionName = method.GetCustomAttribute<FunctionAttribute>()?.Name;
if (functionName is null)
{
continue;
}
if (method.GetCustomAttribute<AllowAnonymousAccessAttribute>() is not null)
{
_anonymousFunctions.Add(functionName);
}
if (method.GetCustomAttribute<RequireScopeAttribute>() is { } scoped)
{
_scopedFunctions.Add(functionName, scoped.RequiredScope);
}
}
}
public bool AllowAnonymousAccess(FunctionContext context)
{
return _anonymousFunctions.Contains(context.FunctionDefinition.Name);
}
public string? RequiredScope(FunctionContext context)
{
var hasScope = _scopedFunctions.TryGetValue(context.FunctionDefinition.Name, out var scope);
return hasScope ? scope : null;
}
private static IEnumerable<MethodInfo> GetAppDomainMethods()
{
return AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(a => a.GetTypes())
.SelectMany(t => t.GetMethods());
}
}
here is the scope attribute:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class RequireScopeAttribute : Attribute
{
public string RequiredScope { get; }
public RequireScopeAttribute(string requiredScope)
{
RequiredScope = requiredScope;
}
}
then you can leverage your "rules" in a middleware:
public class JwtBearerAuthenticationMiddleware : IFunctionsWorkerMiddleware
{
private readonly IJwtValidationService _jwtValidationService;
private readonly FunctionAuthRules _rules;
private readonly ILogger _logger;
public JwtBearerAuthenticationMiddleware(IJwtValidationService jwtValidationService, FunctionAuthRules rules, ILogger logger)
{
_jwtValidationService = jwtValidationService;
_rules = rules;
_logger = logger;
}
public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
{
var requestData = await context.GetHttpRequestDataAsync();
if (requestData is null)
{
throw new InvalidOperationException("Unable to get request data");
}
if (_rules.AllowAnonymousAccess(context))
{
await next(context);
return;
}
if (!requestData.TryGetJwt(out var jwt))
{
context.GetInvocationResult().Value = requestData.CreateResponse(HttpStatusCode.Unauthorized);
_logger.Warning("Authorization header not found");
return;
}
var jwtValidationResponse = await _jwtValidationService.ValidateJwt(jwt!);
if (!jwtValidationResponse.IsValid)
{
context.GetInvocationResult().Value = requestData.CreateResponse(HttpStatusCode.Unauthorized);
_logger.Warning("Unauthorized: {Request_Uri}", requestData.Url);
return;
}
context.SetApiClaimsPrincipal(new ApiClaimsPrincipal(jwtValidationResponse.ToUserPrincipal()));
await next(context);
}
}
and
public class RequireScopeMiddleware : IFunctionsWorkerMiddleware
{
private readonly FunctionAuthRules _rules;
private readonly ILogger _logger;
public RequireScopeMiddleware(FunctionAuthRules rules, ILogger logger)
{
_rules = rules;
_logger = logger;
}
public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
{
var requestData = await context.GetHttpRequestDataAsync();
if (requestData is null)
{
throw new InvalidOperationException("Unable to get request data");
}
if (_rules.RequiredScope(context) is { } requiredScope)
{
var principal = context.GetApiClaimsPrincipal();
if (principal is null)
{
context.GetInvocationResult().Value = requestData.CreateResponse(HttpStatusCode.Unauthorized);
_logger.Warning("Unauthorized: {Request_Uri}", requestData.Url);
return;
}
if (!principal.HasScope(requiredScope))
{
context.GetInvocationResult().Value = requestData.CreateResponse(HttpStatusCode.Forbidden);
_logger
.ForContext(nameof(principal.ClientId), principal.ClientId)
.ForContext(nameof(principal.Scopes), principal.Scopes)
.ForContext("RequiredScope", requiredScope)
.Warning("Forbidden: {Request_Uri}", requestData.Url);
return;
}
}
await next(context);
}
}
from azure-functions-dotnet-worker.
Related Issues (20)
- Analyzer for multiple output bindings using IActionResult
- Upgrade to version 1.16.0 generates error CS0246 HOT 2
- Service bus message actions throwing Grpc.Core.RpcException when sending multiple requests HOT 2
- CreateCheckStatusResponse does not work when `HttpRequestMessage` is used (no built-in Function HTTP types)
- Multiple output bindings does not work with ASP.NET Core integration response objects HOT 1
- TimeZoneInfo.FindSystemTimeZoneById discrepancy in .Net 8 based Web API deployed as Web App on Linux HOT 3
- Is there a way to get the next scheduled occurence of an Azure Timer function? This issue seems to say that `TimerInfo` should have a schedule property, but I'm not seeing it in .NET 8.
- Logs sometimes going missing in isolated worker HOT 14
- ASP.NET Core integration HOT 1
- [ASP.NET Core Integration] Skip serialization of http response following function execution
- GeneratedFunctionMetadataProvider emitting binding data without "dataType" attribute
- .NET 8 HttpContext is null when it is not in .NET 6 HOT 11
- Worker.Extensions.CosmosDB is using old Azure.Identity package (v1.4) with vulnerabilities HOT 2
- [ServiceBusSessionMessageActions] Implement session management APIs
- InvalidOperationException when canceling request HOT 12
- Worker failing without raising error HOT 2
- AI logs are not flushed when process exits HOT 2
- Graceful cancellation period on function timeout HOT 4
- Exception when running ServiceBusTrigger with managed identity locally HOT 6
- ServiceBusTrigger ignoring the DefaultAzureCredentialOptions set in DefaultAzureCredentials HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from azure-functions-dotnet-worker.