2016-07-15 4 views
2

Ich benutze die asp.net-Formularauthentifizierung, damit Benutzer sich beim Besuch einer bestimmten Seite anmelden müssen. Ich möchte, dass sich die Benutzer nach 5 Minuten Inaktivität wieder einloggen müssen, aber unabhängig davon, was ich im Timeout-Wert des forms-Abschnitts in web.config eingegeben habe, wird der Benutzer erst nach Ablauf des Sitzungsstatus gestartet.Zeitlimitüberschreitung bei Formularauthentifizierung

Einer der Tests, die ich versucht habe, beinhaltet diese Konfiguration:

<system.web> 
<sessionState timeout="1" /> 
    <authentication mode="Forms"> 
     <forms loginUrl="~/authentication" timeout="2" slidingExpiration="true"/> 
    </authentication> 
</system.web> 

Wenn ich mich einloggen und bleiben Leerlauf für eine Minute, die ich gefragt bin wieder anmelden, wenn ich die Seite aktualisieren. Ich hatte jedoch den Eindruck, dass ich weiterarbeiten könnte, bis das Zeitlimit für die Formularauthentifizierung abgelaufen ist. Ich verstehe, dass es bei der 1-Minuten-Marke zu spät für die Einstellung gleitendeErlaubnis wäre, mein Cookie zu erneuern, aber ich sollte noch eine Minute warten, bevor das Cookie tatsächlich abläuft.

Wenn ich den Sessiontate-Timeout-Bereich entferne, werde ich nach zwei Minuten nicht aufgefordert, mich einzuloggen. Es dauert eine lange Zeit (wahrscheinlich 30 Minuten), bevor ich aufgefordert werde, mich wieder anzumelden. Das klingt für mich so, als ob ich mich nur anmelde, wenn der sessionState abläuft.

Fehle ich hier etwas?

Hier ist das grundlegende Layout der beteiligten Controller und Methoden. Zuerst versucht der Benutzer auf die Recruiter Seite zu gehen:

public class HireController : Controller 
{ 
    [Authorize] 
    public ActionResult Recruiter() 
    { 
     //do stuff after we've been authorized to access this page 
    } 
} 

Da der Benutzer autorisiert werden muss sie auf die Anmeldeseite in dem Authentifizierungs-Controller weitergeleitet werden:

public class AuthenticationController : BaseAuthenticationController 
{ 
    private readonly IAuthenticationService AuthenticationService; 
    public AuthenticationController(IAuthenticationService authService) 
     : base(authService) 
    { 
     AuthenticationService = authService; 
    } 
    [AcceptVerbs(HttpVerbs.Get)] 
    public ActionResult Index(string returnUrl) 
    { 
     var special= false; 
     return View("~/Views/Login/Login.cshtml", new LoginModel(special) { ReturnUrl = returnUrl }); 
    } 

    [AcceptVerbs(HttpVerbs.Post)] 
    public ActionResult Index(LoginCredentials credentials, string returnUrl) 
    { 
     try 
     { 
      if (!ModelState.IsValid) 
      { 
       throw new ApplicationException(GeneralError); 
      } 

      base.DoLogin(credentials.Username, credentials.Password); 
     } 
     catch (Exception ex) 
     { 
      string message = (ex is ApplicationException) ? ex.Message : GeneralError; 
      ModelState.AddModelError("", message); 
      return View("~/Views/Login/Login.cshtml", new LoginModel { Username = credentials.Username, ReturnUrl = returnUrl }); 
     } 
     return RedirectToLocal(returnUrl); 

    } 

    private ActionResult RedirectToLocal(string returnUrl) 
    { 
     if (Url.IsLocalUrl(returnUrl)) 
     { 
      return Redirect(returnUrl); 
     } 
     if (User.Identity != null && User.Identity.IsAuthenticated) 
     { 
      return RedirectToAction("Recruiter", "Hire"); 
     } 
     return RedirectToAction("Recruiter", "Hire"); 
    } 
} 

Hier ist die BaseAuthenticationController Klasse :

public class BaseAuthenticationController : Controller 
{ 
    private readonly IAuthenticationService AuthenticationService; 
    protected const string GeneralError = "Login failure please try again"; 

    public BaseAuthenticationController(IAuthenticationService authService) 
    { 
     AuthenticationService = authService; 
    } 

    public void DoLogin(string username, string password) 
    { 
     AuthenticationService.Login(username, password); 
    } 
} 

Hier ist die konkrete IAuthenticationService Klasse:

public class WebAuthenticationService : IAuthenticationService 
{ 
    private const string InvalidError = "Invalid User Credentials Please try again"; 
    private const string LockoutError = "You have been locked out of the Hiring Center. You will receive an email shortly once your password has been reset."; 
    readonly string uri = ConfigurationManager.AppSettings["HiringLoginApiBaseUrl"]; 
    private readonly ISecurityContext SecurityContext; 

    public WebAuthenticationService(ISecurityContext securityContext) 
    { 
     SecurityContext = securityContext; 
    } 

    private LoginResult GetUserLogin(string username, string password) 
    { 
     using (var httpClient = new HttpClient()) 
     { 
      httpClient.BaseAddress = new Uri(uri); 
      var content = new FormUrlEncodedContent(new[] 
      { 
       new KeyValuePair<string, string>("username", username), 
       new KeyValuePair<string, string>("password", password) 
      }); 
      var postResult = httpClient.PostAsync("/api/Login/Post", content).Result;     
      var loginResult = postResult.Content.ReadAsAsync<LoginResult>().Result; 

      return loginResult; 
     } 
    } 

    public MembershipProvider AuthenticationProvider 
    { 
     get { return Membership.Provider; } 
    } 

    public void Login(string userName, string password) 
    { 
     var loginResult = this.GetUserLogin(userName, password); 
     if (!loginResult.IsValid) 
     { 
      throw new ApplicationException(InvalidError); 
     } 

     if (loginResult.IsLockedOut) 
     { 
      throw new ApplicationException(LockoutError); 
     } 

     // Maintain the location 
     IUser current = SecurityContext.Current; 

     SecurityContext.SetCurrent(User.CreateAuthorized(userName, current.Location, current.Preferences)); 
     FormsAuthentication.SetAuthCookie(userName, false); 

    } 
} 

ich nicht ganz klar bin, was der Punkt der folgenden Zeile ist in der WebAuthenticationService Klasse:

SecurityContext.SetCurrent(User.CreateAuthorized(userName, current.Location, current.Preferences)); 

die SetCurrent() -Methode wie folgt definiert ist:

public class HttpSecurityContext : ISecurityContext 
{ 
    public static string SECURITY_CONTEXT_KEY = "SECURITY_CONTEXT"; 

    public IUser Current 
    { 
     get 
     { 
      IUser user = HttpContext.Current.User as IUser; 
      if (user == null) 
      { 
       throw new ApplicationException("Context user is invalid;"); 
      } 
      return user; 
     } 
    } 

    public void SetCurrent(IUser user) 
    { 
     HttpContext.Current.User = user; 
    } 
} 

Web.Config Mitgliedschafts-Provider:

 <membership> 
     <providers> 
      <clear /> 
      <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=asdfasf" connectionStringName="mydb" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="3" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" passwordStrengthRegularExpression="" applicationName="/" /> 
     </providers> 
    </membership> 
+0

Was ist der Name der Ansicht für die Anmeldung in der App? Normalerweise haben Entwickler eine Ansicht mit dem Namen 'Login', in diesem Fall' loginUrl = "~/authentication/Login" 'in der Konfigurationsdatei für forms. – Sunil

+0

Die Ansicht selbst heißt Login.cshtml. Die Einstellung "loginUrl =" ~/authentication "" löst die Index-Methode im Authentifizierungs-Controller aus, die wiederum den Benutzer in die Login.shtml-Ansicht versetzt, nachdem überprüft wurde, ob der ModelState gültig ist. Die Login-Logik scheint größtenteils in Ordnung zu sein. Die einzige Ausnahme ist das Intervall, nach dem der Benutzer abgemeldet wird und aufgefordert wird, seine Anmeldeinformationen erneut einzugeben. – Bruno

+0

Vielleicht sollten Sie versuchen mit 'loginUrl =" ~/authentication/Login "'. Ich weiß nicht, was Ihre App-Anforderungen sind, aber um einen Benutzer zur Anmeldeseite umzuleiten, sollte ModelState nicht überprüft werden. Wenn Sie jedoch die Anmeldeaktion mit HttpPost aufrufen, d. H. Wenn der Benutzer seine Anmeldeinformationen übermittelt, müssen Sie ModelState überprüfen. Ich vermute, Sie haben den Authentifizierungsteil nicht richtig verdrahtet. – Sunil

Antwort

2

Ich fand die Ursache für alle meine Probleme. Ich habe eine Menge Code in global.asax gefunden, der die Sitzung des Benutzers manipuliert und die Formularauthentifizierung im Wesentlichen außer Kraft setzt. Dieser Code wird bei jeder Anfrage an den Server ausgeführt und hält den Benutzer angemeldet, solange er in der Sitzung authentifiziert ist. Dies bedeutet, dass selbst wenn das Formular auth cookie abgelaufen ist (was es getan hat!) Der Benutzer eingeloggt bleiben würde. Ich nehme an, die früheren Entwickler begannen mit forms auth und entschieden dann aus irgendeinem Grund ihr eigenes Ding zu schreiben. Wir beschließen, das Session-Timeout zu ändern, so dass die Benutzer nach 5 Minuten abgemeldet anstelle des Standard würden 20.

Hier wird ein Teil des Codes von global.asax, die für mich verantwortlich ist fast kahl gehen:

protected void Application_PreRequestHandlerExecute() 
    { 
     HttpSessionState session = HttpContext.Current.Session; 
     if (session == null) 
      return; 

     IUser user = (session[HttpSecurityContext.SECURITY_CONTEXT_KEY] as IUser) ?? CreateUser(); 
     securityContext.SetCurrent(user); 
    } 

    protected void Application_PostRequestHandlerExecute() 
    { 
     HttpSessionState session = HttpContext.Current.Session; 
     if (session == null) return; 

     session[HttpSecurityContext.SECURITY_CONTEXT_KEY] = securityContext.Current; 
    } 

private IUser CreateUser() 
    { 
     IUserLocation location = LocateUser(); 
     IUser user = Common.Security.User.CreateAnonymous(location); 
     SetupUserPreferences(user); 
     return user; 
    } 

Und das ist, was wir in web.config für das Session-Timeout geändert:

<system.web> 
    <sessionState timeout="5"/> 
</system.web> 
0

Ich musste der web.config f Folgendes hinzufügen ile, um nicht autorisierte Benutzer zu verhindern Zugriff auf die Seite:

<authorization> 
    <deny users="?" /> 
</authorization> 

Anscheinend ziemlich Standardverfahren ist, und ich bin überrascht, dass ich nicht in sie viel früher in meiner Suche lief. This msdn Artikel erwähnt tatsächlich das Hinzufügen dieses Abschnitts.

+0

Es sieht so aus, als ob die Benutzer auf die Anmeldeseite gelangen, egal welche Seite sie getroffen haben. Sie sollen nur auf die Login-Seite gehen, wenn sie versuchen, auf eine bestimmte Seite zu gehen. (seufzt) Zurück zum Zeichenbrett. – Bruno

+0

Hat dies Ihr Problem gelöst, dass Sie nach 1 Minute das Zeitlimit überschritten haben? – Sunil

+0

Es war nicht wirklich. Es funktionierte in dem Sinne, dass Benutzer nach 1 Minute wie gewünscht abgemeldet wurden, aber es würde Benutzer, die JEDE Seite der Site besuchten, auf die Login-Seite umleiten. Sie sollten nur auf die Anmeldeseite geleitet werden, wenn sie versuchen, die Seite "Hire/Recruiter" zu besuchen, da sie mit dem Attribut Authorize gekennzeichnet ist. – Bruno

2

Sie verwenden nur falschen Parameterwert für FormsAuthentication.SetAuthCookie Methode. Gemäß der Dokumentation https://msdn.microsoft.com/pl-pl/library/twk5762b(v=vs.110).aspx setzt der zweite Parameter persistenten Cookie, wenn dieser Wert auf "true" gesetzt ist. Andernfalls wird der Cookie nicht gespeichert und ist beim Sitzungszeitlimit verloren.Also, wenn Sie Authentifizierungscookie durch verschiedene Sitzungen beibehalten möchten (nach Session-Timeout), dann verwenden:

FormsAuthentication.SetAuthCookie(userName, true); 

im Auge behalten jedoch, dass seine alle Session-Variablen nach Session-Timeout Benutzer verloren gehen und dass möglicherweise Fehler in Ihrem Web verursachen App

+0

Ich habe versucht, auch einen dauerhaften Cookie zu verwenden, aber es hat nicht funktioniert, weil wir Formulare auth völlig ignoriert haben, obwohl es eingeschaltet war (siehe meine Antwort unten). – Bruno

Verwandte Themen