在Prod环境中,非活动用户的注销不起作用:React前端,Spring后端

yzuktlbb  于 2023-11-21  发布在  React
关注(0)|答案(1)|浏览(192)

我们正在使用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秒标记处正确工作。

5ssjco0h

5ssjco0h1#

因此,真实的问题是,在注销请求的头部需要有一个特定的cookie,而不是一个完整的cookie jar。这一变化做了修复:

headers: {'X-XSRF-TOKEN': cookie['XSRF-TOKEN']}

字符串
使这个问题难以解决的是,空闲时间注销将在本地主机上的完整构建下工作,然后在生产中失败。当我使用小于30秒的超时时,我只能从生产中再现一次行为。

相关问题