Reputation: 55
I have an issue with an ASP.NET C# API application.
It uses the AuthApiAttribute
class to check authorization, using 2 HTTP header to authenticate the query.
Once I have validated the credentials, I put some configuration linked to those credentials in a class with static attributes. That class is named ApiKeyConfig
. That parts works correctly.
My problem is when the ApiController
handles the response, the value of the attributes of ApiKeyConfig
are the values of the previous API call.
So if I call the API 4 time with userA, userB, userC and userA again, the result will be:
I was expecting the static values of the ApiKeyConfig
class not to survive from one query to another. I thought it would be static for the query API call only.
And from that behaviour, I suppose that the AuthApiAttribute
class call is done AFTER the controller method has executed ?
In my controller, I have defined [AuthApi]
above my public class CustomerController : ApiController
.
So what would be the best way to pass to my controller configuration that are specific to the API-key for the current call ?
Also, is there a way to prevent values to be kept from API call to API call ? Like in this case, what would I do to make sure ApiKeyConfig don't have the value of the previous request?
Edit:
My AuthApiAttribute
class:
public class AuthApiAttribute : Attribute, IAuthorizationFilter
{
public bool AllowMultiple => true;
public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
// I have the logic to check if user is valid
// [...]
List<ApiKey> keys; // Is assigned the valid API keys, skip that code below to avoid long comment
// I have some logic here to stock the valid keys in "keys"
// [...]
foreach (ApiKey apikey in keys)
{
if (key == apikey.key && auth == apikey.auth)
{
// FIXME: Would need to do somehting here to assign that key to something for me to be able to use that value once I'm in the controller's method
return response;
}
}
response.Result.StatusCode = System.Net.HttpStatusCode.Forbidden;
response.Result.Content = new StringContent("Access forbidden. Make sure your credentials are valid.");
return response;
}
}
The class ApiKeyConfig
is just a class with attributes representing the settings of the API key in use (somewhat like a user's profile)
Here, an example of a Controller in which I want to refer to the ApiKey for the current request.
[AuthApi]
public class CustomerController : ApiController
{
public Models.Response Get(string id)
{
// FIXME: Here, I want to access the value of ApiKey for the current session.
try
{
// I have some logic here to get the Customer requested
// [...]
return new Models.Response
{
Status = "Success",
Data = Customer
};
}
catch (Exception e)
{
return new Models.Response
{
Status = "Error",
Message = e.Message,
Stack = e.StackTrace
};
}
}
}
Solution:
Based on Athanasios Kataras answer, in AuthApiAttribute:
actionContext.ControllerContext.Configuration.Properties.TryAdd("apikey", apikey);
And then, in my Controller's Method accessing this value with:
Configuration.Properties.TryGetValue("apikey", out object config);
ApiKeyConfig keyConfig = (ApiKeyConfig)config;
if (keyConfig.value.Equals(""))
{
// Handle session undefined
}
Upvotes: 1
Views: 879
Reputation: 26382
You should not use static variables for these types of communication.
When you have multiple concurrent users, the static variable might change in your authorization, before the request is handled by the controller. This will lead to bugs that can't be easily identified.
Maybe you could use something like this to share data between filters and controllers. WebApi: how to pass state from filter to controller?
Also make sure that you extend the https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api authorization attribute for your authorization action, as this will certainly run before your controller.
Upvotes: 1