简体   繁体   English

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

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

I'm currently making some web site which need authentication.我目前正在制作一些需要身份验证的 web 站点。 I use Next(React) and typescript for web dev.我将 Next(React) 和 typescript 用于 web 开发。

My goal is to make most of pages as ServerSideRendered or StaticHTML.我的目标是将大部分页面设置为 ServerSideRendered 或 StaticHTML。 But I faced problem at the very beginning of development.但是我在开发的一开始就遇到了问题。

I'm currently making login page and overall work flow is below.我目前正在制作登录页面,整体工作流程如下。

  1. Server renders LoginForm include RSA-public-key (for encrypting email and password)服务器呈现 LoginForm 包括 RSA-public-key(用于加密 email 和密码)
  2. User writes email address and password and click 'Submit Button' in form.用户写入 email 地址和密码,然后在表单中单击“提交按钮”。
  3. In the web browser, it will be encrypted with RSA public key then sent to server via http request.在 web 浏览器中,它将使用 RSA 公钥加密,然后通过 http 请求发送到服务器。
  4. The server accept it then create session and tokens then send it into client.服务器接受它然后创建 session 和令牌然后将其发送到客户端。 (Maybe, I guess it can be achieved by receiving token and routing to next page -- Can you correct it too?) (也许,我想这可以通过接收令牌并路由到下一页来实现——你也可以纠正它吗?)

The problem I faced with is on 3 -- encrypt before fetch.我面临的问题是3 - 在获取之前加密。 Since it is server side rendered and I didn't put any of react CSR code.因为它是服务器端渲染的,我没有放任何反应 CSR 代码。 It should be encrypted with certain ways.它应该以某些方式加密。 And I ends up with use external script using script tag --put some js files into /public/script/ then import it and run it from browser.最后我使用脚本标签使用外部脚本——将一些 js 文件放入/public/script/然后导入它并从浏览器运行它。

  1. /pages/auth/login.tsx /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 /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 /public/script/library/opencrypto.js
// Some external lightweight RSA encryption library

What I want to know is how can I make browser run function submitLoginForm() in tag.我想知道的是如何让浏览器在标签中运行 function submitLoginForm()

I think I can run it by adding onSubmit="submitLoginForm()" to submit type input .我想我可以通过添加onSubmit="submitLoginForm()"submit类型input来运行它。 (Position I marked as '!!HERE!!') But it is typescript and it deny to accept string as prop of onSubmit . (我标记为 '!!HERE!!' 的位置)但它是 typescript 并且它拒绝接受string作为onSubmit的道具。 It shows error Type 'string' is not assignable to type '((event: FormEvent<HTMLButtonElement>) => void) | undefined'.它显示错误Type 'string' is not assignable to type '((event: FormEvent<HTMLButtonElement>) => void) | undefined'. Type 'string' is not assignable to type '((event: FormEvent<HTMLButtonElement>) => void) | undefined'. . .

First, Is this right way to run script?首先,这是运行脚本的正确方法吗? Second, If so, how can I put run command in that HTML?其次,如果是这样,我该如何在 HTML 中输入run命令? Third, Ultimately, is it right approach for the feature?第三,归根结底,该功能是否正确? I try to avoid using libraries like next-auth and so on... (But I'm gonna use JWTToken for session)我尽量避免使用诸如 next-auth 之类的库......(但我将使用 JWTToken 进行会话)

Least of codes can be wrong since I'm quite new to Web Dev.因为我对 Web Dev 还很陌生,所以最少的代码可能是错误的。 Appreciate if check that too.欣赏是否也检查。

Thank you.谢谢你。

Appendix.附录。 I tested rendered page with inspector and checked below.我用检查器测试了渲染页面并在下面检查。

  1. Login page renders well with getServerSideProps -- means RSA pub token is inserted well.使用getServerSideProps可以很好地呈现登录页面——这意味着 RSA pub 令牌插入得很好。
  2. When checking network panel, I can see external script and it's crypto library is received well with status 200 and I can see the code from browser.检查网络面板时,我可以看到外部脚本,它的crypto库以状态 200 接收良好,我可以从浏览器中看到代码。

I think you should read through the React docs some more time, because it seems like you haven't fully grasped the concepts.我认为您应该多花点时间阅读React文档,因为您似乎还没有完全掌握这些概念。 You can save the values of the input fields in the state.您可以将输入字段的值保存在 state 中。 See here how forms work in React .在这里查看 forms 如何在React中工作。 No need for document.getElementById , also you can execute your function directly in the component:不需要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>
      </>
    );
  }
}

All you would have to do now is use fetch or axios to send your data to the server.您现在要做的就是使用fetchaxios将您的数据发送到服务器。

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

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