Skip to main content

5 带有授权的前端组件

在前面的章节中,我们学习了如何使用权限框架保护插件的后端 API 路由。 大多数返回一些要显示的数据的路由(例如我们的GET /todos路由)无需对前端进行额外更改,因为后端只需返回一个空列表或一个404不过,对于触发突变操作的用户界面元素,通常的做法是在用户没有权限时隐藏或禁用它们。

以我们的待办事项列表应用程序中的 "添加 "按钮为例,当用户点击该按钮时,前端会生成一个POST请求/todos如果用户试图添加一个未授权的待办事项,在他们执行操作并出现错误之前,他们根本无法知道这一点。 这样的用户体验很差。 我们可以禁用添加按钮来做得更好。

注意:将前端组件置于授权后不能取代将后端路由置于授权后。 前端的授权检查应作为相应后端授权的 "补充",以改善用户体验。 如果不将后端路由置于授权后,即使禁用了相应的前端组件,恶意行为者仍可向路由发送请求。

使用`使用权限

让我们先添加我们需要的软件包:

$ yarn workspace @internal/plugin-todo-list \
add @backstage/plugin-permission-react @internal/plugin-todo-list-common

让我们在plugins/todo-list/src/components/TodoListPage/TodoListPage.tsx:

plugins/todo-list/src/components/TodoListPage/TodoListPage.tsx
import {
alertApiRef,
discoveryApiRef,
fetchApiRef,
useApi,
} from '@backstage/core-plugin-api';
import { usePermission } from '@backstage/plugin-permission-react';
import { todoListCreatePermission } from '@internal/plugin-todo-list-common';

function AddTodo({ onAdd }: { onAdd: (title: string) => any }) {
const title = useRef('');
const { loading: loadingPermission, allowed: canAddTodo } = usePermission({
permission: todoListCreatePermission,
});

return (
<>
<Typography variant="body1">Add todo</Typography>
<Box
component="span"
alignItems="flex-end"
display="flex"
flexDirection="row"
>
<TextField
placeholder="Write something here..."
onChange={e => (title.current = e.target.value)}
/>
<Button variant="contained" onClick={handleAdd}>
Add
</Button>
{!loadingPermission && (
<Button
disabled={!canAddTodo}
variant="contained"
onClick={() => onAdd(title.current)}
>
Add
</Button>
)}
</Box>
</>
);
}

在这里,我们使用使用权限与权限策略通信,并接收关于该用户是否有权创建待办事项列表项的决定。

就是这么简单!让我们改变策略,测试禁用按钮:

packages/backend/src/plugins/permission.ts
if (isPermission(request.permission, todoListCreatePermission)) {
return {
result: AuthorizeResult.ALLOW,
result: AuthorizeResult.DENY,
};
}

现在你应该看到,你无法从前台创建待办事项!

使用RequirePermission(要求权限

提供禁用状态可以向用户发出有用的信号,但在某些情况下,隐藏元素可能更受欢迎。要求权限:

plugins/todo-list/src/components/TodoListPage/TodoListPage.tsx
import {
alertApiRef,
discoveryApiRef,
fetchApiRef,
useApi,
} from '@backstage/core-plugin-api';
import { usePermission } from '@backstage/plugin-permission-react';
import { RequirePermission } from '@backstage/plugin-permission-react';
import { todoListCreatePermission } from '@internal/plugin-todo-list-common';

export const TodoListPage = () => {
// ..
<Grid container spacing={3} direction="column">
<Grid item>
<AddTodo onAdd={handleAdd} />
</Grid>
<RequirePermission permission={todoListCreatePermission} errorPage={<></>}>
<Grid item>
<AddTodo onAdd={handleAdd} />
</Grid>
</RequirePermission>
<Grid item>
<TodoList key={key} onEdit={setEdit} />
</Grid>
</Grid>;
};

function AddTodo({ onAdd }: { onAdd: (title: string) => any }) {
const title = useRef('');
const { loading: loadingPermission, allowed: canAddTodo } = usePermission({
permission: todoListCreatePermission,
});

return (
<>
<Typography variant="body1">Add todo</Typography>
<Box
component="span"
alignItems="flex-end"
display="flex"
flexDirection="row"
>
<TextField
placeholder="Write something here..."
onChange={e => (title.current = e.target.value)}
/>
{!loadingPermission && (
<Button
disabled={!canAddTodo}
variant="contained"
onClick={() => onAdd(title.current)}
>
Add
</Button>
)}
<Button variant="contained" onClick={() => onAdd(title.current)}>
Add
</Button>
</Box>
</>
);
}

现在,您会发现用于添加待办事项列表项的组件根本不会呈现。 成功!

您还可以使用RequirePermission来阻止对路由的访问。 以下是在packages/app/src/App.tsx:

packages/app/src/App.tsx
import { RequirePermission } from '@backstage/plugin-permission-react';
import { todoListCreatePermission } from '@internal/plugin-todo-list-common';

const routes = (
<FlatRoutes>
<Route path="/search" element={<SearchPage />}>
{searchPage}
</Route>
<Route path="/settings" element={<UserSettingsPage />} />
<Route path="/todo-list" element={
{/* You might want to create a "read" permission for this, we are just using this one as an example */}
<RequirePermission permission={todoListCreatePermission}>
<TodoListPage />
</RequirePermission>
{/* highlight-add-end */}}
{/* ... */}
</Route>
</FlatRoutes>
);

现在,如果您尝试导航到https://localhost:3000/todo-list如果您没有权限,您将看到一个错误页面。