Servicestack — вопросы аутентификации

#servicestack

#servicestack

Вопрос:

В настоящее время я немного борюсь со своей пользовательской CredentialsAuthProvider реализацией. Сначала важно сказать, что я пишу клиент WPF в качестве ссылки для моего API.

  1. Браузер хранит файлы cookie, и вы можете настроить, как с ними обращаться, например, удалять при закрытии браузера. На рабочем столе Windows у вас есть среда.Специальная папка.Файлы cookie, в которых Windows хранит файлы cookie. Но я ничего не смог найти из ServiceStack. Так он ничего не хранит в настольном приложении Windows? Я видел, что есть client.CookieContainer место, где я нахожу три файла cookie после входа в систему.
  2. Могу ли я каким-либо образом добавить свойства к этому файлу cookie во время аутентификации? Если да, то как? В настоящее время я использую AuthenticationResponse.Meta словарь для передачи дополнительной информации:
     public override object Authenticate(IServiceBase authService, IAuthSession session, Authenticate request)
    {
        var authResponse = (AuthenticateResponse)base.Authenticate(authService, session, request);
        authResponse.Meta = new Dictionary<string, string>();
        authResponse.Meta.Add("Test", "TestValue");
        return authResponse;
    }
     
  3. И, наконец: является ли экземпляр моего производного CredentialsAuthProvider класса потокобезопасным? В TryAuthenticate(...) я устанавливаю соединение с БД и извлекаю объект, который содержит всю информацию, включая хэшированный пароль и т.д. Но я могу только заполнить эту информацию для объекта сеанса OnAuthenticated(....) и / или переопределить Authenticate(...) . Если возможно, я не хочу делать еще один вызов DB для повторного получения того же объекта. Так безопасно ли объявлять элемент user , заполнять его TryAuthenticate и повторно использовать в других перезаписанных методах, например:
     public class BediCredentialsAuthProvider : CredentialsAuthProvider
    {
        private AppUser user = null;
    
        public override object Authenticate(IServiceBase authService, IAuthSession session, Authenticate request)
        {
            var authResponse = (AuthenticateResponse)base.Authenticate(authService, session, request);
            authResponse.Meta = new Dictionary<string, string>();
            authResponse.Meta.Add("ValueA", user.ValueA);
            // ... add more properties from user object
            return authResponse;
         }
    
         public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
         {
            AppUser user = null;
            using (var session = NhSessionFactories.OpenSession(TopinConstants.TopInDbFactory))
            {
                using (var transaction = session.BeginTransaction())
                {
                    try
                    {
                        var appUserRepo = new AccountManagementRepository(session);
                        user = appUserRepo.GetAppUser(userName); // get user from database using NHibernate
                        transaction.Commit();
                        session.Close();
                     }
                     catch (Exception ex)
                     {
                         Log.Error($"Error retrieving user {user} to authenticate. Error: {ex}");
                         throw;
                     }
                 }
             }
             // do some logic to test passed credentials and return true or false
          }
    
         public override IHttpResult OnAuthenticated(IServiceBase authService, IAuthSession session, IAuthTokens tokens,
                                                Dictionary<string, string> authInfo)
        {
            session.DisplayName = user.DisplayName;
            session.FirstName = user.Firstname;
            session.LastName = user.Lastname;
            session.Email = user.EmailAddress;
            // etc.....
            return base.OnAuthenticated(authService, session, tokens, authInfo);
        }
    }
     

Ответ №1:

Вы можете заполнять файлы cookie клиента сервиса ServiceStack точно так же, как в браузере, за исключением того, что он сохраняет только постоянные идентификаторы сеанса, с помощью которых вам нужно будет проходить аутентификацию RememberMe=true , например:

 var response = client.Post(new Authenticate {
    provider = "credentials",
    UserName = ...,
    Password = ...,
    RememberMe = true,
});
 

Который сохранит сеанс аутентифицированного пользователя в ss-pid постоянном файле cookie в контейнере CookieContainer HttpWebRequest и будет отправляться при каждом последующем запросе.

Вы можете установить свои собственные постоянные файлы cookie в OnAuthenticated from authService с помощью:

 var httpRes = authService.Request.Response;
httpRes.SetPermanentCookie(cookieName, cookieValue);
 

Является ли экземпляр моего производного класса CredentialsAuthProvider потокобезопасным?

Нет, для аутентификации каждого запроса используется один и тот же экземпляр AuthProvider singleton, поэтому вы не можете поддерживать какие-либо сохраненные переменные в самом экземпляре и должны будете удалить:

 //private AppUser user = null; //Instance variables are not ThreadSafe
 

Если вы хотите передавать элементы и получать к ним доступ по всему конвейеру запросов, вы можете сохранить их в IRequest.Items словаре, например:

 authService.Request.Items["AppUser"] = user;