繁体   English   中英

在 React SharePoint WebPart 中,使用“html-react-parser”和使用“dompurify eslint-plugin-risxss”来安全地显示 HTML 之间有什么区别

[英]In React SharePoint WebPart what are the differences between using 'html-react-parser' & using 'dompurify eslint-plugin-risxss' to securely show HTML

我正在尝试构建一个 React.js SharePoint 现代 Web 部件,它具有以下功能:-

  1. 在 Web 部件设置页面内 >> 有 2 个名为“我们是谁”和“我们的价值”的字段,它们允许用户输入 HTML。

  2. Web 部件将呈现 2 个按钮“我们是谁”和“我们的价值”>> 并且当用户单击任何按钮时 >> 将显示一个弹出窗口,其中包含在第 1 步中输入的 HTML 代码

如下:-

在此处输入图片说明

但是为了能够在我的 Web 部件中将 HTML 代码呈现为富文本,我必须在 .tsx 文件中使用dangerouslySetInnerHTML的SetInnerHTML 属性。 如下:-

import * as React from 'react';
import { useId, useBoolean } from '@fluentui/react-hooks';
import {
  getTheme,
  mergeStyleSets,
  FontWeights,
  Modal,
  IIconProps,
  IStackProps,
} from '@fluentui/react';
import { IconButton, IButtonStyles } from '@fluentui/react/lib/Button';
export const MYModal2 = (myprops) => {
  const [isModalOpen, { setTrue: showModal, setFalse: hideModal }] = useBoolean(false);
  const [isPopup, setisPopup] = React.useState(true);
  const titleId = useId('title');
  React.useEffect(() => {
      showModal();
  }, [isPopup]);
  function ExitHandler() {
    hideModal();
    setisPopup(current => !current)
    myprops.handler();
  }

  return (
    <div>
      <Modal
        titleAriaId={titleId}
        isOpen={isModalOpen}
        onDismiss={ExitHandler}
        isBlocking={true}
        containerClassName={contentStyles.container}
      >
        <div className={contentStyles.header}>
          <span id={titleId}>Modal Popup</span>
          <IconButton
            styles={iconButtonStyles}
            iconProps={cancelIcon}
            ariaLabel="Close popup modal"
            onClick={ExitHandler}
          />
        </div>
        <div  className={contentStyles.body}>
        <p dangerouslySetInnerHTML={{__html:myprops.OurValue}}>
   </p>

        </div>
      </Modal>

    </div>

  );
};

const cancelIcon: IIconProps = { iconName: 'Cancel' };

const theme = getTheme();
const contentStyles = mergeStyleSets({
  container: {
    display: 'flex',
    flexFlow: 'column nowrap',
    alignItems: 'stretch',
  },
  header: [
    // eslint-disable-next-line deprecation/deprecation
    theme.fonts.xLarge,
    {
      flex: '1 1 auto',
      borderTop: '4px solid ${theme.palette.themePrimary}',
      color: theme.palette.neutralPrimary,
      display: 'flex',
      alignItems: 'center',
      fontWeight: FontWeights.semibold,
      padding: '12px 12px 14px 24px',
    },
  ],
  body: {
    flex: '4 4 auto',
    padding: '0 24px 24px 24px',
    overflowY: 'hidden',
    selectors: {
      p: { margin: '14px 0' },
      'p:first-child': { marginTop: 0 },
      'p:last-child': { marginBottom: 0 },
    },
  },
});
const stackProps: Partial<IStackProps> = {
  horizontal: true,
  tokens: { childrenGap: 40 },
  styles: { root: { marginBottom: 20 } },
};
const iconButtonStyles: Partial<IButtonStyles> = {
  root: {
    color: theme.palette.neutralPrimary,
    marginLeft: 'auto',
    marginTop: '4px',
    marginRight: '2px',
  },
  rootHovered: {
    color: theme.palette.neutralDark,
  },
};

为了保护dangerouslySetInnerHTML我执行了以下步骤:-

1- 在我的 Node.Js CMD >> 我在我的项目目录中运行这个命令:-

npm install dompurify eslint-plugin-risxss

2-然后在我上面的.tsx里面我做了以下修改:-

  • 我添加了这个 import import { sanitize } from 'dompurify';
  • 我将这个不安全的代码<p dangerouslySetInnerHTML={{__html:myprops.OurValue}}></p>替换为这个<div dangerouslySetInnerHTML={{ __html: sanitize(myprops.OurValue) }} />

所以我有以下问题:-

  1. 现在我的方法(使用sanitize(myprops.OurValue)将/应该在弹出窗口中安全地将 HTML 呈现为富文本,因为我使用的是sanitize函数,它是dompurify eslint-plugin-risxss 。但我读了另一种方法提到要在弹出窗口中安全地将 HTML 呈现为富文本,我们可以使用html-react-parser包,如下所示{parse(myprops.OurValue)} 。那么使用 'html-react-parser' & 之间有什么区别?使用“dompurify eslint-plugin-risxss”在 React Web 部件的弹出窗口中安全地将 HTML 代码呈现为富文本?

这是我的完整 Web 部件代码:-

在 MyModalPopupWebPart.ts 中:-

import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Version } from '@microsoft/sp-core-library';
import {
  IPropertyPaneConfiguration,
  PropertyPaneTextField
} from '@microsoft/sp-property-pane';
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';

import * as strings from 'MyModalPopupWebPartStrings';
import MyModalPopup from './components/MyModalPopup';
import { IMyModalPopupProps } from './components/IMyModalPopupProps';

export interface IMyModalPopupWebPartProps {
  description: string;
  WhoWeAre: string;
  OurValue:string;
}

export default class MyModalPopupWebPart extends BaseClientSideWebPart<IMyModalPopupWebPartProps> {

  public render(): void {
    const element: React.ReactElement<IMyModalPopupProps> = React.createElement(
      MyModalPopup,
      {
        description: this.properties.description,
        WhoWeAre: this.properties.WhoWeAre,
        OurValue: this.properties.OurValue
      }
    );

    ReactDom.render(element, this.domElement);
  }

  protected onDispose(): void {
    ReactDom.unmountComponentAtNode(this.domElement);
  }

  protected get dataVersion(): Version {
    return Version.parse('1.0');
  }

  protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
    return {
      pages: [
        {
          header: {
            description: strings.PropertyPaneDescription
          },
          groups: [
            {
              groupName: strings.BasicGroupName,
              groupFields: [
                PropertyPaneTextField('WhoWeAre', {
                  label: "who We Are",
    multiline: true
                }),
                PropertyPaneTextField('OurValue', {
                  label: "Our value"
                }), PropertyPaneTextField('description', {
                  label: "Description",
    multiline: true
                }),
              ]
            }
          ]
        }
      ]
    };
  }
}

在 MyModalPopup.tsx 中:-

import * as React from 'react';
import { IMyModalPopupProps } from './IMyModalPopupProps';
import { DefaultButton } from '@fluentui/react/lib/Button';
import { MYModal } from './MYModal';
import { MYModal2 } from './MYModal2';

interface IPopupState {
  showModal: string;
}

export default class MyModalPopup extends React.Component<IMyModalPopupProps, IPopupState> {
  constructor(props: IMyModalPopupProps, state: IPopupState) {
    super(props);
    this.state = {
      showModal: ''
    };
    this.handler = this.handler.bind(this);
    this.Buttonclick = this.Buttonclick.bind(this);
  }
  handler() {
    this.setState({
      showModal: ''
    })
  }
  private Buttonclick(e, whichModal) {
    e.preventDefault();

    this.setState({ showModal: whichModal });
  }
  public render(): React.ReactElement<IMyModalPopupProps> {

    const { showModal } = this.state;

    return (
      <div>

        <DefaultButton onClick={(e) => this.Buttonclick(e, 'our-value')} text="Our Value" />
        { showModal === 'our-value' && <MYModal2 OurValue={this.props.OurValue} myprops={this.state} handler={this.handler} />}

        <DefaultButton onClick={(e) => this.Buttonclick(e, 'who-we-are')} text="Who We Are" />
        { showModal === 'who-we-are' && <MYModal WhoWeAre={this.props.WhoWeAre} myprops={this.state} handler={this.handler} />}
      </div>
    );
  }
}

实际上, html-react-parser返回的是 ReactJs 对象,它的返回类型类似于React.createElement或称为 JSX 的类型。

使用DOMPurify.sanitize将返回安全的纯 HTML 元素,这些元素与html-react-parser返回的对象不同。 risxss ESLint 插件将强制您使用任何类型的 sanitize 函数或库进行 sanitizing,我在您的另一个问题中留下了一个关于如何清理字符串 HTML的答案。

最终,使用清理会更好,因为html-react-parser会将您的字符串 HTML转换为 ReactJs 对象,并进行一些微小的更改,这将是危险的,因为项目中可能有一些字符串 HTML 的脚本,这可能是有害的它只是从 HTML 标签中删除onclickonload等,但清理将删除所有可能的有害标签。 消毒也会收到配置,这意味着您可以拥有自己的消毒选项

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM