2016-07-15 60 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