在 React js 应用程序中使用 Keycloak 注销用户时出现问题
Problem in log out user using Keycloack in React js app
我正在 React js 应用程序中使用 Keycloak 实现身份验证。
我正在使用 React Context 来管理全局状态,在这种情况下是 KeycloackContext
中的 keycloackValue
和 authenticated
。
案例:
- 当应用首次 运行 时,应用会检查
keycloackValue
和 authenticated
。它们的初始状态是 null
和 false
.
- 如果
keycloackValue
和authenticated
是null
和false
,应用程序将初始化keycloak登录页面(通过在[=17中调用keycloak.init
=]).
- 如果
keycloackValue
和authenticated
是not null
和true
(意味着用户通过keycloak成功登录),那么应用程序将呈现[中的所有组件=32=].
- 如果用户点击
Header
组件中的 log out button
,应用会将 keycloackValue
和 authenticated
设置为 null
和 false
还调用 keycloak 来注销用户。之后调用keycloak登录页面。
问题:
我使用keycloak成功登录了。然后应用程序成功渲染了 MyApp.js
.
中的所有组件
问题是当我点击Header.js
中的log out button
时,keycloackValue
和authenticated
被成功设置为null
和false
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",
注:
- 我昨天尝试在另一个应用程序中使用此代码。该应用程序很好(一切如我所愿 运行)。不知道为什么这次代码不像之前的app那样运行
- 如果这个问题不够清楚,请告诉我。我会尽快更新的。
更新:
- 在以前的应用程序(昨天的应用程序)中,如果我单击注销按钮,应用程序将刷新一次(来自 keycloak)并出现 keycloak 登录页面。
- 在这个应用程序(今天的应用程序)中,如果我单击注销按钮,应用程序将刷新三次(来自 keycloak),keycloak 识别用户已通过身份验证(
keycloackValue
和 authenticated
是 not null
和 true
), 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 }
我正在 React js 应用程序中使用 Keycloak 实现身份验证。
我正在使用 React Context 来管理全局状态,在这种情况下是 KeycloackContext
中的 keycloackValue
和 authenticated
。
案例:
- 当应用首次 运行 时,应用会检查
keycloackValue
和authenticated
。它们的初始状态是null
和false
. - 如果
keycloackValue
和authenticated
是null
和false
,应用程序将初始化keycloak登录页面(通过在[=17中调用keycloak.init
=]). - 如果
keycloackValue
和authenticated
是not null
和true
(意味着用户通过keycloak成功登录),那么应用程序将呈现[中的所有组件=32=]. - 如果用户点击
Header
组件中的log out button
,应用会将keycloackValue
和authenticated
设置为null
和false
还调用 keycloak 来注销用户。之后调用keycloak登录页面。
问题:
我使用keycloak成功登录了。然后应用程序成功渲染了 MyApp.js
.
问题是当我点击Header.js
中的log out button
时,keycloackValue
和authenticated
被成功设置为null
和false
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",
注:
- 我昨天尝试在另一个应用程序中使用此代码。该应用程序很好(一切如我所愿 运行)。不知道为什么这次代码不像之前的app那样运行
- 如果这个问题不够清楚,请告诉我。我会尽快更新的。
更新:
- 在以前的应用程序(昨天的应用程序)中,如果我单击注销按钮,应用程序将刷新一次(来自 keycloak)并出现 keycloak 登录页面。
- 在这个应用程序(今天的应用程序)中,如果我单击注销按钮,应用程序将刷新三次(来自 keycloak),keycloak 识别用户已通过身份验证(
keycloackValue
和authenticated
是not null
和true
), 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 }