# Form Authentication 在 timeout 時間還沒到前就失效 ###### tags: `ASP.NET` > 更新時間:2020/09/30 ## 情境 authentication timeout 設定值為 20 分鐘,但過了 10 幾分鐘就被強制登出。 **Web.config** ```xml <authentication mode="Forms"> <forms loginUrl="login.aspx" name="GSE.ASPXFORMSAUTH" slidingExpiration="true" timeout="20" /> </authentication> <authorization> <deny users="?"/> </authorization> ``` ## 原因 ASP.Net 有一個 FormsAuthentication.SlidingExpiration 的設定,而且預設是 True,只要使用者有持續使用系統,他就會自動重新設定票證的失效時間。 但是為了避免不斷重新設定票證會影響效能,所以 SlidingExpiration 的行為是當票證已經超過原本的失效時間一半時才會重新設定票證,也就是說若票證是 1:00 產生,timeout 時間設定20分鐘,則只有在 1:10 後使用者還有對 Server 送出要求才會重新取得新的票證。 這邊的設計就會產生我們所遇到的,為什麼我明明沒有超過 20 分鐘沒有使用系統,卻被要求重新登入。原因就在於 SlidingExpiration 重新取得票證的行為。如果我最後使用系統是在 1:09 的時候,這樣當我在 1:21 回來使用系統,雖然感覺上我只有 12 分鐘沒有使用系統,但因為我的票證失效時間還是 1:20 所以我就被要求重新登入。 但反過來說如果你最後使用系統的時間是 1:11, 由於已經超過了 1:10 所以你的票證會重取,新票證的失效時間就不會是 1:20 了,所以 1:21 回來使用系統,就不會被重新要求登入了。 ## 解決方式 可在 Global.asax 的 Application_AuthenticateRequest 方法裡讓每次的請求都手動更新票證過期時間。 **Global.asax** ```csharp protected void Application_AuthenticateRequest(object sender, EventArgs e) { // 每次 Request 皆更新一次 Authentication timeout 設定時間 if (Request.IsAuthenticated && Context.User.Identity is FormsIdentity) { //原本的 Ticket var orgTicket = ((FormsIdentity)Context.User.Identity).Ticket; //取出 Timeout 的值 var timeoutValue = (TimeSpan)(orgTicket.Expiration - orgTicket.IssueDate); var now = DateTime.Now; //重新再計算新的過期時間 var newExpiration = now + timeoutValue; //建立一個新的 Ticket var newTicket = new FormsAuthenticationTicket(orgTicket.Version, orgTicket.Name, now, newExpiration, orgTicket.IsPersistent, orgTicket.UserData); if (newTicket.Expiration > orgTicket.Expiration) { // 建立 FormsAuthentication Cookie HttpCookie objCookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(newTicket)); // 蓋掉舊的 Cookie Response.Cookies.Add(objCookie); } } } ``` ## 參考資料 * 為什麼我的 APS.Net Form Authentication 在 timeout 時間還沒到前就失效了 https://blog.gss.com.tw/index.php/2017/03/16/aps_net_form_authentication_timeout/ * Forms AuthenticationTicket SlidingExpiration 過期問題 https://dotblogs.com.tw/rainmaker/2017/03/23/165147