9
9
using System . Threading . Tasks ;
10
10
using DarkLoop . Azure . Functions . Authorization . Extensions ;
11
11
using DarkLoop . Azure . Functions . Authorization . Features ;
12
+ using DarkLoop . Azure . Functions . Authorization . Internal ;
12
13
using Microsoft . AspNetCore . Authorization ;
13
14
using Microsoft . Azure . Functions . Worker ;
14
15
using Microsoft . Azure . Functions . Worker . Middleware ;
@@ -39,9 +40,9 @@ public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next
39
40
return ;
40
41
}
41
42
42
- if ( ! _options . IsFunctionRegistered ( context . FunctionDefinition . Name ) )
43
+ if ( ! _options . IsFunctionRegistered ( context . FunctionDefinition . Name ) )
43
44
{
44
- RegisterHttpTriggerAuthorization ( context ) ;
45
+ await RegisterHttpTriggerAuthorizationAsync ( context ) ;
45
46
}
46
47
47
48
context . Features . Set < IFunctionsAuthorizationFeature > (
@@ -50,27 +51,45 @@ public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next
50
51
await next ( context ) ;
51
52
}
52
53
53
- private void RegisterHttpTriggerAuthorization ( FunctionContext context )
54
+ private async Task RegisterHttpTriggerAuthorizationAsync ( FunctionContext context )
54
55
{
55
- var functionName = context . FunctionDefinition . Name ;
56
- var declaringTypeName = context . FunctionDefinition . EntryPoint . LastIndexOf ( '.' ) switch
56
+ // Middleware can be hit concurrently, we need to ensure this functionality
57
+ // is thread-safe on a per function basis.
58
+ // Ensuring key is interned before entering monitor since key is compared as object
59
+ var monitorKey = string . Intern ( $ "famm:{ context . FunctionId } ") ;
60
+ await KeyedMonitor . EnterAsync ( monitorKey ) ;
61
+
62
+ try
57
63
{
58
- - 1 => string . Empty ,
59
- var index => context . FunctionDefinition . EntryPoint [ ..index ]
60
- } ;
64
+ if ( _options . IsFunctionRegistered ( context . FunctionDefinition . Name ) )
65
+ {
66
+ return ;
67
+ }
68
+
69
+ var functionName = context . FunctionDefinition . Name ;
70
+ var declaringTypeName = context . FunctionDefinition . EntryPoint . LastIndexOf ( '.' ) switch
71
+ {
72
+ - 1 => string . Empty ,
73
+ var index => context . FunctionDefinition . EntryPoint [ ..index ]
74
+ } ;
61
75
62
- var methodName = context . FunctionDefinition . EntryPoint [ ( declaringTypeName . Length + 1 ) ..] ;
63
- var assemblies = AppDomain . CurrentDomain . GetAssemblies ( ) ;
64
- var method = assemblies . Select ( a => a . GetType ( declaringTypeName , throwOnError : false ) )
65
- . FirstOrDefault ( t => t is not null ) ?
66
- . GetMethod ( methodName , BindingFlags . Public | BindingFlags . Instance | BindingFlags . Static ) ??
67
- throw new MethodAccessException (
68
- $ "Method instance for function '{ context . FunctionDefinition . Name } ' " +
69
- $ "cannot be found or cannot be accessed due to its protection level.") ;
76
+ var methodName = context . FunctionDefinition . EntryPoint [ ( declaringTypeName . Length + 1 ) ..] ;
77
+ var assemblies = AppDomain . CurrentDomain . GetAssemblies ( ) ;
78
+ var method = assemblies . Select ( a => a . GetType ( declaringTypeName , throwOnError : false ) )
79
+ . FirstOrDefault ( t => t is not null ) ?
80
+ . GetMethod ( methodName , BindingFlags . Public | BindingFlags . Instance | BindingFlags . Static ) ??
81
+ throw new MethodAccessException (
82
+ $ "Method instance for function '{ context . FunctionDefinition . Name } ' " +
83
+ $ "cannot be found or cannot be accessed due to its protection level.") ;
70
84
71
- var declaringType = method . DeclaringType ! ;
85
+ var declaringType = method . DeclaringType ! ;
72
86
73
- _options . RegisterFunctionAuthorizationAttributesMetadata < AuthorizeAttribute > ( functionName , declaringType , method ) ;
87
+ _options . RegisterFunctionAuthorizationAttributesMetadata < AuthorizeAttribute > ( functionName , declaringType , method ) ;
88
+ }
89
+ finally
90
+ {
91
+ KeyedMonitor . Exit ( monitorKey ) ;
92
+ }
74
93
}
75
94
}
76
95
}
0 commit comments