我们正在使用Okta进行身份验证。当应用程序部署在CentOS OS刀片上时,非活动用户注销并立即重新登录。当在本地主机上测试应用程序时,这种行为可以在超时小于60秒的情况下重现。超时大于60秒导致成功注销。当我意识到在服务器上5分钟后,用户一直在注销和登录。非常令人不安,因为这不会发生在本地主机上。这里是App.js和IdleTimer实现:
export default function App() {
const [isTimeout,setIsTimeout] = useState(false);
useEffect(() => {
const timer = new IdleTimer({
timeOutInSeconds: 500,
onTimeout() {
setIsTimeout(true);
},
onExpired() {
setIsTimeout(true);
}
});
return () => {
timer.logout();
timer.cleanUp();
}
}, [isTimeout]);
if(isTimeout) {
console.log("logging out due to inactivity");
} else {
return (
<CookiesProvider>
<Router>
<div>
<Switch>
</Switch>
<FooterBar/>
</div>
</Router>
</CookiesProvider>
)}
}
//Our IdleTimer Implementation
class IdleTimer {
#timeInterval = 5000;
#setTimeOut = 300;
#fractionInSeconds = 1000;
#parseRadix = 10
constructor({ timeOutInSeconds, clearCookie = false, onTimeout, onExpired}) {
this.timeout = timeOutInSeconds;
this.onTimeout = onTimeout;
this.clearCookie = clearCookie;
const expiredTime = parseInt(sessionStorage.getItem("_expiredTime") || 0, this.#parseRadix);
if (expiredTime > 0 && expiredTime < Date.now()) {
onExpired();
return;
}
this.eventHandler = this.updateExpiredTime.bind(this);
this.tracker();
this.startInterval();
}
startInterval(){
this.updateExpiredTime();
this.interval = setInterval(()=> {
const expiredTime = parseInt(sessionStorage.getItem("_expiredTime") || 0, this.#parseRadix);
if (expiredTime < Date.now()) {
console.log("Clean Cookies: ", expiredTime+ ' = '+ Date.now())
if (this.onTimeout) {
this.onTimeout();
}
this.cleanCookies();
this.cleanUp();
this.logout();
}
}, this.#timeInterval)
}
updateExpiredTime() {
if (this.timeoutTracker) {
clearTimeout(this.timeoutTracker);
}
this.timeoutTracker = setTimeout(() => {
sessionStorage.setItem("_expiredTime", Date.now() + this.timeout * this.#fractionInSeconds);
}, this.#setTimeOut);
}
tracker() {
window.addEventListener("mousemove", this.eventHandler);
window.addEventListener("scroll", this.eventHandler);
window.addEventListener("keydown", this.eventHandler);
}
cleanUp() {
sessionStorage.removeItem("_expiredTime");
clearInterval(this.interval);
window.removeEventListener("mousemove", this.eventHandler);
window.removeEventListener("scroll", this.eventHandler);
window.removeEventListener("keydown", this.eventHandler);
window.location.reload();
window.location.href = "/";
}
cleanCookies(){
if(this.clearCookie) {
var cookies = cookies.keys();
for (var index in cookies) {
cookies.remove(cookies[index]);
}
}
}
logout = () => {
const [cookie, setCookie] = useCookies('XSRF-TOKEN');
console.log("logout");
fetch('/application/logout', {
method: 'POST', credentials: 'include',
headers: {'X-XSRF-TOKEN': cookie}
}).then(res => res.json())
.then(response => {
console.log(response);
window.location.href = response.logoutUrl + "?id_token_hint=" +
response.idToken + "&post_logout_redirect_uri=" + window.location.origin;
});
}
}
export default IdleTimer;
字符串
我能够通过设置一个小于60秒的超时来重现登录和注销。看起来发生的情况是,注销调用的响应我没有很快回来,但这是非常具有欺骗性的,因为奇迹的是,它在60秒标记处正确工作。
1条答案
按热度按时间5ssjco0h1#
因此,真实的问题是,在注销请求的头部需要有一个特定的cookie,而不是一个完整的cookie jar。这一变化做了修复:
字符串
使这个问题难以解决的是,空闲时间注销将在本地主机上的完整构建下工作,然后在生产中失败。当我使用小于30秒的超时时,我只能从生产中再现一次行为。