在React js应用中使用keyclock注销用户的问题



我在React js应用程序中使用Keycloak实现身份验证。

我使用React上下文来管理全局状态,在这种情况下是KeycloackContext中的keycloackValueauthenticated

案例:

  1. 应用程序第一次运行时,应用程序检查keycloackValueauthenticated。初始状态为nullfalse
  2. 如果keycloackValueauthenticatednullfalse,应用程序将初始化keycloak登录页面(通过调用KeycloackContext中的keycloak.init)。
  3. 如果keycloackValueauthenticatednot nulltrue(意味着用户通过keycloak成功登录),那么应用程序将渲染MyApp.js中的所有组件。
  4. 如果用户点击Header组件中的log out button,应用会将keycloackValueauthenticated设置为null,false也会调用keycloak注销用户。之后,调用keycloak登录页面。

问题:

我使用keycloak成功登录。然后,应用程序成功渲染了MyApp.js中的所有组件。

问题是当我点击Header.js中的log out button时,keycloackValueauthenticated被成功设置为nullfalse, keycloak也成功注销。然后应用程序刷新自己并渲染MyApp.js中的所有组件(应用程序没有调用keycloak登录页面)。

代码:

index.js

import React from "react";
import ReactDOM from "react-dom";
import MyApp from './my/App'
import { KeycloackContextProvider } from "./my/contexts/KeycloackContext"

ReactDOM.render(
<KeycloackContextProvider>
<MyApp/>
</KeycloackContextProvider>,
document.getElementById("root")
);

KeycloackContext.js

import React, { createContext, useState, useEffect } from 'react'
// KEYCLOACK
import Keycloak from 'keycloak-js'
const KeycloackContext = createContext()
const KeycloackContextProvider = (props) => {
const [ keycloackValue, setKeycloackValue ] = useState(null)
const [ authenticated, setAuthenticated ] = useState(false)
const setKeycloack = () => {
const keycloak = Keycloak({
realm: process.env.REACT_APP_WULING_KEYCLOAK_REALM,
url: process.env.REACT_APP_WULING_KEYCLOAK_URL,
clientId: process.env.REACT_APP_WULING_KEYCLOAK_CLIENTID,
})
keycloak.init({
onLoad: 'login-required', 
checkLoginIframe: false,
}).then(authenticated => {
setKeycloackValue(keycloak)
setAuthenticated(authenticated)
})
}
const logout = () => {
setKeycloack(null)
setAuthenticated(false)
keycloackValue.logout()
}
useEffect(() => {
setKeycloack()
}, [])
return (
<KeycloackContext.Provider
value={{
keycloackValue,
authenticated,
logout
}}
>
{props['children']}
</KeycloackContext.Provider>
)
}
export { KeycloackContextProvider, KeycloackContext }

MyApp.js

import React, { useContext } from 'react'
import {BrowserRouter as Router, Switch, Route, Redirect } from 'react-router-dom'
import Header from './components/Header/Header'
import Tab from './components/Tab/Tab'
// CONTEXTS
import { KeycloackContext } from './contexts/KeycloackContext'
import Device from './pages/Device/Device'
import Stock from './pages/Stock/Stock'
const MyApp = () => {
const { keycloackValue, authenticated } = useContext(KeycloackContext)
return (
(keycloackValue && authenticated) &&
<div className='app-root'>
<Router>
<Header/>
<Tab/>
<Redirect from='/' to='/device'/>
<Switch>
<Route exact path='/device'>
<Device/>
</Route>
<Route exact path='/stock'>
<Stock/>
</Route>
</Switch>
</Router>
</div>
)
}
export default MyApp

Header.js

import React, { useContext } from 'react'
// CONTEXTS
import { KeycloackContext } from '../../contexts/KeycloackContext'
const Header = () => {
const { logout } = useContext(KeycloackContext)
return (
<div className='logout-popup-root'>
<p className='logout-popup-username'>Username</p>
<p className='logout-popup-email'>username@gmail.com</p>
<div className='logout-popup-divider'></div>
<div 
className='logout-popup-logout-button'
onClick={() => logout()}
>
Log Out
</div>
</div>
)
}
export default Header

相关的依赖关系:

"keycloak-js": "^15.0.0",
"react": "16.12.0",
"react-dom": "16.12.0",
"react-router-dom": "5.1.2",
"react-scripts": "3.2.0",

注意:

  1. 我昨天尝试在另一个应用程序中使用此代码。该应用程序很好(一切都按照我想要的方式运行)。我不知道为什么这次代码没有像以前的应用程序那样运行。
  2. 如果这个问题不够清楚,请让我知道。我会尽快更新。

更新:

  1. 在之前的应用(昨天的应用)中,如果我点击退出按钮,应用会刷新一次(从keycloak),出现keycloak登录页面。
  2. 在这个app(今天的app)中,如果我点击注销按钮,app会刷新三次(来自keycloak), keycloak识别用户已通过认证(keycloackValueauthenticated分别是not nulltrue), keycloak登录页面没有出现。

经过几天的尝试和调试,我终于找到了解决方案。

只需注释或删除KeycloackContext.js中的checkLoginIframe: false。它修复了登出问题。

Keycloack.js

import React, { createContext, useState, useEffect } from 'react'
// KEYCLOACK
import Keycloak from 'keycloak-js'
const KeycloackContext = createContext()
const KeycloackContextProvider = (props) => {
const [ keycloackValue, setKeycloackValue ] = useState(null)
const [ authenticated, setAuthenticated ] = useState(false)
const setKeycloack = () => {
const keycloak = Keycloak({
realm: process.env.REACT_APP_WULING_KEYCLOAK_REALM,
url: process.env.REACT_APP_WULING_KEYCLOAK_URL,
clientId: process.env.REACT_APP_WULING_KEYCLOAK_CLIENTID,
})
keycloak.init({
onLoad: 'login-required', 
// checkLoginIframe: false, // remove checkLoginIframe here
}).then(authenticated => {
setKeycloackValue(keycloak)
setAuthenticated(authenticated)
})
}
const logout = () => {
setKeycloack(null)
setAuthenticated(false)
keycloackValue.logout()
}
useEffect(() => {
setKeycloack()
}, [])
return (
<KeycloackContext.Provider
value={{
keycloackValue,
authenticated,
logout
}}
>
{props['children']}
</KeycloackContext.Provider>
)
}
export { KeycloackContextProvider, KeycloackContext }

最新更新