11

Sto lavorando al progetto ASP.NET MVC5 che ha l'autenticazione dei moduli abilitata. Il progetto è attualmente in fase di test e ospitato online su Azure, ma il proprietario del progetto vorrebbe disabilitare tutti gli accessi pubblici al sito (poiché alcune parti del sito non richiedono l'autenticazione dell'utente).ASP.NET MVC5 Autenticazione HTTP di base e AntiForgeryToken exception

Per questa fase di test, abbiamo deciso di implementare l'autenticazione HTTP di base, da questo link. Ho cambiato il codice, quindi è meglio adatta alle mie esigenze:

public class BasicAuthenticationAttribute : FilterAttribute, IAuthorizationFilter 
{ 
    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 void OnAuthorization (AuthorizationContext 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; 
     var alreadySent = HttpContext.Current.Items.Contains("headers-sent"); 

     if (!alreadySent) 
     { 
      res = filterContext.HttpContext.Response; 
      res.StatusCode = 401; 
      res.AppendHeader("WWW-Authenticate", String.Format("Basic realm=\"{0}\"", BasicRealm ?? "Test")); 

     } 
    } 
} 

ho anche registrato come un filtro globale:

public class FilterConfig 
{ 
    public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
    { 
     filters.Add(new HandleErrorExtendedAttribute()); 
     filters.Add(new BasicAuthenticationAttribute(AppConfig.BasicUsername, AppConfig.BasicPassword)); 
    } 
} 

Tuttavia, ci sono alcuni problemi quando ho eseguito il progetto . Se utilizzo questa versione di codice:

 if (!alreadySent) 
     { 
      res = filterContext.HttpContext.Response; 
      res.StatusCode = 401; 
      res.AppendHeader("WWW-Authenticate", String.Format("Basic realm=\"{0}\"", BasicRealm ?? "Test")); 
     } 

dopo il login con successo esso reindirizza costantemente alla pagina di accesso moduli.

Tuttavia, se aggiungo

res.End(); 

dopo

res.AppendHeader("WWW-Authenticate", String.Format("Basic realm=\"{0}\"", BasicRealm ?? "Test")); 

Antiforgerytoken in file cshtml tiri System.Web.HttpException

Server non è possibile accodare intestazione dopo intestazioni HTTP sono stati inviato.

Ma in questo caso, si autentica alla fine con successo.

Attualmente sono bloccato su questo e non ho idea di come risolvere questo problema, dal momento che disattivare l'autenticazione dei moduli non è e l'opzione, e non riesco a rimuovere tutti AntiForgeryTokens e la loro convalida.

+2

Perché avete scelto questo approccio?Se si desidera creare un 'Filtro di autenticazione personalizzato ', si dovrebbe ereditare da' AuthorizeAttribute', sovrascrivere la funzione 'IsAuthorized', restituire' false' per le richieste non autorizzate e gestirle nella funzione 'HandleUnauthorizedRequest'. – AnhTriet

+0

Se si capovolge la riga res.StatusCode con la riga res.AppendHeader cosa succederebbe? Il valore StatusCode conta come parte del "Corpo" in modo da chiudere le intestazioni da non essere più scritte? Inoltre, si prega di considerare la risposta di Andrew qui sotto. –

+0

plz non utilizzare l'autenticazione di base. Tieni presente che l'altra domanda a cui fai riferimento è uguale a 6 anni, e anche allora c'erano alternative migliori. Vedi: http://adrianotto.com/2013/02/why-http-basic-auth-is-bad/ – nothingisnecessary

risposta

1

Hai provato questa linea prima di res.AppendHeader (..)?

Response.ClearHeaders(); 
3

vorrei suggerire di utilizzare il provider di appartenenza ASP.NET identità dal momento che è incluso in MVC 5. Con questo si può semplicemente autenticare gli utenti senza scrivere un sacco di codice come è stato con iscrizione precedente. Può anche utilizzare l'accesso esterno con i cookie interni come se si utilizzasse il metodo FormsAuthentication. Tutto ciò di cui hai bisogno è creare semplici configurazioni nel codice e non è necessario scrivere i filtri personalizzati.

1

Invece di terminare la richiesta con req.End(), penso che si voglia impostare filterContext.Result come mostrato di seguito. L'impostazione del risultato su un valore non nullo interromperà l'elaborazione del resto della pipeline MVC e causerà l'invio della risposta al browser, ma non dovrebbe sigillare la risposta come fa , quindi non si dovrebbe ottenere l'eccezione sulle intestazioni già inviate.

Prova questo:

filterContext.Result = new HttpUnauthorizedResult(); 
Problemi correlati