簡體   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