c# - 表单例份验证超时被忽略

标签 c# asp.net asp.net-mvc-4 cookies forms-authentication

我使用 asp.net 表单例份验证来要求用户在访问特定页面时登录。我希望用户在 5 分钟不活动后必须重新登录,但无论我在 web.config 中表单部分的超时值中输入什么,用户只会在 session 状态过期后才会被踢出。

我尝试过的测试之一涉及此配置:

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

如果我登录并保持空闲一分钟,则刷新页面时系统会要求我重新登录。但是,我的印象是我应该能够继续工作,直到表单例份验证超时到期。我知道在 1 分钟标记处,滑动过期设置更新我的 cookie 就太晚了,但在 cookie 实际过期之前我还应该再有一分钟的时间。

如果我删除 Sessiontate 超时部分,两分钟后就不会要求我登录。我需要很长时间(可能 30 分钟)才被要求重新登录。对我来说,这听起来好像只有在 sessionState 过期时才被要求重新登录。

我在这里遗漏了什么吗?

这是所涉及的 Controller 和方法的基本布局。首先,用户尝试转到招聘人员页面:

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

由于用户需要获得授权,因此他们被重定向到身份验证 Controller 中的登录页面:

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>

最佳答案

您只是在 FormsAuthentication.SetAuthCookie 方法中使用了错误的参数值。根据文档https://msdn.microsoft.com/pl-pl/library/twk5762b(v=vs.110).aspx如果设置为 true,第二个参数将设置持久 cookie。否则,cookie 不会保留并在 session 超时时丢失。因此,如果您想通过不同的 session ( session 超时后)保留身份验证 cookie,请使用:

FormsAuthentication.SetAuthCookie(userName, true);

但是请记住, session 超时后,用户将丢失所有 session 变量,这可能会导致您的网络应用程序出现错误。

关于c# - 表单例份验证超时被忽略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38404429/

相关文章:

java - 查询检查列表内部

c# - 使用 "not in"子句连接两个以上的表

c# - 从 ajax 数据创建的下拉列表中绑定(bind)数据

asp.net-mvc-4 - 我如何访问类库中的 session 值?(System.Web.Current.Session 不起作用)

c# - 如何通过加倍正则表达式中的定界符来转义定界符

c# - 在 C# 中的段落范围内添加制表位

c# - 交易失败。服务器响应是 : SMTP Host

c# - ASP.NET MVC 路由以数字开头的 URL

java - (.Net + SQL Server +Azure ) 与 (Java + Oracle +Google App Engine) 哪个更适合这个项目?

asp.net-mvc-4 - asp.net mvc 捆绑可扩展性