oidc-client-js 总是重定向到登录页面

oidc-client-js always redirect to login page

我正在做一个项目,在 React SPA 上设置 OIDC 身份验证(带有 PKCE 的授权码)。 我正在使用 oidc-client-js 库。 我的代码工作正常,但在通过身份验证后,我再次被重定向到登录模式。 我查看了 React 路由器端,但似乎并非如此。我在想一个异步问题,但我似乎无法摆脱它。你能帮帮我吗?

提前致谢

我的配置

const userManager = new UserManager({
authority: identityProvider,
client_id: window.REACT_APP_CLIENT_ID,
response_type: 'code',
redirect_uri: 'http://localhost:3000/auth-callback',
scope: 'openid',
loadUserInfo: false,
revokeAccessTokenOnSignout: true,
filterProtocolClaims: true,
monitorSession: true,
metadata: {
    issuer: identityProvider,
    jwks_uri: `${identityProvider}/pf/JWKS`,
    end_session_endpoint: `${identityProvider}/idp/startSLO.ping`,
    authorization_endpoint: `${identityProvider}/as/authorization.oauth2`,
    token_endpoint: `${identityProvider}/as/token.oauth2`,
    userinfo_endpoint: `${identityProvider}/idp/userinfo.openid`,
    revocation_endpoint: `${identityProvider}/as/revoke_token.oauth2`,
    introspection_endpoint: `${identityProvider}/as/introspect.oauth2`
}

})

我的 AuthProvider

import React, { useEffect, useState } from 'react'

import PropTypes from 'prop-types'

import IdentityProvider from './bo-authentication/context/IdentityProvider'
import useCompleteAuthentication from './useCompleteAuthentication'
import useStartAuthentication from './useStartAuthentication'

const AuthProvider = ({ children }) => {
const [ready, setReady] = useState(false)

useStartAuthentication()
const boAuthentication = useCompleteAuthentication()
console.log(boAuthentication)

useEffect(() => {
    setReady(boAuthentication.token !== undefined)
}, [boAuthentication.token])

if (!ready) return null

return <IdentityProvider value={boAuthentication}>{children}</IdentityProvider>
}

AuthProvider.propTypes = { children: PropTypes.node }

export default AuthProvider

我的服务

export const login = async () => {
await userManager
    .signinRedirect({ redirectUri: window.location.href })
    .then(() => {
        console.log(`User login successful`)
    })
    .catch((error) => console.error(`An error occur during user login flow ${error}`))
}

export const completeAuthentication = once(
async (updater: UserAuthenticationUpdater = () => undefined): Promise<void> => {
    await userManager
        .signinRedirectCallback()
        .then((user: User | null) => {
            if (!user?.access_token) {
                console.warn('The identity provider have not provide the access token')
            } else {
                const userAuthentication = getUserAuthentication(user)
                updater(userAuthentication)
                const millisecondsBeforeExpiration = getMillisecondsBeforeExpiration(
                    userAuthentication.exp as number
                )
                console.log(`The time before refresh token is ${millisecondsBeforeExpiration}`)
            }
        })
        .catch(() => console.error('An error occur during the handle callback from the identity provider'))
}

)

挂钩

import { useContext, useEffect, useState } from 'react'
import { completeAuthentication } from '..'
import AuthenticationContext from '../context/AuthenticationContext'
import { UserAuthentication } from '../model/userAuthentication'

const useBoAuthentication = (): UserAuthentication => {
const authenticationContextValue = useContext(AuthenticationContext)

const [authenticationContext, setAuthenticationContext] = useState<UserAuthentication>(authenticationContextValue)

useEffect(() => {
    if (authenticationContextValue.authenticated) return
    completeAuthentication(setAuthenticationContext)
}, [authenticationContextValue.authenticated])

return authenticationContext

}

导出默认 useBoAuthentication

挂钩

import { useContext, useEffect } from 'react'
import AuthenticationContext from '../context/AuthenticationContext'
import { login } from '../index'

const useStartAuthentication = () => {
const authenticationContextValue = useContext(AuthenticationContext)

useEffect(() => {
    if (authenticationContextValue.authenticated) return
    login()
}, [authenticationContextValue.authenticated])
}

export default useStartAuthentication

您需要根据是否 userManager.getUser returns 对调用 signInRedirect 的时间进行更严格的控制。我将从这种方法开始:

  • 当页面加载时,将登录状态呈现为屏幕上的标签:true 或 false
  • 使用临时登录按钮触发登录重定向,而不是在 useEffect 中自动执行

一旦可靠,您就可以放回 onLoad 自动重定向。如果有帮助,这里是 some code of mine 对比 - 您也可以 运行 这个代码示例非常容易。

当我在 userManager 实例中检查用户时它起作用了。我认为我在 hooks 级别对 authenticated 的验证就足够了。

非常感谢您的效率和反应。