基于Umi前端扫码登录,验证码输入

396 阅读2分钟

1.需要使用iframe引入二维码

            <iframe
                className={styles.scanStyle}
                scrolling="no"
                height="360px"
                width="100%"
                src={scanUrl}
                frameBorder="0"
              />
      这里的scanUrl就是二维码链接,是从后端获取的

2.每次进入页面需要获取二维码和验证码,需要对是否超时进行判断,根据后端发送的消息,请求用户信息

  
      const getScanUrl = () => { //获取二维码
        dispatch({
          type: 'login/getScanUrl',
          payload: {},
        });
      };

      const getUserInfo = (code) => { //获取用户信息
        dispatch({
          type: 'login/loginOn',
          payload: { code },
        });
      };

      const isLoginEvent = (e) => { //监听后端信息事件
        const code = e.data && e.data.code;
        if (code) {
          // 根据 code 去获取用户信息
          getUserInfo(code);
        }
      };
      
      const getCode = () => { //获取验证码
        let imgUrl = `api/quality/user/getCode?key=${new Date().getTime()}`;
        setImgCode(imgUrl);
      };

      useEffect(() => {
        const { overtime } = history.location.query;
        overtime ? message.warning('请登录') : '';
        getScanUrl();
        getCode();
        window.addEventListener('message', isLoginEvent);
        return () => {
          window.removeEventListener('message', isLoginEvent);
        };
      }, []);

3.监听验证码的键盘事件,表单验证,提交信息

      const adminLogin = (params) => { //管理员登录
        dispatch({
          type: 'login/adminLogin',
          payload: { ...params },
        });
      };
      const onPressEnter = (e) => { //键盘回车事件
        if (e.keyCode === 13) {
          e.preventDefault();
          e.stopPropagation();
          submitForm();
        }
      };
      
      const submitForm = () => {
        form.validateFields().then((res) => { //表单验证后提交
          let key = imgCode.split('=')[1];
          adminLogin({
            ...res,
            account: rsaEncrypt(res.account), //rsaEncrypt加密
            password: rsaEncrypt(res.password),
            code: res.code.text,
            key,
          });
        });
      };
      
      const validatorCode = (_, value) => { //表单验证
        if (value?.text) {
          return Promise.resolve();
        }
        return Promise.reject(new Error('请输入验证码'));
      };
      
      useEffect(() => {
        document.removeEventListener('keyup', onPressEnter);
        if (imgCode) {
          document.addEventListener('keyup', onPressEnter);
        }
        return () => {
          document.removeEventListener('keyup', onPressEnter);
        };
      }, [imgCode]);

4.前端整体结构

  const callback = (key) => {
    if (key === 'scanCode') {
      getScanUrl();
    }
    setLoginFlag(key);
  };

  return (
    <div className={styles.wrap}>
      <div className={styles.login}>
        <Tabs
          onChange={callback}
          accessKey={loginFlag}
        >
          <TabPane
            key="scanCode"
            tab={[
              <img
                key={scanCodeAcive}
                src={loginFlag === 'scanCode' ? scanCodeAcive : scanCode}
              />,
              <span
                style={{ fontSize: 16, marginLeft: 8 }}
                key="name1"
                className={styles.tabHeader}
              >
                扫码登陆
              </span>,
            ]}
          >
            <h3>请用浙政钉扫码登录</h3>
            <div className={styles.scanBox}>
              <iframe
                className={styles.scanStyle}
                scrolling="no"
                height="360px"
                width="100%"
                src={scanUrl}
                frameBorder="0"
              />
            </div>
          </TabPane>
          <TabPane
            key="password"
            tab={[
              <img
                key={loginActive}
                src={loginFlag === 'password' ? loginActive : login}
              />,
              <span
                key="name3"
                style={{ fontSize: 16, marginLeft: 8 }}
                className={styles.tabHeader}
              >
                管理员登录
              </span>,
            ]}
          >
            <h3>请输入超级管理员账号</h3>
            <Form
              style={{ marginTop: 55 }}
              name="login"
              autoComplete="off"
              form={form}
            >
              <Form.Item
                name="account"
                rules={[
                  {
                    required: true,
                    message: '请输入用户名',
                  },
                ]}
              >
                <Input size="large" placeholder="请输入用户名" />
              </Form.Item>

              <Form.Item
                name="password"
                rules={[
                  {
                    required: true,
                    message: '请输入密码',
                  },
                ]}
              >
                <Input.Password size="large" placeholder="请输入密码" />
              </Form.Item>
              <Form.Item
                name="code"
                rules={[
                  {
                    validator: validatorCode,
                  },
                ]}
              >
                <VerificationCode getCode={getCode} imgCode={imgCode} />
              </Form.Item>
            </Form>
            <Button
              size="large"
              onClick={submitForm}
              className={styles.loginBtn}
            >
              登录
            </Button>
          </TabPane>
        </Tabs>
      </div>
    </div>
  );

5.验证码组件

    import { useSelector, useDispatch, history } from 'umi';
    import { useEffect, useState } from 'react';
    import { Input, Tooltip } from 'antd';
    import styles from './index.less';

    const VerificationCode = ({ value = {}, onChange, getCode, imgCode }) => {
      const dispatch = useDispatch();
      const [text, setText] = useState('');

      const triggerChange = (changedValue) => {
        onChange?.({
          text,
          ...value,
          ...changedValue,
        });
      };

      const onTextChange = (e) => {
        const newText = e.target.value;
        setText(newText);
        triggerChange({
          text: newText,
        });
      };

      return (
        <div className={styles.codeStyle}>
          <Input
            type="text"
            value={value.text || text}
            onChange={onTextChange}
            placeholder="请输入验证码"
            size="large"
            style={{
              width: 200,
            }}
          />
          <Tooltip
            overlayStyle={{ fontSize: '12px' }}
            placement="bottom"
            title="看不清换一张"
          >
            <img className={styles.imgStyle} onClick={getCode} src={imgCode} />
          </Tooltip>
        </div>
      );
    };
    export default VerificationCode;

6.加密规则

    export const rsaEncrypt = (password) => {
      var encryptor = new JSEncrypt(); // 创建加密对象实例
      //之前ssl生成的公钥,复制的时候要小心不要有空格
      var pubKey = `MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwyG0Tp1Wo1nLBqi8wcQYLC6Z4Udjr9rEYmbnb
        21CVPaU1UmNXYyU3giV7ck6bhreAjEtwg9NjZ+p2xQL35WAL7ZsyFL0k+CYrRu3VqtFE0qwikyOT
        ZjujKOpREqAwzDK4UjzL9hK4ud0GCO9lPfw2ecTJyJ2GTzT0ooPHe5ljAQIDAQAB`;
      encryptor.setPublicKey(pubKey); //设置公钥
      var rsaPassWord = encryptor.encrypt(password); // 对内容进行加密
      return rsaPassWord;
    };