React Microfrontends:如何将身份验证和其他信息从一个前端应用程序传递到另一个前端程序



我正在开发一个系统,该系统由不同的后端微服务和一些相互链接的微前端应用程序组成(所有这些应用程序都是用ReactJS构建的)。

以下是我的用例(为了简洁起见,我只是在这里列出前端应用程序,并省略了后端服务):

我们有以下应用程序:

  1. https://id.example.com-前端处理用户登录、配置文件管理,并向用户提供一个面板,其中包含指向他/她可以访问的模块的链接。该面板具有链接,如SettingsTicketsCampaignsAnalytics
  2. 我们使用OAuth2服务器进行身份验证,它为我们提供了access_tokenrefresh_token。一旦获得这些令牌,就会显示仪表板屏幕
  3. 现在,用户单击Tickets,它必须重定向到https://tickets.example.com

当重定向发生时,我需要能够传递身份验证信息(从https://id.example.com)到Tickets应用程序(位于https://tickets.example.com),以便tickets应用程序可以在加载时验证令牌。

我知道我可以将用户重定向到https://tickets.example.com?token=<auth_token>&refresh_token=<refresh_token>,但我不确定这是否是一种安全的方式

尝试使用localStorage,但它们似乎也与主机相连,我无法从tickets.example.com中的id.example.comlocalStorage中获得值

此外,微前端是单独部署的,每个前端都有自己的子域(tickets.example.com、campaigns.example.com等),我知道可以使用single-spa和Module federation等框架将它们加载到Container应用程序中。但这不是我喜欢的。

总之,我想知道如何在任何两个前端应用程序之间传递信息(如身份验证令牌、会话信息等)?

谢谢,Sriram

我也是微前端的新手。,这就是我解决这个问题的方法

这只适用于父<>通信,不适用于兄弟

让我解释一下:当我想将数据从子应用程序传递给父应用程序时,我会调度操作发布到容器(publish_container),当父应用程序发送数据时,我调度操作订阅容器(subscribe_container)操作以减少同一应用程序。

我有两个应用程序,一个是主应用程序(Container),另一个是微应用程序(MicroApp)。

MicroApp应用程序:

webpack.config.js

new ModuleFederationPlugin({
name: 'MicroApp',
filename: 'remoteEntry.js',
exposes: {
'./MicroAppApp': './src/bootstrap',
},
})

pubsub.js

export const pubsub = () => {
let cb;
const publishToContainer = (_cb) => (cb = _cb);
const containerReducer = (state = 0, action) => {
switch (action.type) {
case 'SUBSCRIBE_CONTAINER':
return action.payload; // Do something with the payload
case 'PUBLISH_CONTAINER':
cb && cb(action.payload);
return action.payload; // This is not required
default:
return state;
}
};
const subscribeToContainer = (store) => (state) => {
store.dispatch({
type: 'SUBSCRIBE_CONTAINER',
payload: state,
});
};
return {
containerReducer,
publishToContainer,
subscribeToContainer,
};
};

bootstrap.js

export * from './App';

App.js

const { containerReducer, publishToContainer, subscribeToContainer } = pubsub();
const reducers = () => {
return combineReducers({
containerReducer,
});
};
const store = createStore(reducers());
export const publish = publishToContainer; // this will be used by Container app
export const subscribe = subscribeToContainer(store); // this will be used by Container app

容器应用程序:

webpack.config.js

new ModuleFederationPlugin({
name: 'container',
remotes: {
MicroApp: 'MicroApp@http://localhost:3000/remoteEntry.js',
},
})

App.js

import { subscribe, publish } from 'MicroApp/MicroAppApp';
// Note: publish and subscribe function can be used as redux action similar like MicroApp
const microAppReducer = (state, action) => {
switch (action.type) {
case 'SUBSCRIBE_MICRO_APP':
return action.payload; // Do something with the payload
case 'PUBLISH_MICRO_APP':
publish && publish(action.payload);
// return action.payload; // This is not required
default:
return state;
}
}
subscribe((payload) =>  store.dispatch({ type: 'SUBSCRIBE_MICRO_APP', payload })); // Micro Front end will send data here

您可以使用redux进行状态管理,并与其他微前端应用程序共享。您可以将您的身份验证数据存储在主应用程序redux状态中,并与其他应用程序共享。但为此,您需要在Container应用程序中加载它们。

Redux代码拆分还可以帮助您通过拆分Redux reducer将其他应用程序的数据共享到主应用程序,并使用主应用程序加载。

你的情况不同。所以您可以使用react路由器的Link组件。

示例:

<Link 
to={{ 
pathname: "https://tickets.example.com",
search: "?token=<auth_token>&refresh_token=<refresh_token>",
state: { foo: 'foo' }
}} 
target="_blank"
>
Tickets
</Link>

state不适用于外部链接,因此需要在search中传递数据。至少有一个选项可以通过两个不同的域传递数据。

您也可以尝试跨域存储。允许跨域共享本地存储。

示例链接:Github

我很难确切地理解您想要设置什么,但以下是我学到的关于微格式化中的auth的一些东西。

为了让系统A使用系统B,假设系统B需要身份验证,系统A需要复制系统B正在做的事情。例如,如果系统B正在localStorage中搜索一个名为"example"的jwt,那么您必须确保jwt存储在localStorage中,密钥为"example",这样当您将系统B拉入系统a时,它将自动检测到它已通过身份验证。

在主登录页面中,您希望在多个后端服务之间聚合身份验证,因为如果您登录,然后单击第一个导航项,则会立即重定向到另一个系统的SSO页面,这将是一种糟糕的用户体验。实现这一点的方法是,如果您能够对正在使用的任何OAuth服务器进行密码授予调用。因此,如果您登录到系统A,系统A需要进行自己的身份验证,同时为系统B进行密码授予调用,然后它需要将系统B的令牌存储在localStorage中。然后,当你接入并使用系统B时,它会发现它已经过身份验证。

您不想为包含的每个系统重写整个身份验证,因为这是一项繁重的工作,而且不可维护。

然而,如果你这样做,你就进入了一个永远不会结束的兔子洞,因为很快你就会想包括一个无法进行密码授予调用的系统,或者一个系统正在使用php 3中的遗留会话/cookie设置,管理层说你无法更改。

除此之外,您可以考虑聚合此身份验证服务器端,而不是客户端,在那里您需要创建一个API,您可以在登录时调用该API,以便一次检索所有不同系统的所有令牌。但是,您的客户端可能仍然需要将所有令牌存储在localStorage中,并将其传递给您所包含的任何系统。

域不应该影响localStorage,因为您不应该首先重定向用户。域应该保持不变,在系统之间重定向用户将是一种糟糕的用户体验。相反,您希望将系统B作为系统A上的另一个导航项包括在内,并使其看起来像是同一个系统,而无需重定向。为了做到这一点,您需要在编译时(从他们的repo)或运行时(从其实时服务器)从他们的服务器中提取系统B的html,为此,您需要启用他们的CORS,并将您的域列入白名单。然后,您可以完全引入该系统,也就是说,将系统B呈现为具有自己路由的react应用程序中的新react组件。您甚至可以将该应用程序的路由器用作主路由器的子路由器。

微线程可能会变得非常复杂,非常快,身份验证只是这个兔子洞里的一件事,没有两个系统以相同的方式工作,所以希望它们能为您提供一些想法。

在您的auth-micro前端设置一个隐藏的iframe,以便为您的子域加载一个页面和令牌。在iframe中加载的页面将具有作为查询参数的令牌,并将其设置在localStorage中。

相关内容

最新更新