尝试使用 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 组件,到目前为止我已经按照它所说的做了所有事情:
- 我已经通过 NPM 安装了 KEycloak 软件包
- 我已将 keycloak.json 放入 public 文件夹
- 我修改了我的组件,以便在路由页面时安装它
但最后我得到这个错误:
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();
}
此外,还有另一种使用包装器组件进行限制的方法,如下例所示。 (带包装器组件)
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)
})
我正在尝试使用 keycloak 保护 React 组件,到目前为止我已经按照它所说的做了所有事情:
- 我已经通过 NPM 安装了 KEycloak 软件包
- 我已将 keycloak.json 放入 public 文件夹
- 我修改了我的组件,以便在路由页面时安装它
但最后我得到这个错误:
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();
}
此外,还有另一种使用包装器组件进行限制的方法,如下例所示。 (带包装器组件)
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)
})