我们正在将Okta Sign-in Widget集成到基于React的webapp中。
var oktaSignIn = new OktaSignIn({baseUrl: baseUrl});
oktaSignIn.renderEl(...)
在第一次渲染窗口小部件时,我们可以正常工作,但在用户登录并再次注销后,webapp再次呈现登录组件并尝试再次执行renderEl
以呈现窗口小部件。这会导致抛出以下异常:
Backbone.history has already been started
我创建了this jsfiddle来演示这个问题。它只是实例化一个登录小部件两次(等待后第二次)。您可以看到第二次调用导致抛出异常。
https://jsfiddle.net/nudwcroo/6/
目前,我的解决方法是在转到登录组件时重新加载整个webapp,但这对于单个页面应用程序来说是不合需要的。
这是一个已知的问题?有没有办法在单个javascript会话中初始化登录窗口小部件两次?
由于窗口小部件每页只能实例化一次,因此最好隐藏/显示所有单页应用程序的元素。
<div id="okta-login-container"></div>
<script type="text/javascript">
var oktaSignIn = new OktaSignIn(/* config */);
oktaSignIn.renderEl(
{ el: '#okta-login-container' },
function (res) {
if (res.status === 'SUCCESS') {
// Hide element
$("#okta-login-container").hide();
}
}
);
</script>
当您创建logout()
函数时,请确保show()
元素而不是再次渲染它。
function logout() {
$('#okta-login-container').show();
// Do more logic
}
对于那些在遵循此处提供的Okta示例后遇到类似问题的人:(https://github.com/okta/samples-js-react/blob/master/custom-login/src/Login.jsx)
问题是尝试在单个页面应用程序中多次初始化窗口小部件。我通过仅在App级别初始化窗口小部件,然后在子组件安装/卸载时渲染它并从DOM中删除它来修复此问题。
例:
//App.js
class App extends Component {
constructor() {
super()
this.signIn = new OktaSignIn({...})
}
render() {
return <SignInPage widget={this.signIn} />
}
}
--
//SignInPage.js
...
componentDidMount() {
let { redirectUri } = this.state
let { widget } = this.props
widget.renderEl(
{ el: '#sign-in-widget' },
(response) => {
response.session.setCookieAndRedirect(redirectUri)
},
(error) => {
throw error;
},
);
}
componentWillUnmount() {
let { widget } = this.props
widget.remove()
}
render() {
return <div id="sign-in-widget"/></div>
}