2016-07-15 58 views
2

我使用asp.net Forms身份驗證來要求用戶在訪問特定頁面時登錄。我希望用戶在不活動5分鐘後再次登錄,但無論我在web.config中的表單部分的超時值中放置了什麼,用戶僅在會話狀態到期後纔會啓動。表單身份驗證超時被忽略

一個我一直在嘗試,測試包括以下配置:

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

如果我登錄並保持空閒一分鐘,我問,如果我刷新頁面,重新登錄。但是,我的印象是,我應該能夠繼續工作,直到表單身份驗證超時過期。我明白,在1分鐘的時間內,對於slidingexpiration設置來更新我的cookie已經太晚了,但我應該在cookie實際到期之前還有一分鐘。

如果我刪除Sessiontate超時部分,我不會在兩分鐘後通過登錄。在我被要求重新登錄之前,需要很長時間(大概30分鐘)。這對我來說聽起來像只有在sessionState過期時纔會被要求重新登錄。

我在這裏錯過了什麼嗎?

下面是涉及的控制器和方法的基本佈局。首先,用戶試圖去招聘頁面:

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

因爲用戶需要授權他們將被重定向到登錄頁面,認證控制器:

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

這裏是BaseAuthenticationController類:

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

下面是具體的IAuthenticationService類:

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

    } 
} 

我不上點以下行的是什麼太清楚是在WebAuthenticationService類:是指

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

的setCurrent()方法如下:

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會員供應商:

 <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

什麼是查看在應用程序的登錄名?通常情況下,開發人員在config表單元素中有一個名爲'Login'的視圖,在這種情況下loginUrl =「〜/ authentication/Login」。 – Sunil

+0

視圖本身被稱爲Login.cshtml。 'loginUrl =「〜/ authentication」'設置觸發認證控制器中的Index方法,該方法在檢查ModelState是否有效後又將用戶帶到Login.cshtml視圖。登錄邏輯似乎大部分工作正常。唯一關閉的是用戶註銷並且被要求重新輸入其憑據的時間間隔。 – Bruno

+0

可能你應該嘗試'loginUrl =「〜/ authentication/Login」'。我不知道你的應用程序需求是什麼,但是爲了將用戶重定向到登錄頁面,應該不需要檢查ModelState。但是,當您使用HttpPost調用Login操作時,即用戶提交他/她的憑據時,則需要檢查ModelState。所以我猜測,你沒有正確連接認證部分。 – Sunil

回答

2

我找到了我所有問題的原因。我在global.asax中找到了一堆處理用戶會話並基本覆蓋表單身份驗證的代碼。此代碼在對服務器的每個請求上運行,並保持用戶登錄,只要它們仍在會話中進行身份驗證即可。這意味着,即使表單auth cookie過期(它做了!)用戶仍然會登錄。我猜測以前的開發人員開始使用表單驗證,然後決定寫出他們自己的東西出於某種原因。我們決定更改會話超時,使用戶將5分鐘而不是默認的20

這裏之後被註銷是一些從Global.asax中的代碼,負責我的幾乎禿頂:

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

而這正是我們在web.config中改變會話超時:

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

我不得不將以下內容添加到web.config f ILE以防止未經授權的用戶訪問的頁面:

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

顯然,這是非常標準的程序,我很驚訝,我沒有在我的搜索碰上它要早得多。 This msdn文章實際上提到了添加該部分。

+0

看起來這會將用戶發送到登錄頁面,而不管他們點擊了哪個頁面。如果他們試圖訪問特定頁面,他們只能進入登錄頁面。 (嘆氣)回到繪圖板。 – Bruno

+0

這是否解決了您1分鐘後超時的問題? – Sunil

+0

它實際上沒有。它的工作原理是,用戶將在1分鐘後根據需要註銷,但會將訪問網站上任意頁面的用戶重定向到登錄頁面。如果他們嘗試訪問Hire/Recruiter頁面,那麼他們只應該進入登錄頁面,因爲它被標記爲Authorize屬性。 – Bruno

2

您只是使用FormsAuthentication.SetAuthCookie方法的錯誤參數值。根據文檔https://msdn.microsoft.com/pl-pl/library/twk5762b(v=vs.110).aspx如果設置爲true,則第二個參數設置永久cookie。否則,Cookie不會在會話超時時保持並丟失。所以,如果你想保留通過不同的會話(會話超時後)的身份驗證cookie,然後使用此:

FormsAuthentication.SetAuthCookie(userName, true); 

但是請記住,會話超時用戶後將失去了所有的會話變量,並可以在您的網絡造成的錯誤應用程序。

+0

我嘗試使用一個持久性cookie,但它沒有工作,因爲即使它已打開,我們完全忽略了表單身份驗證(請參閱下面的答案)。 – Bruno