繁体   English   中英

在下一个 js 环境中发送到服务器之前如何处理数据?

[英]How to process data before sending to server in next js environment?

我目前正在制作一些需要身份验证的 web 站点。 我将 Next(React) 和 typescript 用于 web 开发。

我的目标是将大部分页面设置为 ServerSideRendered 或 StaticHTML。 但是我在开发的一开始就遇到了问题。

我目前正在制作登录页面,整体工作流程如下。

  1. 服务器呈现 LoginForm 包括 RSA-public-key(用于加密 email 和密码)
  2. 用户写入 email 地址和密码,然后在表单中单击“提交按钮”。
  3. 在 web 浏览器中,它将使用 RSA 公钥加密,然后通过 http 请求发送到服务器。
  4. 服务器接受它然后创建 session 和令牌然后将其发送到客户端。 (也许,我想这可以通过接收令牌并路由到下一页来实现——你也可以纠正它吗?)

我面临的问题是3 - 在获取之前加密。 因为它是服务器端渲染的,我没有放任何反应 CSR 代码。 它应该以某些方式加密。 最后我使用脚本标签使用外部脚本——将一些 js 文件放入/public/script/然后导入它并从浏览器运行它。

  1. /pages/auth/login.tsx
import React, { Component } from 'react';
import Head from 'next/head';
import { GetServerSideProps, GetServerSidePropsContext, GetServerSidePropsResult  } from 'next';
import { RSAHash } from '../../types/alias';    // RSAHash euquivalent with dtype 'string' just alias
import rsa from '../../lib/server-rsa';         // Server-side RSA encryption module

interface LogInProps {
    encryptKey: RSAHash
}

export default class LogIn extends Component<LogInProps> {
    render() {
        return (
            <>
                <Head>
                    <script type='module' src='/script/user/submitLoginForm.js' async={false}></script>
                </Head>
                <form>
                    <input id='encryptKey' type='hidden' defaultValue={this.props.encryptKey}/> {/* RSA public key */}
                    <label>Email Address :
                        <input id='email' type='email'/>
                    </label>
                    <label>Password :
                        <input id='password' type='password'/>
                    </label>
                    <button type='submit'>Login</button> {/* !!HERE!! */}
                </form>
            </>
        );
    }
}

export const getServerSideProps: GetServerSideProps = async (ctx: GetServerSidePropsContext): Promise<GetServerSidePropsResult<LogInProps>> => {
    // Put RSA public key to props for encryption on browser
    return {
        props: {
            encryptKey: rsa.getPublicKey(),
        },
    };
}
  1. /public/script/user/submitLoginForm.js
import OpenCrypto from "../library/opencrypto.js";

function submitLoginForm() {
    const email = document.getElementById('email').value;
    const password = document.getElementById('password').value;
    const key = document.getElementById('encryptKey').textContent;

    const crypt = new OpenCrypto();
    const emailCipher = crypt.rsaEncrypt(credit, email);
    const passwordCipher = crypt.rsaEncrypt(credit, sha256(password));
    // Also there are function sha256(_) which encrypt to sha256 hash -- not implemented yet-- it is implemented like opencrypto did
    console.log(`Receive data ${email} / ${password}`);
    console.log(`Got cipher`)
    console.log(emailCipher);
    console.log(passwordCipher);
    // Send POST request for login, then receive session. then proceed with web site maybe?
}
  1. /public/script/library/opencrypto.js
// Some external lightweight RSA encryption library

我想知道的是如何让浏览器在标签中运行 function submitLoginForm()

我想我可以通过添加onSubmit="submitLoginForm()"submit类型input来运行它。 (我标记为 '!!HERE!!' 的位置)但它是 typescript 并且它拒绝接受string作为onSubmit的道具。 它显示错误Type 'string' is not assignable to type '((event: FormEvent<HTMLButtonElement>) => void) | undefined'. Type 'string' is not assignable to type '((event: FormEvent<HTMLButtonElement>) => void) | undefined'. .

首先,这是运行脚本的正确方法吗? 其次,如果是这样,我该如何在 HTML 中输入run命令? 第三,归根结底,该功能是否正确? 我尽量避免使用诸如 next-auth 之类的库......(但我将使用 JWTToken 进行会话)

因为我对 Web Dev 还很陌生,所以最少的代码可能是错误的。 欣赏是否也检查。

谢谢你。

附录。 我用检查器测试了渲染页面并在下面检查。

  1. 使用getServerSideProps可以很好地呈现登录页面——这意味着 RSA pub 令牌插入得很好。
  2. 检查网络面板时,我可以看到外部脚本,它的crypto库以状态 200 接收良好,我可以从浏览器中看到代码。

我认为您应该多花点时间阅读React文档,因为您似乎还没有完全掌握这些概念。 您可以将输入字段的值保存在 state 中。 在这里查看 forms 如何在React中工作。 不需要document.getElementById ,你也可以直接在组件中执行你的 function :

export default class LogIn extends Component<LogInProps> {
  state = {
    email: "",
    password: ""
  };

  submitLoginForm(e) {
    e.preventDefault();
    const { email, password } = this.state;
    const crypt = new OpenCrypto();
    const emailCipher = crypt.rsaEncrypt(credit, email);
    const passwordCipher = crypt.rsaEncrypt(credit, sha256(password));
    // Send POST request for login, then receive session. then proceed with web site maybe?
  }

  handleChange(e) {
    const name = e.target.name;
    const value = e.target.value;

    this.setState({ [name]: value });
  }

  render() {
    return (
      <>
        <Head>
          <script type="module" src="/script/user/submitLoginForm.js" async={false}></script>
        </Head>

        <form onSubmit={this.submitLoginForm}>
          <input id="encryptKey" type="hidden" defaultValue={this.props.encryptKey} />{" "}
          {/* RSA public key */}
          <label>
            Email Address :
            <input
              name="email"
              type="email"
              value={this.state.email}
              onChange={this.handleChange}
            />
          </label>
          <label>
            Password :
            <input
              name="password"
              type="password"
              value={this.state.password}
              onChange={this.handleChange}
            />
          </label>
          <button type="submit">Login</button> {/* !!HERE!! */}
        </form>
      </>
    );
  }
}

您现在要做的就是使用fetchaxios将您的数据发送到服务器。

暂无
暂无

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

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