尝试使用 keycloak 服务器保护前端反应页面,但出现此错误 'keycloak.init(...).then is not a function'

Tryning to secure a front End react page with keycloak server but i have this error 'keycloak.init(...).then is not a function'

我正在尝试使用 keycloak 保护 React 组件,到目前为止我已经按照它所说的做了所有事情:

但最后我得到这个错误:

keycloak.init(...).then is not a function

我试过用 check-sso 替换 login-required

这是我在组件中注入的代码:

import Keycloak from 'keycloak-js';

componentDidMount() {
        const keycloak = Keycloak('./public/keycloak.json');
        keycloak.init({onLoad: 'login-required'}).then(authenticated => {
          this.setState({ keycloak: keycloak, authenticated: authenticated })
        })
    }

render(){
    if (this.state.keycloak) {
        if (this.state.authenticated)
            return (<div className="container text-dark">);
        else return (<div>Unable to authenticate!</div>)
    }
    return (<div>Initializing Keycloak...</div>);
}

请检查 keycloak.json 是否包含这些值:-

{
    "realm": "...",
    "auth-server-url": "http://...",
    "ssl-required": "none",
    "resource": "...",
    "public-client": true,
    "confidential-port": 0
} 

而不是:

const keycloak = Keycloak('./public/keycloak.json');

试试这个:

const keycloak = Keycloak('/keycloak.json');

并在初始化选项中将 promiseType 设置为 native(在您的情况下):

keycloak.init({onLoad: 'login-required', promiseType: 'native'}).then(authenticated => { this.setState({ keycloak: keycloak, authenticated: authenticated }) })

这可能对你有帮助,但它是用另一个库实现的,但你可以限制 React Routes / Component / Functions

安装@react-keycloak/web库

前置要求:keycloak-js 9.0.2 或更高版本

npm install --save keycloak-js
npm install --save @react-keycloak/web

在项目的 src 文件夹中创建一个 keycloak.js 文件,其中包含以下内容以根据需要设置 Keycloak 实例。

设置 Keycloak 实例

import Keycloak from 'keycloak-js'
const keycloakConfig = {
  url: 'http://localhost:8080/auth', 
  realm: 'Demo', 
  clientId: 'react-app'
}
const keycloak = new Keycloak(keycloakConfig);
export default keycloak

然后将您的应用程序包装在 KeycloakProvider 中并将 keycloak 实例作为 prop

传递
import React from 'react';
import { KeycloakProvider } from '@react-keycloak/web'
import keycloak from './keycloak'
import AppRouter from './routes'

const App = () => {
  return (
    <KeycloakProvider keycloak={keycloak}>
      <AppRouter/>
    </KeycloakProvider>
  )
}

正如您在 AppRouter 组件中看到的那样,useKeycloak 在没有第一个参数的情况下使用,因为我们不需要使用该 keycloak 实例对象。但是正在使用第二个 initialized 参数,因为 PrivateRoute 正在使用 keycloak 实例,并且 keycloak 对象需要在 PrivateRoute 初始化时可用,这意味着直到 keycloak 初始化路由无法返回

import { useKeycloak } from '@react-keycloak/web';

import React from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';

import Menu from '../components/Menu';
import HomePage from '../pages/HomePage';
import { PrivateRoute } from '../utilities/PrivateRoute';
import ProtectedPage from '../pages/ProtectedPage';


export const AppRouter = () => {
    const [, initialized] = useKeycloak();
    if (!initialized) {
        return <h3>Loading ... !!!</h3>;
    }
    return (<>
        <Menu />
        <BrowserRouter>
            <Switch>
                <Route exact path="/" component={HomePage} />
                <PrivateRoute roles={['RealmAdmin']} path="/protected" component={ProtectedPage} />
            </Switch>
        </BrowserRouter>
    </>
    );
};

使用以下内容在项目的 src/utilities 文件夹中创建一个 PrivateRoute.js 文件。

import { useKeycloak } from '@react-keycloak/web';
import React from 'react';
import { Redirect, Route } from 'react-router-dom';


export function PrivateRoute({ component: Component, roles, ...rest }) {
  const [keycloak] = useKeycloak();

  const isAutherized = (roles) => {
    if (keycloak && roles) {
        return roles.some(r => {
            const realm =  keycloak.hasRealmRole(r);
            const resource = keycloak.hasResourceRole(r);
            return realm || resource;
        });
    }
    return false;
   }

   return (
      <Route
        {...rest}
        render={props => {
            return isAutherized(roles)
                ? <Component {...props} />
                : <Redirect to={{ pathname: '/', }} />
        }}
      />
    )
}

让我们看看如何使用 Keycloak 来限制 Components/Functions。

import { useKeycloak } from '@react-keycloak/web';




    export default function AuthorizedFunction(roles) {
        const [keycloak, initialized] = useKeycloak();

        const isAutherized = () => {
            if (keycloak && roles) {
                return roles.some(r => {
                    const realm =  keycloak.hasRealmRole(r);
                    const resource = keycloak.hasResourceRole(r);
                    return realm || resource;
                });
            }
            return false;
        }

        return isAutherized();
    }

此外,还有另一种使用包装器组件进行限制的方法,如下例所示。 (带包装器组件)

https://medium.com/@cagline/authenticate-and-authorize-react-routes-component-with-keycloak-666e85662636

Keycloak 现在在 keycloak.init() 被触发时使用 .success() 用于已解决的 promise 和 .error() 用于拒绝的 promise

const keycloak = Keycloak({
            "clientId": "...",
            "realm": "...",
            "url": "...",
            "ssl-required": "...",
          
            "credentials": {
                "secret": "...1"
            },
            "enable-cors": true,
            "public-client": true,
            "confidential-port": 0

        });
        keycloak.init({ onLoad: 'login-required' }).success(authenticated => {
            this.setState({ keycloak, authenticated: authenticated },loadData)
        })