Vue+Springbootでインターフェースシグネチャを実装するためのサンプルコード

Vue+Springbootでインターフェースシグネチャを実装するためのサンプルコード

1. 実装のアイデア

インターフェース署名の目的は、リクエストパラメータが改ざんされていないか、リクエストされたデータがタイムアウトしていないか、データが繰り返し送信されていないかなどを確認することです。

インターフェース署名図

クライアントがリクエストを送信すると、合意された署名方法に従って次のパラメータに署名し、パラメータと署名を一緒にサーバーに送信します。

1. リクエストヘッダー部分(ヘッダー)
AppID: 呼び出し元ごとに異なる appID が割り当てられます。
noce: 繰り返しの送信を防ぐためのリクエストのシリアル番号。
タイムスタンプ: リクエストのタイムスタンプ。リクエストがタイムアウトしたかどうかを確認するために使用されます。

2. データ部分
パス: パス内のパラメータに従って、すべてのキー = 値のペアを連結します。
クエリ: すべてのキー=値のペアを連結します。
フォーム: すべてのキー=値のペアを連結する
本文: すべてのキー=値に従って連結された Json。文字列の場合、文字列全体が文字列として連結されます。

サイン

サーバーはハンドオーバー要求を送信した後、受信した「要求ヘッダー部分」と「データ部分」のパラメータも結合します。クライアントが送信した署名が正しいかどうかが検証されます。

2. コードの実装

クライアント (Vue) は、まず RSA 暗号化、復号化、署名、検証機能を実装するために「jsrsasign」ライブラリをインストールする必要があります。
公式アドレス: http://kjur.github.io/jsrsasign/
次のコマンドを実行します。

npm インストール jsrsasign -save

インストールが完了したら、sign.jsをパッケージ化します。

'jsrsasign' から {KJUR、KEYUTIL、hex2b64、b64tohex} をインポートします。

// 署名アルゴリズム const ALGORITHM = 'SHA256withRSA'

// 秘密鍵署名 const RSA_SIGN = (privateKey, src) => {
    const 署名 = 新しい KJUR.crypto.Signature({'alg': ALGORITHM})
    // キーを解析するには const priKey = KEYUTIL.getKey(privateKey) 
    署名.init(priKey)
    // 署名するプレーンテキストを渡す signature.updateString(src) 
    定数 a = 署名.sign()
    // base64 に変換して返す return hex2b64(a) 
}
// 公開鍵検証 const RSA_VERIFY_SIGN = (publicKey, src, data) => {
    const signature = 新しい KJUR.crypto.Signature({'alg': ALGORITHM, 'prvkeypem': publicKey})
    署名.updateString(ソース) 
    署名を返す。検証(b64tohex(データ))
}

輸出 {
    RSA_SIGN、
    RSA_VERIFY_SIGN
}

クライアント (Vue) は sign.js を使用して署名し、署名を検証します。

const src = '私はテスト文字列2です'

const publicKey = '-----公開鍵の開始-----\n' +
            'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC35wxzdTzseajkYL06hEKBCEJu\n' +
            'JQ/nySId2oTnsxbLiSTEjpAESSbML1lqkKaIwjrSFZzyLMH6DirsoEQcATqqoCDU\n' +
            '/H9QNVb5jMSAxxdQusQkTWz6k07bEuy1ppVjpGxNi8o2OGNd+lwPC/hOSDR7lpfm\n' +
            'aXLIjEwKSXzil7YAHQIDAQAB\n' +
            '-----公開鍵終了-----'

const privateKey = '-----秘密鍵の開始-----\n' +
            'MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBALfnDHN1POx5qORg\n' +
            'vTqEQoEIQm4lD+fJIh3ahOezFsuJJMSOkARJJswvWWqQpojCOtIVnPIswfoOKuyg\n' +
            'RBwBOqqgINT8f1A1VvmMxIDHF1C6xCRNbPqTTtsS7LWmlWOkbE2LyjY4Y136XA8L\n' +
            '+E5INHuWl+ZpcsiMTApJfOKXtgAdAgMBAAECgYB2PAcGSC7mPoW2ZvfiIlx7hurm\n' +
            '0885D1hu5yohqUOTklXgRWQUTU+zYRHU8LERJgcZQKoKDXqdIPS584Q2mRe0uZMr\n' +
            'vaiaBVEnHQreUJUQ8UN12pPUdBHDZvOk3L7/fZHk6A8uy5e09p2rsn+Vfki3zijp\n' +
            '7Pd758HMtjuiHBb2QQJBAOuN6jdWBr/zb7KwM9N/cD1jJd6snOTNsLazH/Z3Yt0T\n' +
            'jlsFmRJ6rIt/+jaLKG6YTR8SFyW5LIQTbreeQHPw4FECQQDH3Wpd/mBMMcgpxLZ0\n' +
            'F5p1ieza+VA5fbxkQ0hdubEP26B6YwhkTB/xMSOwEjmUI57kfgOTvub36/peb8rI\n' +
            'JdwNAkB3fzwlrGeqMzYkIU15avomuki46TqCvHJ8jOyXHUOzQbuDI5jfDgrAjkEC\n' +
            'MKBnUq41J/lEMueJbU5KqmaqKrWxAkAyexlHnl1iQVymOBpBXkjUET8y26/IpZp0\n' +
            '1I2tpp4zPCzfXK4c7yFOQTQbX68NXKXgXne21Ivv6Ll3KtNUFEPtAkBcx5iWU430\n' +
            '0/s6218/enaa8jgdqw8Iyirnt07uKabQXqNnvbPYCgpeswEcSvQqMVZVKOaMrjKO\n' +
            'G319Es83iq/m\n' +
            '-----秘密鍵終了-----\n'


console.log('プレーンテキスト:', src)
定数データ = RSA_SIGN(秘密鍵、src)
console.log('署名された結果:', データ)

const res = RSA_VERIFY_SIGN(公開鍵、ソース、データ)
console.log('署名検証結果:', res)

サーバー (Spring Boot) はリクエストを受信した後、データと署名を検証する必要があります。

まず、依存関係である hutool ツールキットを導入します。Hutool は Java ツールキットであり、単なるツールキットです。コードの各行を簡素化し、すべてのメソッドを削減し、Java 言語を「使いやすく」するのに役立ちます。

公式サイト: https://www.hutool.cn/

pom.xml の下に次の構成を追加します。

<依存関係>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <バージョン>5.3.5</バージョン>
</依存関係>

サーバー (Spring boot) は、まずクライアント (Vue) から要求されたデータを取得する必要があります。前述のように、リクエスト データには「リクエスト ヘッダー部分」と「データ部分」の 2 つの部分があります。したがって、上記 2 つの部分を取得するにはインターセプターを構成する必要があります。

インターセプター (MyInterceptor.java) を構成します。コードは次のようになります。

lombok.extern.slf4j.Slf4j をインポートします。
org.springframework.beans.factory.annotation.Value をインポートします。
org.springframework.stereotype.Component をインポートします。
org.springframework.util.StreamUtils をインポートします。
org.springframework.web.servlet.HandlerInterceptor をインポートします。

javax.servlet.http.HttpServletRequest をインポートします。
javax.servlet.http.HttpServletResponse をインポートします。

翻訳者
@成分
パブリッククラス MyInterceptor は HandlerInterceptor を実装します {

    @オーバーライド
    public boolean preHandle(HttpServletRequest リクエスト、HttpServletResponse レスポンス、オブジェクト ハンドラ) 例外をスローします {
        //リクエストパラメータを取得する String queryString = request.getQueryString();
        log.info("リクエストパラメータ:{}", queryString);

        // ヘッダーを取得する
        log.info("キー:{}",request.getHeader("タイムスタンプ"));

        MyHttpServletRequestWrapper は、リクエストをラッパーに追加します。
        //リクエスト本文を取得する
        byte[] bodyBytes = StreamUtils.copyToByteArray(myRequestWrapper.getInputStream());
        文字列本体 = 新しい文字列(bodyBytes、request.getCharacterEncoding());

        log.info("リクエスト本文: {}", body);

        true を返します。
    }
}

「リクエスト ボディ」を取得する場合、「HttpServletRequest」は 1 回しか読み取れないため、インターセプターが読み取った後、後続のコントローラーは読み取り時に空になります。そのため、HttpServletRequestWrapper を書き換える必要があります。

org.springframework.util.StreamUtils をインポートします。

javax.servlet.ReadListener をインポートします。
javax.servlet.ServletInputStream をインポートします。
javax.servlet.http.HttpServletRequest をインポートします。
javax.servlet.http.HttpServletRequestWrapper をインポートします。
java.io.* をインポートします。


パブリッククラス MyHttpServletRequestWrapper は HttpServletRequestWrapper を拡張します {

    /**
     * キャッシュされたHTTPボディ
     */
    プライベートbyte[]本体;

    パブリック MyHttpServletRequestWrapper(HttpServletRequest リクエスト) は IOException をスローします {
        super(リクエスト);
        本文 = StreamUtils.copyToByteArray(request.getInputStream());
    }

    @オーバーライド
    パブリックServletInputStream getInputStream()はIOExceptionをスローします{
        入力ストリーム bodyStream = 新しい ByteArrayInputStream(body);
        新しいServletInputStream()を返す{

            @オーバーライド
            パブリックint read() はIOExceptionをスローします {
                bodyStream.read() を返します。
            }

            @オーバーライド
            パブリックブール値isFinished() {
                false を返します。
            }

            @オーバーライド
            パブリックブール値isReady() {
                true を返します。
            }

            @オーバーライド
            パブリック void setReadListener(ReadListener readListener) {

            }
        };
    }

    @オーバーライド
    パブリック BufferedReader getReader() は IOException をスローします {
        新しい BufferedReader(新しい InputStreamReader(getInputStream())) を返します。
    }
}

その後、フィルターを作成し、「ServletRequest」を「MyHttpServletRequestWrapper」に置き換える必要があります。コードは次のとおりです。

lombok.extern.slf4j.Slf4j をインポートします。

javax.servlet.* をインポートします。
javax.servlet.http.HttpServletRequest をインポートします。
java.io.IOException をインポートします。

翻訳者
パブリッククラスRepeatedlyReadFilterはFilterを実装します{
    @オーバーライド
    パブリック void init(FilterConfig filterConfig) は ServletException をスローします {

    }

    @オーバーライド
    パブリック void doFilter(ServletRequest servletRequest、ServletResponse servletResponse、FilterChain filterChain) は IOException、ServletException をスローします {
        ServletRequest リクエストラッパー = null;
        if (servletRequest インスタンス HttpServletRequest) {
            リクエストラッパー = 新しい MyHttpServletRequestWrapper((HttpServletRequest) servletRequest);
        }
        リクエストラッパーが null の場合
            フィルターチェーン.doFilter(サーブレットリクエスト、サーブレットレスポンス);
        } それ以外 {
            filterChain.doFilter(リクエストラッパー、サーブレットレスポンス);
        }

    }

    @オーバーライド
    パブリックvoidの破棄(){

    }
}

次に、カスタム構成 CorsConfig.java を作成し、構成にフィルターとインターセプターを追加します。

com.xyf.interceptor.MyInterceptor をインポートします。
com.xyf.interceptor.RepeatedlyReadFilter をインポートします。
org.springframework.beans.factory.annotation.Autowired をインポートします。
org.springframework.boot.web.servlet.FilterRegistrationBean をインポートします。
org.springframework.context.annotation.Bean をインポートします。
org.springframework.context.annotation.Configuration をインポートします。
org.springframework.web.servlet.config.annotation.InterceptorRegistry をインポートします。
org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport をインポートします。

@構成
パブリッククラスCorsConfigはWebMvcConfigurationSupportを拡張します{

    プライベート MyInterceptor myInterceptor;

    オートワイヤード
    パブリック CorsConfig (MyInterceptor myInterceptor) {
        this.myInterceptor = myInterceptor;
    }

    //フィルターを登録@Bean
    パブリック FilterRegistrationBean<繰り返し読み取りフィルタ> 繰り返し読み取りフィルタ() {
        FilterRegistrationBean 登録 = 新しい FilterRegistrationBean();
        繰り返し読み取りフィルターを繰り返し読み取りフィルター = 新しい繰り返し読み取りフィルター();
        登録.setFilter(繰り返し読み取りフィルタ)
        登録.addUrlPatterns("/*");
        返品登録;
    }


    @オーバーライド
    保護された void addInterceptors(InterceptorRegistry レジストリ) {
        // addPathPatterns はインターセプトする必要がある名前空間を追加します。
        // excludePathPatterns は除外インターセプト名前空間を追加します registry.addInterceptor(myInterceptor).addPathPatterns("/**");
        //.excludePathPatterns("/api/sys/login")
    }

}

最後に、署名の検証を完了します。コードは次のとおりです。

cn.hutool.core.codec.Base64 をインポートします。
cn.hutool.crypto.SecureUtil をインポートします。
cn.hutool.crypto.asymmetric.Sign をインポートします。
cn.hutool.crypto.asymmetric.SignAlgorithm をインポートします。


byte[] data = "私はテスト文字列2です".getBytes();
        文字列公開キー = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC35wxzdTzseajkYL06hEKBCEJu\n" +
                「JQ/nySId2oTnsxbLiSTEjpAESSbML1lqkKaIwjrSFZzyLMH6DirsoEQcATqqoCDU\n」+
                "/H9QNVb5jMSAxxdQusQkTWz6k07bEuy1ppVjpGxNi8o2OGNd+lwPC/hOSDR7lpfm\n" +
                「aXLIjEwKSXzil7YAHQIDAQAB」;

署名 sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA,null,publicKey);

//クライアントから送信された署名文字列 qm = "IhY3LNuFn0isud1Pk6BL2eJV3Jl/UzDCYsdG9CYyJwOGqwnzStsv/RiYLnVP4bnQh1NRPMazY6ux/5Zz5Ypcx6RI5W1p5BDbO2afuIZX7x/eIu5utwsanhbxEfvm3XOsyuTbnMDh6BQUrXb4gUz9qgt9IXWjQdqnQRRv3ywzWcA=";
byte[] signed = Base64.decode(qm);

//署名を検証する boolean verify = sign.verify(data, signed);

3. 公開鍵と秘密鍵の生成

いくつかのウェブサイトを通じてオンラインで公開鍵と秘密鍵を生成できます: https://www.bejson.com/enc/rsa/

bejson はオンラインで公開鍵と秘密鍵を生成します

4. その他の問題

クライアントが署名を追加し、サーバーが署名を検証するためです。したがって、署名の追加と検証の方法は一貫している必要があり、そうでないと署名を検証できません。 Vue と Java では署名ツール ライブラリが異なるため、使用する前に必ずテストしてください。

これで、Vue+Springboot のインターフェースシグネチャを実装するサンプルコードに関するこの記事は終了です。Springboot インターフェースシグネチャの関連コンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • SpringBoot インターフェース呼び出し後の 404 問題の解決方法
  • SpringBoot ビジュアル インターフェース開発ツール magic-api の使用に関する簡単なチュートリアル
  • Spring Bootインターフェースパラメータの暗号化と復号化の実装方法
  • Spring Bootインターフェースの電流制限の一般的なアルゴリズムと特性
  • アノテーションとインターフェースを介して Springboot でスケジュールされたタスクを作成する詳細な説明
  • Java Springbootインターフェースはすぐに使い始めることができ、30分ですぐに使い始めることができます

<<:  Hadoop を使用せずに Linux 環境に Spark のスタンドアロン バージョンをインストールする方法

>>:  MySQL 5.7 と Mac 上の MySql の詳細なインストール図をダウンロードする

推薦する

MySQL5.7+ MySQL Workbenchのインストールと設定方法のグラフィックチュートリアル(MAC)

この記事では、主にMACオペレーティングシステムでのMySQL5.7とMySQLWorkbenchの...

docker nginxコンテナの起動とローカルへのマウントの詳細な説明

まず、nginx コンテナ内の構造:コンテナを入力します: docker exec -it b511...

MySQL データベースの操作とデータ型

目次1. データベース操作1.1 データベースの表示1.2 データベースを作成する1.3 データベー...

Vueルーティングルーターの詳細な説明

目次ルーティングプラグインをモジュール方式で使用するルートの使用宣言型ナビゲーションプログラムによる...

無効と読み取り専用で入力を読み取り専用に設定する

読み取り専用入力を実現するには、無効と読み取り専用の 2 つの方法があります。当然、どちらの結果も読...

Linuxはバイナリモードを使用してmysqlをインストールします

この記事では、LinuxにバイナリモードでMySQLをインストールする具体的な手順を参考までに紹介し...

Alibaba Cloud CentOS 7 に MySQL 8.0.13 をインストールする方法

1. MySQL インストール パッケージをダウンロードします(ここにはコツがあります。おそらく、こ...

MySQL カーソルの概念と使用法の詳細な説明

この記事では、例を使用して MySQL カーソルの概念と使用方法を説明します。ご参考までに、詳細は以...

Unicode 署名 BOM の詳細な説明

Unicode 署名 BOM - BOM とは何ですか? BOM は Byte Order Mark...

MySQL における大規模オブジェクトのマルチバージョン同時実行制御の詳細な説明

MySQL 8.0: InnoDB のラージ オブジェクトに対する MVCCこの記事では、MySQL...

はじめに: HTML の基本的なタグと属性の簡単な紹介

HTML はタグと属性で構成されており、これらを組み合わせてブラウザにページの表示方法を指示します。...

MySQLユーザー管理操作例の分析

この記事では、MySQL ユーザー管理操作について説明します。ご参考までに、詳細は以下の通りです。こ...

JS の querySelector メソッドと getElementById メソッドの違い

目次1. 概要1.1 querySelector() と querySelectorAll() の使...

JS ES 新機能テンプレート文字列

目次1. テンプレート文字列とは何ですか? 2. 複数行のテンプレート文字列2.1 式付きテンプレー...

Vue における $router と $route の違いの詳細な説明

通常、vue プロジェクトではルーティングを使用します。vue-router は vue.js の公...