web-dev-qa-db-fra.com

Authentification de base dans ASP.NET MVC 5

Quelles étapes devez-vous suivre pour implémenter l'authentification de base dans ASP.NET MVC 5?

J'ai lu qu'OWIN ne supporte pas l'authentification sans cookie, l'authentification de base est-elle généralement possible?

Ai-je besoin d'un attribut personnalisé ici? Je ne suis pas sûr de savoir comment fonctionnent ces attributs.

33
Sonic

Vous pouvez utiliser ce mécanisme simple mais efficace en utilisant un attribut ActionFilter personnalisé:

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();
    }
}

Il peut être utilisé pour mettre sous Authentification de base tout un contrôleur:

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

ou un ActionResult spécifique:

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

Au cas où vous auriez besoin d'informations supplémentaires, consultez cet article de blog que j'ai écrit sur le sujet.

68
Darkseal

Vous pouvez le faire avec un attribut personnalisé. Il existe une implémentation d'un attribut personnalisé qui prend en charge l'authentification de base dans le projet open source SimpleSecurity , que vous pouvez télécharger ici . Il existe une application de référence pour démontrer son utilisation. Il a été développé à l'origine pour fonctionner avec SimpleMembership dans MVC 4 et a récemment été porté pour utiliser l'identité ASP.NET dans MVC 5

13
Kevin Junghans

Je voulais modifier la réponse partagée par Darkseal, car ce code présente une faille de sécurité majeure. Tel qu'écrit, ce filtre d'action ne met pas réellement fin à la demande lorsque res.End () est appelée. Des informations d'identification sont demandées à l'utilisateur et une réponse 401 est renvoyée si les informations d'identification ne correspondent pas, mais l'action du contrôleur est toujours exécutée côté serveur. Vous devez définir la propriété filterContext.Result sur quelque chose pour que la demande se termine correctement et ne continue pas avec la méthode action. 

Cela était particulièrement mauvais pour ma situation, car j'essayais de protéger un point de terminaison de service Web recevant un flux de données provenant d'une tierce partie. Tel qu'écrit, ce filtre d'action ne protégeait rien car les données étaient toujours transmises par ma méthode d'action.

Ma "solution rapide" est ci-dessous:

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();
    }
}
5
PatrickGaule

Excellente réponse de @Darkseal. Voici le même code réutilisé pour une utilisation avec API Web ASP.NET (cousin proche de MVC). Même idée, espaces de noms et classes de contexte légèrement différents. Ajoutez-le à vos classes et méthodes exactement de la même manière.

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"));
    }
}
2
Neil Laslett

L'authentification HTTP de base ne nécessite pas de cookie. Il est basé sur un HEADER dans la requête HTTP. L'en-tête est nommé Authorization et sa valeur doit être le nom d'utilisateur et le mot de passe combinés dans une chaîne, "nom d'utilisateur: mot de passe" (tous codés en base64).

Je n'ai sincèrement jamais utilisé l'authentification de base avec ASP.NET MVC, mais j'ai utilisé l'API Web pour créer un attribut personnalisé (vous pouvez démarrer à partir de ici pour WebAPI ou ici pour MVC).

2
imperugo

vous pouvez essayer ce paquet sur Nuget (AuthPackage) Il vous permet d’ajouter facilement une authentification à votre asp.net mvc.

  1. installez le paquet en utilisant Package Manager Console:

    AuthPackage du paquet d'installation

  2. ajoutez une chaîne de connexion à votre Web.config dans (appSettings):

     <add key="connectionString" value="connectionStringHere" />
    
  3. vous êtes prêt à enregistrer des utilisateurs, vous connecter, vous déconnecter

exemple:

 public async Task<ActionResult> SignIn()
    {
        var context = System.Web.HttpContext.Current;
        AuthUser authUser = new AuthUser(context);
        await authUser.SignIn("[email protected]", "123456");
        return RedirectToAction("Index", "Home");
    }

Vous pouvez lire la documentation ici

1
Waleed Chayeb

Une de nos applications a utilisé "accidentellement" l'authentification de base en raison du code suivant dans Web.config:

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

L’application est par ailleurs configurée pour utiliser l’authentification par formulaires . La fenêtre d’authentification du navigateur apparaît chaque fois que l’authentification par formulaire normale aurait été utilisée.

0
Charles Burns