How to implement basic authentication in web API 2

2019-09-11 19:07发布

问题:

I am new to asp.net core and web API 2 and trying to implement basic authentication in web API like request headers contains the username and password and i will verify them. I have implemented the same thing in Web API using action filters. Now my question is that is it possible to implement basic authentication in web API 2? If possible then can I achieve it with action filters and how? What is the best way to authentication in Web API 2? Should i use middle ware?

回答1:

I'm not sure why you said ASP.Net Core and Web API 2. They are mutually exclusive; we don't normally use both in same project.

Now my question is that is it possible to implement basic authentication in web API 2? If possible then can I achieve it with action filters and how? What is the best way to authentication in Web API 2? Should i use middle ware?

In Web API 2, you can easily implement Basic Authentication using DelegatingHandler.

Here is the sample code -

IBasicSecurityService

public interface IBasicSecurityService
{
    bool SetPrincipal(string username, string password);
}

BasicSecurityService

public class BasicSecurityService : IBasicSecurityService
{
    public bool SetPrincipal(string username, string password)
    {
        // Get user from database
        var user = GetUser(username);
        IPrincipal principal = null;
        if (user == null || (principal = GetPrincipal(user)) == null)
        {
            // System could not validate user
            return false;
        }

        Thread.CurrentPrincipal = principal;
        if (HttpContext.Current != null)
        {
            HttpContext.Current.User = principal;
        }

        return true;
    }

    public virtual IPrincipal GetPrincipal(User user)
    {
        var identity = new GenericIdentity(user.Username, Constants.SchemeTypes.Basic);

        identity.AddClaim(new Claim(ClaimTypes.GivenName, user.Firstname));
        identity.AddClaim(new Claim(ClaimTypes.Surname, user.Lastname));
        // Get authroized roles and add them as Role Claim.
        identity.AddClaim(new Claim(ClaimTypes.Role, "Manager"));

        return new ClaimsPrincipal(identity);
    }
}

BasicAuthenticationMessageHandler

public class BasicAuthenticationMessageHandler : DelegatingHandler
{
    public const char AuthorizationHeaderSeparator = ':';
    private const int UsernameIndex = 0;
    private const int PasswordIndex = 1;
    private const int ExpectedCredentialCount = 2;

    private readonly IBasicSecurityService _basicSecurityService;

    public BasicAuthenticationMessageHandler(IBasicSecurityService basicSecurityService)
    {
        _basicSecurityService = basicSecurityService;
    }

    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        if (HttpContext.Current.User.Identity.IsAuthenticated)
        {
            // Already authenticated; passing on to next handler...
            return await base.SendAsync(request, cancellationToken);
        }

        if (!CanHandleAuthentication(request))
        {
            // Not a basic auth request; passing on to next handler...
            return await base.SendAsync(request, cancellationToken);
        }

        bool isAuthenticated;
        try
        {
            isAuthenticated = Authenticate(request);
        }
        catch (Exception e)
        {
            // Failure in auth processing
            return CreateUnauthorizedResponse();
        }

        if (isAuthenticated)
        {
            var response = await base.SendAsync(request, cancellationToken);
            return response;
        }

        return CreateUnauthorizedResponse();
    }

    public bool CanHandleAuthentication(HttpRequestMessage request)
    {
        return (request.Headers != null
                && request.Headers.Authorization != null
                && request.Headers.Authorization.Scheme.ToLowerInvariant() == Constants.SchemeTypes.Basic);
    }

    public bool Authenticate(HttpRequestMessage request)
    {
        // Attempting to authenticate...
        var authHeader = request.Headers.Authorization;
        if (authHeader == null)
        {
            return false;
        }

        var credentialParts = GetCredentialParts(authHeader);
        if (credentialParts.Length != ExpectedCredentialCount)
        {
            return false;
        }

        return _basicSecurityService.SetPrincipal(credentialParts[UsernameIndex], credentialParts[PasswordIndex]);
    }

    public string[] GetCredentialParts(AuthenticationHeaderValue authHeader)
    {
        var encodedCredentials = authHeader.Parameter;
        var credentialBytes = Convert.FromBase64String(encodedCredentials);
        var credentials = Encoding.ASCII.GetString(credentialBytes);
        var credentialParts = credentials.Split(AuthorizationHeaderSeparator);
        return credentialParts;
    }

    public HttpResponseMessage CreateUnauthorizedResponse()
    {
        var response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
        response.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue(Constants.SchemeTypes.Basic));
        return response;
    }
}

Credit: Page 121 of ASP.NET Web API 2: Building a REST Service from Start to Finish.