Сохраняя традицию , отвечая на ваш собственный вопрос на этот вопрос.
TL; DR - это желаемое поведение в Safari.Единственный способ обойти это - привести пользователя на веб-страницу, размещенную на домене API (myapi.com
в вопросе), и установить оттуда cookie-файл - что угодно, вы можете написать небольшое стихотворение в cookie-файле, если хотите.
После того, как это будет сделано, домен будет добавлен в «белый список», и Safari будет любезен с вами и будет устанавливать ваши cookie-файлы при любом последующем звонке, даже если он поступает от клиентов из разных доменов.
Этоподразумевает, что вы можете оставить свою логику аутентификации нетронутой и просто ввести тупую конечную точку, которая установит для вас «начальный» файл cookie.В моем приложении на Ruby это выглядит следующим образом:
class ServiceController < ActionController::Base
def seed_cookie
cookies[:s] = {value: 42, expires: 1.week, httponly: true} # value can be anything at all
render plain: "Checking your browser"
end
end
Клиентская сторона, вы можете проверить , если браузер, выполняющий запрос, Safari и отложить логику входа в систему после того, как появилось это уродливое всплывающее окноБыло открыто:
const doLogin = () => {
if(/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {
const seedCookie = window.open(`http://myapi.com/seed_cookie`, "s", "width=1, height=1, bottom=0, left=0, toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no")
setTimeout(() => {
seedCookie.close();
// your login logic;
}, 500);
} else {
// your login logic;
}
}
ОБНОВЛЕНИЕ : Приведенное выше решение отлично работает для входа пользователя, т.е. оно корректно «заносит в белый список» домен API для текущего сеанса браузера.
К сожалению, однако, похоже, что пользователь, обновляющий страницу, вернет браузер в исходное состояние, когда сторонние куки для домена API заблокированы.
Я нашел хороший способ справиться со случаемобновление окна должно обнаружить его в javascript при загрузке страницы и перенаправить пользователя на конечную точку API, которая делает то же, что и выше, просто чтобы затем перенаправить пользователя на исходный URL, на который он переходил (страница обновляется):
if(performance.navigation.type == 1 && /^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {
window.location.replace(`http://myapi.com/redirect_me`);
}
Чтобы усложнить ситуацию, оказывается, что Safari не будет хранить куки, если HTTP-статус ответа 30X (повторнонепосредственный).Таким образом, Safari-дружественное решение включает в себя настройку файлов cookie и возврат ответа 200 вместе с JS-фрагментом, который будет обрабатывать перенаправление в браузере.
В моем случае, являясь бэкендом приложения Rails, вот какэта конечная точка выглядит так:
def redirect_me
cookies[:s] = {value: 42, expires: 1.week, httponly: true}
render body: "<html><head><script>window.location.replace('#{request.referer}');</script></head></html>", status: 200, content_type: 'text/html'
end