Basic authentication in ASP.NET MVC 5

What steps must be done to implement basic authentication in ASP.NET MVC 5?

I have read that OWIN does not support cookieless authentication, so is basic authentication generally possible?

Do I need a custom attribute here? I am not sure about how these attributes work.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

You can use this simple yet effective mechanism using a custom ActionFilter attribute:

public class BasicAuthenticationAttribute : ActionFilterAttribute
{
    public string BasicRealm { get; set; }
    protected string Username { get; set; }
    protected string Password { get; set; }

    public BasicAuthenticationAttribute(string username, string password)
    {
        this.Username = username;
        this.Password = password;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var req = filterContext.HttpContext.Request;
        var auth = req.Headers["Authorization"];
        if (!String.IsNullOrEmpty(auth))
        {
            var cred = System.Text.ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(auth.Substring(6))).Split(':');
            var user = new { Name = cred[0], Pass = cred[1] };
            if (user.Name == Username && user.Pass == Password) return;
        }
        filterContext.HttpContext.Response.AddHeader("WWW-Authenticate", String.Format("Basic realm="{0}"", BasicRealm ?? "Ryadel"));
        /// thanks to eismanpat for this line: http://www.ryadel.com/en/http-basic-authentication-asp-net-mvc-using-custom-actionfilter/#comment-2507605761
        filterContext.Result = new HttpUnauthorizedResult();
    }
}

It can be used to put under Basic Authentication a whole controller:

[BasicAuthenticationAttribute("your-username", "your-password", 
    BasicRealm = "your-realm")]
public class HomeController : BaseController
{
   ...
}

or a specific ActionResult:

public class HomeController : BaseController
{
    [BasicAuthenticationAttribute("your-username", "your-password", 
        BasicRealm = "your-realm")]
    public ActionResult Index() 
    {
        ...
    }
}

In case you need additional info check out this blog post that I wrote on the topic.

Method 2

You can do this with a custom attribute. There is an implementation of a custom attribute that supports base authentication in the open source project SimpleSecurity, which you can download here. There is a reference application to demonstrate how it is used. It was originally developed to work with SimpleMembership in MVC 4 and has been recently ported to use ASP.NET Identity in MVC 5.

Method 3

I wanted to amend the answer shared by Darkseal, because that code has a major security flaw. As written, that action filter does not actually terminate the request when res.End() is called. The user is prompted for credentials and a 401 response is returned if the credentials don’t match, but the controller action is still executed on the server side. You need to set the filterContext.Result property to something in order for the request to terminate properly and not continue to the action method.

This was particularly bad for my situation, as I was trying to protect a web service endpoint that receives a data feed from a third party. As written, this action filter didn’t protect anything because the data was still being pushed through my action method.

My “quick fix” is below:

public class BasicAuthenticationAttribute : ActionFilterAttribute
{
    public string BasicRealm { get; set; }
    protected string Username { get; set; }
    protected string Password { get; set; }

    public BasicAuthenticationAttribute(string username, string password)
    {
        this.Username = username;
        this.Password = password;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var req = filterContext.HttpContext.Request;
        var auth = req.Headers["Authorization"];
        if (!String.IsNullOrEmpty(auth))
        {
            var cred = System.Text.ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(auth.Substring(6))).Split(':');
            var user = new { Name = cred[0], Pass = cred[1] };
            if (user.Name == Username && user.Pass == Password) return;
        }
        var res = filterContext.HttpContext.Response;
        res.AddHeader("WWW-Authenticate", String.Format("Basic realm="{0}"", BasicRealm ?? "Ryadel"));
        filterContext.Result = new HttpUnauthorizedResult();
    }
}

Method 4

HTTP basic authentication doesn’t require a cookie. It’s based on a HEADER in the HTTP request. The header is named Authorization and its value should be username and password combined into a string, “username:password” (all base64 encoded).

Sincerely I never used basic authentication with ASP.NET MVC, but I used Web API to create a custom attribute (you can start from here for WebAPI or here for MVC).

Method 5

Great answer from @Darkseal. Here’s the same code repurposed for use with ASP.NET Web API (close cousin to MVC). Same idea, slightly different namespaces and context classes. Add it to your classes and methods in exactly the same way.

using System.Web.Http.Controllers;
using System.Web.Http.Filters;

public class BasicAuthenticationAttribute : ActionFilterAttribute
{
    public string BasicRealm { get; set; }
    protected string Username { get; set; }
    protected string Password { get; set; }

    public BasicAuthenticationAttribute(string username, string password)
    {
        Username = username;
        Password = password;
    }

    public override void OnActionExecuting(HttpActionContext filterContext)
    {
        var req = filterContext.Request;
        var auth = req.Headers.Authorization;
        if (auth?.Scheme == "Basic")
        {
            var cred = Encoding.ASCII.GetString(Convert.FromBase64String(auth.Parameter)).Split(':');
            var user = new { Name = cred[0], Pass = cred[1] };
            if (user.Name == Username && user.Pass == Password) return;
        }
        filterContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
        filterContext.Response.Headers.Add("WWW-Authenticate", string.Format("Basic realm="{0}"", BasicRealm ?? "YourRealmName"));
    }
}

Method 6

you can try this package on Nuget (AuthPackage)
its enables you to add authentication to your asp.net mvc easily.

  1. install package using Package Manager Console:

    Install-Package AuthPackage

  2. add Connection String to your Web.config in (appSettings):
     <add key="connectionString" value="connectionStringHere" />
  3. you’re ready to register users, login, logout

example:

 public async Task<ActionResult> SignIn()
    {
        var context = System.Web.HttpContext.Current;
        AuthUser authUser = new AuthUser(context);
        await authUser.SignIn("<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b4c3d5d8d1d1d0d7dcd5cdd1d686f4d3d9d5ddd89ad7dbd9">[email protected]</a>", "123456");
        return RedirectToAction("Index", "Home");
    }

You can read the Documentation here

Method 7

An application of ours “accidentally” used basic authentication because of the following code in Web.config:

<system.webServer>
    <modules>
        <remove name="FormsAuthentication" />
    </modules>
    ... other stuff
</system.webServer>

The application is otherwise configured to use forms authentication.
The browser authentication window popped up whenever normal forms authentication would otherwise have been used.

Method 8

The Darkseal’s answer

[BasicAuthenticationAttribute("your-username", "your-password", 
    BasicRealm = "your-realm")]

has 2 disadvantages :
name and password are hardcoded and they support only single user.

More flexible solution should support multiple username/password pairs stored in configuration.

Microsoft describes a sample https://gm/aspnet/samples/tree/main/samples/aspnet/WebApi/BasicAuthentication.

public abstract class BasicAuthenticationAttribute : Attribute, IAuthenticationFilter

In overload of

abstract Task<IPrincipal> AuthenticateAsync(string userName, string password,   
CancellationToken cancellationToken);

you can implement check to find if username/password from the header exist in configuration/secret list of username/password pairs

It’s also possible to create HTTP module that performs Basic Authentication. You can easily plug in an ASP.NET membership provider by replacing the CheckPassword method.
https://docs.microsoft.com/en-us/aspnet/web-api/overview/security/basic-authentication#basic-authentication-with-custom-membership

Example of OWIN implementation https://github.com/scottbrady91/Blog-Example-Classes/tree/master/OwinBasicAuthentication/WebApi

Possible implementation in .Net core is described in
https://github.com/mihirdilip/aspnetcore-authentication-basic


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x