最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

javascript - Problem in log out user using Keycloack in React js app - Stack Overflow

matteradmin4PV0评论

I'm implementing authentication using Keycloak in React js app.

I'm using React Context to manage the global states in this case are the keycloackValue and authenticated in KeycloackContext.

Cases:

  1. When the app is running the first time, the app checks for keycloackValue and authenticated. The initial state for them are null and false.
  2. If keycloackValue and authenticated are null and false, the app would initialize the keycloak login page (by calling keycloak.init in KeycloackContext).
  3. If keycloackValue and authenticated are not null and true (means that the user is successfully login through keycloak), then the app will render all ponents in MyApp.js.
  4. If the user clicks the log out button in Header ponent, the app would set keycloackValue and authenticated into null and false also call the keycloak to log out the user. After that, the keycloak login page is called.

Problem:

I successfully logged in using keycloak. Then the app successfully rendered all ponents in MyApp.js.

The problem is when I clicked the log out button in Header.js, the keycloackValue and authenticated were successfully set to null and false also the keycloak successfully logged out. Then the app refreshed itself and rendered all ponents in MyApp.js (the app didn't call the keycloak login page).

Code:

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 './ponents/Header/Header'
import Tab from './ponents/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'>[email protected]</p>
            <div className='logout-popup-divider'></div>
            <div 
                className='logout-popup-logout-button'
                onClick={() => logout()}
            >
                Log Out
            </div>
        </div>
    )
}

export default Header

Related dependencies:

"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",

Note:

  1. I tried to use this code yesterday in another app. The app was fine (everything was running as I want). I don't know why this time the code was not running as the previous app.
  2. If this question is not clear enough, please let me know. I will update is as soon as possible.

Update:

  1. In the previous app (yesterday app), if I clicked the logout button, the app would refresh one time (from keycloak) and the keycloak login page appeared.
  2. In this app (today app), if I clicked the logout button, the app would refresh three times (from keycloak), the keycloak recognized the user is authenticated (keycloackValue and authenticated are not null and true), and the keycloak login page didn't appeared.

I'm implementing authentication using Keycloak in React js app.

I'm using React Context to manage the global states in this case are the keycloackValue and authenticated in KeycloackContext.

Cases:

  1. When the app is running the first time, the app checks for keycloackValue and authenticated. The initial state for them are null and false.
  2. If keycloackValue and authenticated are null and false, the app would initialize the keycloak login page (by calling keycloak.init in KeycloackContext).
  3. If keycloackValue and authenticated are not null and true (means that the user is successfully login through keycloak), then the app will render all ponents in MyApp.js.
  4. If the user clicks the log out button in Header ponent, the app would set keycloackValue and authenticated into null and false also call the keycloak to log out the user. After that, the keycloak login page is called.

Problem:

I successfully logged in using keycloak. Then the app successfully rendered all ponents in MyApp.js.

The problem is when I clicked the log out button in Header.js, the keycloackValue and authenticated were successfully set to null and false also the keycloak successfully logged out. Then the app refreshed itself and rendered all ponents in MyApp.js (the app didn't call the keycloak login page).

Code:

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 './ponents/Header/Header'
import Tab from './ponents/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'>[email protected]</p>
            <div className='logout-popup-divider'></div>
            <div 
                className='logout-popup-logout-button'
                onClick={() => logout()}
            >
                Log Out
            </div>
        </div>
    )
}

export default Header

Related dependencies:

"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",

Note:

  1. I tried to use this code yesterday in another app. The app was fine (everything was running as I want). I don't know why this time the code was not running as the previous app.
  2. If this question is not clear enough, please let me know. I will update is as soon as possible.

Update:

  1. In the previous app (yesterday app), if I clicked the logout button, the app would refresh one time (from keycloak) and the keycloak login page appeared.
  2. In this app (today app), if I clicked the logout button, the app would refresh three times (from keycloak), the keycloak recognized the user is authenticated (keycloackValue and authenticated are not null and true), and the keycloak login page didn't appeared.
Share Improve this question edited Aug 5, 2021 at 4:13 Jabal Logian asked Aug 5, 2021 at 3:50 Jabal LogianJabal Logian 2,3606 gold badges27 silver badges55 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 3

After trying and debugging for some days, finally I found the solution.

Just ment or remove checkLoginIframe: false in KeycloackContext.js. It fix the logout problem.

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 }
Post a comment

comment list (0)

  1. No comments so far