简体   繁体   中英

Enabling Windows and Basic Authentication for ASP.NET Web API 2 Application

I have an ASP.NET Web API 2 application that uses Windows Authentication for all the controllers. I have a need now for some controllers to use Basic Authentication.

I know it is not possible to enable both Anonymous and Windows Authentications, but is it possible to enable Windows Authentication for some controllers and Basic Authentication for some others?

UPDATE: Implemented a filter as shown on the article EdSF shared

Here is what I have so far:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class BasicAuthenticationFilter : AuthorizationFilterAttribute
{
    private bool _active = true;
    private const string ValidUsername = @"Test";
    private const string ValidPassword = @"T3st";

    public BasicAuthenticationFilter()
    {
    }

    public BasicAuthenticationFilter(bool active)
    {
        _active = active;
    }

    public override void OnAuthorization(HttpActionContext actionContext)
    {
        if (_active)
        {
            var identity = ParseAuthorizationHeader(actionContext);
            if (identity == null)
            {
                Challenge(actionContext);
                return;
            }


            if (!OnAuthorizeUser(identity.Name, identity.Password, actionContext))
            {
                Challenge(actionContext);
                return;
            }

            var principal = new GenericPrincipal(identity, null);

            Thread.CurrentPrincipal = principal;

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

            base.OnAuthorization(actionContext);
        }
    }

    protected virtual bool OnAuthorizeUser(string username, string password, HttpActionContext actionContext)
    {
        if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password) ||
            !username.Equals(ValidUsername) || !password.Equals(ValidPassword))
        {
            return false;
        }

        return true;
    }

    protected virtual BasicAuthenticationIdentity ParseAuthorizationHeader(HttpActionContext actionContext)
    {
        string authHeader = null;
        var auth = actionContext.Request.Headers.Authorization;
        if (auth != null && auth.Scheme == "Basic")
        {
            authHeader = auth.Parameter;
        }

        if (string.IsNullOrEmpty(authHeader)) return null;

        authHeader = Encoding.Default.GetString(Convert.FromBase64String(authHeader));

        var tokens = authHeader.Split(':');
        if (tokens.Length < 2) return null;

        return new BasicAuthenticationIdentity(tokens[0], tokens[1]);
    }

    private void Challenge(HttpActionContext actionContext)
    {
        var host = actionContext.Request.RequestUri.DnsSafeHost;
        actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
        actionContext.Response.Headers.Add("WWW-Authenticate", string.Format("Basic realm=\"{0}\"", host));
    }
}

BasicAuthenticationIdentity Class:

public class BasicAuthenticationIdentity : GenericIdentity
{
    public BasicAuthenticationIdentity(string name, string password)
        : base(name, "Basic")
    {
        Password = password;
    }

    public string Password { get; set; }
}

Also, decorated my controller with the Basic Authentication Filter:

[BasicAuthenticationFilter]
[RoutePrefix("api/BasicAuth")]
public class BasicAuthController : ApiController
{
    //[BasicAuthenticationFilter]
    [HttpGet]
    public IHttpActionResult TestBasicAuth()
    {
        return Ok("success");
    }
}

When I make a call to api/BasicAuth from Fiddler I got back 401, but it only returns the following challenges:

WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM

At this point Fiddler tries it again but this time instead of passing Basic Authorization Scheme, it passes Negotiate. This one fails also.

Then, when Fiddler finally tries the third time, my filter actually gets the request, but since authorization scheme is Negotiate instead of Basic, my filter returns Unauthorized also.

Is there a way to force the controller to just use the BasicAuthenticationFilter?

Thanks in advance

You can - because BASIC AUTH credentials are sent in HTTP Headers (base64 encoded only). You don't have to "enable" anything at the application level and handle HTTP requests to your API endpoints "manually" (by inspecting headers).

eg Basic Auth Header: Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

See this example that creates an AuthorizationFilter that can be applied to Controller or Action , or even globally if needed...

Hth.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM