0
When studying the functionality of the "Web API Pipeline . NET Faramework", I came across the property "Allowmultiple", brought by inheritance of the abstract class "Ifilter".
Microsoft documentation informs that it is a boolean property that "obtains or defines a value indicating whether more than one instance of the specified attribute can be specified for a single program element".
However, either I did not understand the concept, or I did not understand the use. Even if I set the value of this property to true (true), I cannot use more than one instance of the filter in the same program element.
Below is the implementation of my filter code:
public class BasicAuthenticationFilter : Attribute, IAuthenticationFilter
{
public bool AllowMultiple { get { return true; } }
public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
var authorization = context.Request.Headers.Authorization;
if (authorization != null &&
string.Equals(authorization.Scheme, "Basic", StringComparison.OrdinalIgnoreCase) &&
!string.IsNullOrEmpty(authorization.Parameter))
{
if (ExtractUserNameAndPassword(authorization.Parameter, out string userName, out string password) &&
userName == "userName" && password == "123qwe")
{
var identity = new GenericIdentity(userName, "Basic");
context.Principal = new GenericPrincipal(identity, null);
}
else
{
context.ErrorResult = new AuthenticationFailureResult("Invalid username or password", context.Request);
}
}
else
{
context.ErrorResult = new AuthenticationFailureResult("Missing auth", context.Request);
}
return Task.FromResult(0);
}
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
var host = context.Request.RequestUri.DnsSafeHost;
context.Result = new AddChallengeOnUnauthorizedResult(new AuthenticationHeaderValue("Basic", "realm=\"" + host + "\""), context.Result);
return Task.CompletedTask;
}
public class AddChallengeOnUnauthorizedResult : IHttpActionResult
{
private readonly AuthenticationHeaderValue _challenge;
private readonly IHttpActionResult _innerResult;
public AddChallengeOnUnauthorizedResult(AuthenticationHeaderValue challenge, IHttpActionResult innerResult)
{
_challenge = challenge;
_innerResult = innerResult;
}
public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = await _innerResult.ExecuteAsync(cancellationToken);
if (response.StatusCode == HttpStatusCode.Unauthorized && response.Headers.WwwAuthenticate.All(h => h.Scheme != _challenge.Scheme))
response.Headers.WwwAuthenticate.Add(_challenge);
return response;
}
}
private bool ExtractUserNameAndPassword(string authorizationParameter, out string userName, out string password)
{
userName = null;
password = null;
byte[] credentialBytes;
try
{
credentialBytes = Convert.FromBase64String(authorizationParameter);
}
catch (FormatException)
{
return false;
}
var encoding = System.Text.Encoding.GetEncoding("ISO-8859-1");
var decodedCredentials = encoding.GetString(credentialBytes);
if (string.IsNullOrEmpty(decodedCredentials))
{
return false;
}
int colonIndex = decodedCredentials.IndexOf(':');
if (colonIndex == -1)
{
return false;
}
userName = decodedCredentials.Substring(0, colonIndex);
password = decodedCredentials.Substring(colonIndex + 1);
return true;
}
public class AuthenticationFailureResult : IHttpActionResult
{
public AuthenticationFailureResult(string reasonPhrase, HttpRequestMessage request)
{
ReasonPhrase = reasonPhrase;
Request = request;
}
public string ReasonPhrase { get; private set; }
public HttpRequestMessage Request { get; private set; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
return Task.FromResult(Execute());
}
private HttpResponseMessage Execute()
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
response.RequestMessage = Request;
response.ReasonPhrase = ReasonPhrase;
return response;
}
}
}
Using this class as attribute more than once in a single program element generates build error (Duplicate "Basicauthenticationfilter" attribute) in the second citation of the attribute :
[BasicAuthenticationFilter]
[BasicAuthenticationFilter]
public class StudioGhibliController : ApiController
{
public HttpClient HttpClient { get; set; }
public string ApiUrlPrefix { get; set; }
public HttpResponseMessage Response { get; set; }
public StudioGhibliController()
{...
What would then be the concept and correct use of this property? What is it really for?
Perfect. Concept and assimilated use. Thank you very much, master!
– Sérgio Piacenti