У меня есть сетевое базовое веб-приложение, ориентированное на API и проходящее аутентификацию на Identity Server (также как веб-приложение). Поскольку приложение основано на веб-сервере, у меня проблема с хранением токена доступа от Identity Server, который требуется приложению в каждом запросе (в заголовке) для связи с API. Идеальный ход: пользователь запускает приложение и получает запрос на ввод своего номера телефона (для получения кода OTP и аутентификации), когда отправляет номер телефона. Identity Server с некоторыми внешними провайдерами отправляет код OTP пользователю, и теперь пользователю предлагается ввести его. ОТП код. После успешной отправки OTP-кода Identity Server проверяет его и предоставляет клиенту токен доступа. И это тот момент, когда начинается проблема.
Сначала я попытался сохранить токен доступа в синглтоне, который после проверки otp сохраняет (в некотором словаре) токен доступа, связанный с номером телефона в качестве ключа. Но проблема заключается в том, что приложение основано на веб-сервере, и при работе на сервере необязательно, чтобы каждый пользователь имел экземпляр своего приложения на сервере, поэтому синглтон бесполезен, скорее всего, у нас в примере 3-4 приложение работает на 20 пользователей и в этой ситуации несколько пользователей используют один и тот же синглтон!
Затем я погуглил и обнаружил, что лучше всего хранить токен доступа или некоторые ключи от него для этого токена в сеансе браузера или в файле cookie документа. Таким образом, теперь приложение работает так, что после проверки OTP-кода телефонный номер пользователя и токены доступа хранятся в коллекции Dictionary (теперь все больше пользователей используют одну коллекцию, потому что синглтон бесполезен для этого), где ключ - номер телефона, а токен доступа - значение, затем javascript запускает и устанавливает номер телефона пользователя в cookie (в каждом запросе), и теперь при создании заголовка Bearer я просто читаю cookie из текущего запроса и с этого номера телефона беру токен доступа из коллекции.
Таким образом, это решение очень плохое, потому что все (после входа в систему), что вам нужно, чтобы получить токен доступа, это изменить номер телефона в cookie, и если вам повезет и сопоставить существующий номер в коллекции, вы получите токен доступа и легко получите доступ к API .
Ниже приведен метод, который вызывается в каждом запросе для получения токена доступа из коллекции, в которую после проверки otp был добавлен токен доступа с номером телефона.
public async Task<string> GetAccessToken()
{
string phoneNumber = GetUserPhoneNumber();
if (string.IsNullOrEmpty(phoneNumber))
throw new ArgumentNullException(nameof(phoneNumber));
if (_usersTokenStore == null || _usersTokenStore.Count == 0)
throw new NotImplementedException(nameof(_usersTokenStore));
var refSingleUser = new SingleUserTokenStore();
bool userHaveAccessToken = _usersTokenStore.TryGetValue(phoneNumber, out refSingleUser);
if (!userHaveAccessToken)
throw new Exception($"User with {phoneNumber} not authorized.");
if (refSingleUser.IsTimeToRefreshToken)
return await RefreshAndGetAccessToken();
return refSingleUser.AccessToken;
}
private string GetUserPhoneNumber()
{
if (_httpContext == null)
throw new ArgumentException(nameof(_httpContext));
var phoneNumberCookie = _httpContext.HttpContext.Request.Cookies.Where(c => c.Key == "phone_number").FirstOrDefault();
if (phoneNumberCookie.Value == null || phoneNumberCookie.Key == null)
return null;
return phoneNumberCookie.Value;
}