Подтвердить что ты не робот

Как сохранить вход пользователя в систему и выйти из системы только после того, как пользователь нажимает кнопку выхода из системы?

Я использую пользовательскую реализацию идентификатора asp.net для microsoft, потому что у меня есть пользовательские таблицы, поэтому я дал пользовательскую реализацию всех моих методов IUserStore и IUserPasswordStore.

Проблема заключается в том, что пользователь регистрируется после 10 - 15 минут входа пользователя сеанс истек, но я хочу, если пользователь не выйдет из системы, я хочу войдите в систему в систему.

Код:

public partial class Startup
    {
        public void ConfigureAuth(IAppBuilder app)
        {
            app.CreatePerOwinContext(ApplicationDbContext.Create);
            app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
            app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Account/Login"),
                Provider = new CookieAuthenticationProvider
                {
                    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                        validateInterval: TimeSpan.FromMinutes(30),
                        regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
                }
            });            
            app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
            app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
        }
    }

Контроллер учетной записи:

[Authorize]
    public class AccountController : Controller
    {
        public AccountController()
            : this(new UserManager<UserModel>(new UserStore()))
        {
        }

        public AccountController(UserManager<UserModel> userManager)
        {
            UserManager = userManager;
        }
        public UserManager<UserModel> UserManager { get; private set; }

         [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Login(string email, string password, bool rememberMe = false, string returnUrl = null)
        {
            if (ModelState.IsValid)
            {
                var user = UserManager.Find(email, password);

                if (user != null)
                {
                    await SignInAsync(user, rememberMe);
                    return RedirectToLocal(returnUrl);
                }
                else
                {
                    ModelState.AddModelError("", "Invalid username or password.");
                }
            }
            return View();
        }

        private async Task SignInAsync(UserModel user, bool isPersistent)
        {
            var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
            identity.AddClaim(new Claim("FullName", user.FirstName + " " + user.LastName));
            identity.AddClaim(new Claim("Email", user.Email));
            identity.AddClaim(new Claim("Role", user.Role));
            AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent, ExpiresUtc = DateTime.UtcNow.AddDays(7) }, identity);
        }

 private IAuthenticationManager AuthenticationManager
        {
            get
            {
                return HttpContext.GetOwinContext().Authentication;
            }
        }
    }

Web.config:

<system.web>
    <authentication mode="None" />
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
  </system.web>
  <system.webServer>
    <modules>
      <remove name="FormsAuthentication" />
    </modules>
  </system.webServer>

Теперь в этой ниже строке я дал 7 дней истечения срока действия, но все же сеансы истекают через 10 - 15 минут:

  AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent, ExpiresUtc = DateTime.UtcNow.AddDays(7) }, identity);

Здесь в моем следующем вопросе вы найдете мой UserModel, пользовательский класс UserStore, но для того, чтобы этот вопрос был небольшим, я не помещаю этот код здесь:

UserModel и UserStore

Обновление. Я полностью исключил класс ApplicationUser, поэтому теперь код ниже для меня бесполезен, и я думаю, из-за этого мой файл cookie истек, я думаю (все же я не уверен):

 public void ConfigureAuth(IAppBuilder app)
        {
            app.CreatePerOwinContext(ApplicationDbContext.Create);
            app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
            app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Account/Login"),
                Provider = new CookieAuthenticationProvider
                {
                    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                        validateInterval: TimeSpan.FromMinutes(30),
                        regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
                }
            });            
 }

Примечание. ** Причина поддержания активного сеанса в течение длительного времени заключается в том, что мое приложение mvc angular управляется как вызов Http get, Http post call, поэтому, когда пользовательский сеанс истек, и я, если я попытаюсь ** get или post, тогда ничего не происходит в случае окончания сеанса, но когда я обновляю всю свою страницу, тогда пользователь перенаправляется на страницу входа, но до тех пор, как пользователь узнает, что происходит, если пользователь не обновляет страницу.

4b9b3361

Ответ 1

Ваша проблема связана с отсутствием SecurityStamp. Марка безопасности - это случайная строка, которая работает как проверка, был ли пароль изменен на сервере. Штамп безопасности хранится в файле cookie, а затем - и затем проверяется на базе базы данных. Если значение в базе данных (хранилище) отличается от значения в файле cookie - пользователю предлагается войти в систему. SecurityStampValidator выполняет все проверки и недействительность файлов cookie.

Вы используете пользовательское хранилище для пользователей и это прекрасно, но ваше хранилище не реализует IUserSecurityStampStore, и когда пользовательский файл cookie не получает значение SecurityStamp. Это приводит к неисправности SecurityStampValidator.

Итак, ваши варианты:

  • Внесите IUserSecurityStampStore в ваш магазин.
  • Удалите SecurityStampValidator из вашей конфигурации.

Мне не нравится второй вариант из-за проблемы с безопасностью. Вы хотите, чтобы ваши пользователи оставались включенными навсегда - это означает, что cookie никогда не аннулируется. Но когда у пользователя есть 2 браузера, оба вошли в систему. И сменить пароль в одном из браузеров - второй должен быть выведен из системы и просить пароль. Не проверяя маркер безопасности, второй браузер не будет выходить из системы, и файл cookie будет по-прежнему действителен. Теперь представьте, что второй браузер открывается на общедоступном компьютере, и пользователь забыл выйти из системы - никоим образом не завершить этот сеанс даже с изменением пароля.

Чтобы реализовать IUserSecurityStampStore посмотреть на контракт:

/// <summary>
///     Stores a user security stamp
/// </summary>
/// <typeparam name="TUser"></typeparam>
/// <typeparam name="TKey"></typeparam>
public interface IUserSecurityStampStore<TUser, in TKey> : IUserStore<TUser, TKey> where TUser : class, IUser<TKey>
{
    /// <summary>
    ///     Set the security stamp for the user
    /// </summary>
    /// <param name="user"></param>
    /// <param name="stamp"></param>
    /// <returns></returns>
    Task SetSecurityStampAsync(TUser user, string stamp);

    /// <summary>
    ///     Get the user security stamp
    /// </summary>
    /// <param name="user"></param>
    /// <returns></returns>
    Task<string> GetSecurityStampAsync(TUser user);
}

В основном это добавляет другой столбец в таблицу ваших пользователей: SecurityStamp и вам нужно сохранить там строку. И значение для штампа - любая случайная строка. Идентификация по умолчанию Identity (вокруг строки 734) использует Guid.NewGuid().ToString() - я предлагаю вам сделать то же самое.

Магазин вашего пользователя будет выглядеть примерно так:

public class UserStore : IUserStore<UserModel>, IUserPasswordStore<UserModel>, IUserSecurityStampStore<TUser>
{
    // your other methods


    public async Task SetSecurityStampAsync(TUser user, string stamp)
    {
        if (user == null)
        {
            throw new ArgumentNullException("user");
        }
        user.SecurityStamp = stamp;
        return Task.FromResult(0);
    }

    Task<string> GetSecurityStampAsync(TUser user)
    {
        if (user == null)
        {
            throw new ArgumentNullException("user");
        }
        return Task.FromResult(user.SecurityStamp);
    }
}

Имейте в виду - вам не нужно сохранять пользователя в хранилище в этой операции. UserManager делает это для вас в UpdateSecurityStampAsync - если вы не переопределите этот метод самостоятельно.

Также не забудьте назначить значение в поле SecurityStamp при создании новых пользователей. И обновите всех существующих пользователей со значением. Что-то вроде этого будет работать update MyUsersTable set SecurityStamp = convert(nvarchar(38), NewId())

Ответ 2

метод управления вызовом в определенный интервал времени, поэтому он будет reset тайм-аутом сеанса при вызове evry. Например, если изначально вы установили свой тайм-аут сеанса через 30 минут, а через 20 минут вы вызываете это действие, он снова будет reset тайм-аута сеанса снова 30 минут, таким образом ваш сеанс остается активным даже до 30 минут после входа в систему.

Поместите код JQuery в макет

JQuery

var RefreshSessionInterval;

$(document).ready(function () {        
      clearInterval(RefreshSessionInterval);
      RefreshSessionInterval = setInterval("RefreshSession()", 30000);  // change your interval time as per requirement     
});

function RefreshSession() {
       $.ajax({
            type: "POST",
            url: '@Url.Action("RefreshSession", "YourControllerName")',           
            success: function (data) {               
            },
            error: function () {
            }
       }); 
}

Контроллер:

Public void RefreshSession()
{
    //your session reset from this line, as i know you don't have to write any code here.
}

public bool LogOut()
{
        LogOff();
        return true;
}

void LogOut()
{       
    Session.Clear();
    Session.Abandon();
    Session.RemoveAll();
    ClearCache();        
}

void ClearCache()
{
    Response.Cache.SetCacheability(HttpCacheability.NoCache);
    Response.Cache.SetExpires(DateTime.Now.AddSeconds(-1));
    Response.Cache.SetNoStore();
    ////FormsAuthentication.SignOut();
}

Ответ 3

У меня была такая же проблема, и я был очень смущен, потому что без какой-либо причины пользователь был перенаправлен на страницу входа в систему, что он не был авторизован. Я изменил таймаут на более чем 8 часов, но ничего не изменилось. После прочтения многих страниц, таких как неожиданный выход из системы Aspnet или frequent-unexpected-user-logoff, я обнаружил, что с машиной что-то не так и после проверки машинного ключа в файле web.config я мог обнаружить проблему с помощью машинного ключа. Изменяя машинный ключ и делайте его одинаковым с другими в разделе Owin, все работает хорошо.

Ответ 4

Вы пробовали

 ExpireTimeSpan = TimeSpan.FromDays(7);

поэтому это сделает ваш код:

public partial class Startup
    {
        public void ConfigureAuth(IAppBuilder app)
        {
            app.CreatePerOwinContext(ApplicationDbContext.Create);
            app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
            app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Account/Login"),
                Provider = new CookieAuthenticationProvider
                {
                    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                        validateInterval: TimeSpan.FromMinutes(30),
                        regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
                }
            });

            ExpireTimeSpan = TimeSpan.FromDays(7);
            app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
            app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
        }
    }

Ответ 6

Вот что я сделал, когда я закодировал пользователя, чтобы он был подписан...

код

public partial class Startup
    {

        public void ConfigureAuth(IAppBuilder app)
        {
            // Enable the application to use a cookie to store information for the signed in user
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Account/Login")
            });
// Use a cookie to temporarily store information about a user logging in with a third party login provider
            app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

        }
    }

Контроллер учетных записей

public class AccountController : Controller
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="AccountController"/> class.
        /// </summary>
        public AccountController()
            : this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="AccountController"/> class.
        /// </summary>
        /// <param name="userManager">The user manager.</param>
        public AccountController(UserManager<ApplicationUser> userManager)
        {
            UserManager = userManager;
        }

        /// <summary>
        /// Gets the user manager.
        /// </summary>
        /// <value>
        /// The user manager.
        /// </value>
        public UserManager<ApplicationUser> UserManager { get; private set; }

        //
        // GET: /Account/Login
        /// <summary>
        /// Logins the specified return URL.
        /// </summary>
        /// <param name="returnUrl">The return URL.</param>
        /// <returns></returns>
        [AllowAnonymous]
        public ActionResult Login(string returnUrl)
        {
            ViewBag.ReturnUrl = returnUrl;
            return View();
        }

        //
        // POST: /Account/Login
        /// <summary>
        /// Logins the specified model.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="returnUrl">The return URL.</param>
        /// <returns></returns>
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                var user = await UserManager.FindAsync(model.UserName, model.Password);
                if (user != null)
                {
                    await SignInAsync(user, model.RememberMe);
                    return RedirectToLocal(returnUrl);
                }
                else
                {
                    ModelState.AddModelError("", "Invalid username or password.");
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

private async Task SignInAsync(ApplicationUser user, bool isPersistent)
        {
            AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
            var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
            AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
        }

ИЛИ.. Вы также можете настроить тайм-аут сеанса для пользователя на уровне пула приложений в IIS.

Ответ 7

Время жизни сеанса (до тех пор, пока сеанс не исчезнет) и время ожидания проверки подлинности (как долго, пока пользователь не сможет снова войти в систему) - это два отдельных и отдельных таймфрейма.

Если время ожидания аутентификации больше, чем время сеанса, это означает, что сеанс начнется с уже прошедшего проверку пользователя (то есть пользователю не нужно будет входить в систему для запуска сеанса).

Если срок службы аутентификации короче таймфрейма сеанса, это означает, что пользователь будет вынужден войти в систему до истечения срока их сеанса. Я не уверен, что сеанс "обновляется", когда пользователь повторно проверяет (возможно, предположительно).

Простое установление очень длительных выходов для сеанса и аутентификации может не быть готовым решением для пиратской продукции (т.е. существует множество способов "исчезновения сеансов" ).

Почему вас беспокоит, если пользовательский сеанс пропадает, а затем запускается новый (без входа в систему)? Без дополнительной информации о том, что вы намереваетесь, я не могу понять суть вашего вопроса.

Ответ 8

Изучите настройки элемента в элементе аутентификации вашего файла web.config.

Обратите внимание на значения по умолчанию для двух применимых параметров.

  • таймаут (по умолчанию 30 минут)
  • slideExpiration (True или False/default varines с версией .NET Framework)

В вашей ситуации вам, вероятно, понадобится продолжительность таймаута намного выше 30 минут и значение slideExpiration True.