Frontend SDK Design and Integration for a Unified Permission System
This article explains how to design a unified permission system's frontend SDK, detailing its core APIs, integration methods for standard React and Umi projects, dynamic route generation, and menu/button level permission controls, accompanied by practical code examples.
Building on previous design and backend implementation articles, this final piece introduces the frontend SDK for a unified permission system, which provides login , getUserPermssion , and a special routerFilter API to fetch user data and filter menu trees.
For ordinary React projects, the SDK is invoked before the app mounts using commonLogin to obtain userInfo and permissionInfo , after which routerFilter can be applied to the route configuration:
import { commonLogin } from '@zz-common/zz-permission';
(async () => {
const { userInfo = {}, permissionInfo = {} } = await commonLogin({ appCode: '' });
const { resources } = permissionInfo;
render();
})(); import { routerFilter } from '@zz-common/zz-permission';
const router = [];
const newRouter = routerFilter(router);For Umi projects, install the access plugin, then modify src/app.ts to call commonLogin and store the permission list in initialState :
// app.ts
import { commonLogin } from '@zz-common/zz-permission';
export async function getInitialState() {
const { permissionInfo, userInfo } = await commonLogin({ appCode: '' });
const { resources = [] } = permissionInfo;
return { userInfo, permissionList: resources };
}Create src/access.ts to map route access fields to permission codes, generating an accessList object used by Umi's Access component.
import routes from '../config/routes';
function findRouteAccessList() { /* ... */ }
export default (initialState = {}) => {
const { permissionList = [] } = initialState;
const accessList = permissionList.reduce((acc, item) => { acc[item.code] = true; return acc; }, {});
const routePermissions = findRouteAccessList();
routePermissions.forEach(key => { if (!(key in accessList)) accessList[key] = false; });
return accessList;
};A CheckAuth component wraps buttons to hide them when the corresponding permission code is false:
import React from 'react';
import { useAccess, Access } from 'umi';
const CheckAuth = ({ children, permissionCode }) => {
const access = useAccess();
const accessible = access[permissionCode];
return
{children}
;
};
export default CheckAuth;Dynamic permission‑based menus are achieved by fetching a permission tree from the backend and merging it with local routes. Helper functions in dynamicRoute.ts (e.g., renderRoutes , getRedirectRoute ) flatten local routes, render components, and build a combined route list.
export function renderRoutes(sourceRoutes = [], localRoutes = []) { /* ... */ }
export function getRedirectRoute(routes = [], cataloguePath = '/') { /* ... */ }The patchRoutes runtime hook replaces the original route configuration with the generated routes, adds a redirect route, and appends a 404 fallback.
export function patchRoutes({ routes }) {
const localRoutes = routes[0].routes[0].routes;
const mainRoutes = renderRoutes(authRoutes, localRoutes);
const redirectRoute = getRedirectRoute(mainRoutes);
if (redirectRoute) mainRoutes.unshift(redirectRoute);
mainRoutes.push({ component: NotFound });
routes[0].routes[0].routes = mainRoutes;
}In summary, the SDK centralizes permission handling for menus, routes, and button visibility; it must be invoked before rendering, and when combined with the company’s Umi scaffolding, it enables a streamlined, permission‑aware front‑end architecture.
Zhuanzhuan Tech
A platform for Zhuanzhuan R&D and industry peers to learn and exchange technology, regularly sharing frontline experience and cutting‑edge topics. We welcome practical discussions and sharing; contact waterystone with any questions.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.