Beispielcode zur Implementierung der Schnittstellensignatur mit Vue+Springboot

Beispielcode zur Implementierung der Schnittstellensignatur mit Vue+Springboot

1. Umsetzungsideen

Der Zweck der Schnittstellensignatur besteht darin, sicherzustellen, dass die Anforderungsparameter nicht manipuliert werden, dass keine Zeitüberschreitung bei den angeforderten Daten vorliegt, dass die Daten wiederholt übermittelt werden usw.

Schnittstellensignaturdiagramm

Wenn der Client eine Anforderung sendet, signiert er die folgenden Parameter gemäß der vereinbarten Signaturmethode und sendet dann die Parameter und die Signatur zusammen an den Server:

1. Header-Teil anfordern (Header)
AppID: Verschiedenen Anrufern werden unterschiedliche AppIDs zugewiesen.
noce: Die Seriennummer der Anfrage, um wiederholtes Senden zu verhindern.
Zeitstempel: Anforderungszeitstempel, der verwendet wird, um zu überprüfen, ob die Anforderung abgelaufen ist.

2. Datenteil
Pfad: Verketten Sie alle Schlüssel-Wert-Paare entsprechend den Parametern im Pfad.
Abfrage: Verketten Sie alle Schlüssel=Wert-Paare.
Form: Alle Schlüssel=Wert-Paare verketten
Textkörper: JSON, gemäß Schlüssel=Wert verkettet. Zeichenfolge, die gesamte Zeichenfolge wird zu einer Zeichenfolge zusammengefügt.

Zeichen

Nachdem der Server die Übergabeanforderung übermittelt hat, fügt er auch die empfangenen Parameter „Anforderungsheaderteil“ und „Datenteil“ zusammen. Anschließend wird die Richtigkeit der vom Kunden übermittelten Unterschrift überprüft.

2. Code-Implementierung

Der Client (Vue) muss zuerst die Bibliothek „jsrsasign“ installieren, um RSA-Verschlüsselungs-, Entschlüsselungs-, Signierungs- und Verifizierungsfunktionen zu implementieren.
Offizielle Adresse: http://kjur.github.io/jsrsasign/
Führen Sie den folgenden Befehl aus:

npm installiere jsrsasign -save

Nach Abschluss der Installation verpacken Sie sign.js

importiere {KJUR, KEYUTIL, hex2b64, b64tohex} aus 'jsrsasign'

// Signaturalgorithmus const ALGORITHM = 'SHA256withRSA'

// Signatur des privaten Schlüssels const RSA_SIGN = (privateKey, src) => {
    const signature = new KJUR.crypto.Signature({'alg': ALGORITHM})
    // Um ​​den Schlüssel zu analysieren const priKey = KEYUTIL.getKey(privateKey) 
    signature.init(priKey)
    // Übergeben Sie den zu signierenden Klartext signature.updateString(src) 
    const a = Signatur.sign()
    // In Base64 konvertieren und zurückgeben return hex2b64(a) 
}
// Überprüfung des öffentlichen Schlüssels const RSA_VERIFY_SIGN = (publicKey, src, data) => {
    const signature = new KJUR.crypto.Signature({'alg': ALGORITHM, 'prvkeypem': publicKey})
    Signatur.updateString(src) 
    Signatur zurückgeben.überprüfen(b64tohex(Daten))
}

exportieren {
    RSA_SIGN,
    RSA_VERIFY_SIGN
}

Der Client (Vue) verwendet sign.js, um die Signatur zu signieren und zu überprüfen.

const src = 'Ich bin eine Testzeichenfolge 2'

const publicKey = '-----BEGIN PUBLIC KEY-----\n' +
            'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC35wxzdTzseajkYL06hEKBCEJu\n' +
            'JQ/nySId2oTnsxbLiSTEjpAESSbML1lqkKaIwjrSFZzyLMH6DirsoEQcATqqoCDU\n' +
            '/H9QNVb5jMSAxxdQusQkTWz6k07bEuy1ppVjpGxNi8o2OGNd+lwPC/hOSDR7lpfm\n' +
            'aXLIjEwKSXzil7YAHQIDAQAB\n' +
            '-----ENDE DES ÖFFENTLICHEN SCHLÜSSELS-----'

const privateKey = '-----BEGIN PRIVATE KEY-----\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' +
            '-----ENDE DES PRIVATEN SCHLÜSSELS-----\n'


console.log('Klartext:', src)
const data = RSA_SIGN(privaterSchlüssel, src)
console.log('Signiertes Ergebnis:', Daten)

const res = RSA_VERIFY_SIGN(öffentlicher Schlüssel, Quelle, Daten)
console.log('Ergebnis der Signaturüberprüfung:', res)

Nachdem der Server (Spring Boot) die Anfrage erhalten hat, muss er die Daten und die Signatur überprüfen.

Stellen Sie zunächst die Abhängigkeit vor – das Hutool-Toolkit. Hutool ist ein Java-Toolkit und es ist nur ein Toolkit. Es hilft uns, jede Codezeile zu vereinfachen, jede Methode zu reduzieren und die Java-Sprache „süß“ zu machen.

Offizielle Website: https://www.hutool.cn/

Fügen Sie die folgende Konfiguration unter pom.xml hinzu:

<Abhängigkeit>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-alles</artifactId>
    <version>5.3.5</version>
</Abhängigkeit>

Der Server (Spring Boot) muss zuerst die vom Client (Vue) angeforderten Daten abrufen. Wie oben beschrieben, bestehen die Anforderungsdaten aus zwei Teilen, nämlich dem „Anforderungsheaderteil“ und dem „Datenteil“. Daher ist es notwendig, den Interceptor zu konfigurieren, um die beiden oben genannten Teile zu erhalten.

Konfigurieren Sie den Interceptor (MyInterceptor.java). Der Code lautet wie folgt:

importiere lombok.extern.slf4j.Slf4j;
importiere org.springframework.beans.factory.annotation.Value;
importiere org.springframework.stereotype.Component;
importiere org.springframework.util.StreamUtils;
importiere org.springframework.web.servlet.HandlerInterceptor;

importiere javax.servlet.http.HttpServletRequest;
importiere javax.servlet.http.HttpServletResponse;

@Slf4j
@Komponente
öffentliche Klasse MyInterceptor implementiert HandlerInterceptor {

    @Überschreiben
    public boolean preHandle(HttpServletRequest-Anforderung, HttpServletResponse-Antwort, Objekthandler) löst Exception aus {
        //Anforderungsparameter abrufen String queryString = request.getQueryString();
        log.info("Anforderungsparameter:{}", queryString);

        // Den Header abrufen
        log.info("Schlüssel:{}",request.getHeader("Zeitstempel"));

        MyHttpServletRequestWrapper myRequestWrapper = neuer MyHttpServletRequestWrapper(Anfrage);
        // Den Anforderungstext abrufen
        byte[] bodyBytes = StreamUtils.copyToByteArray(myRequestWrapper.getInputStream());
        String-Body = neuer String (bodyBytes, request.getCharacterEncoding());

        log.info("Anforderungstext: {}", body);

        gibt true zurück;
    }
}

Da „HttpServletRequest“ beim Abrufen des „Anforderungstexts“ nur einmal gelesen werden kann, ist der nachfolgende Controller nach dem Lesen durch den Interceptor beim Lesen leer. Daher müssen Sie den HttpServletRequestWrapper neu schreiben:

importiere org.springframework.util.StreamUtils;

importiere javax.servlet.ReadListener;
importiere javax.servlet.ServletInputStream;
importiere javax.servlet.http.HttpServletRequest;
importiere javax.servlet.http.HttpServletRequestWrapper;
importiere java.io.*;


öffentliche Klasse MyHttpServletRequestWrapper erweitert HttpServletRequestWrapper {

    /**
     * Der zwischengespeicherte HTTP-Text
     */
    privater Byte[]-Text;

    öffentliche MyHttpServletRequestWrapper(HttpServletRequest Anfrage) wirft IOException {
        super(Anfrage);
        body = StreamUtils.copyToByteArray(request.getInputStream());
    }

    @Überschreiben
    öffentlicher ServletInputStream getInputStream() wirft IOException {
        InputStream bodyStream = neuer ByteArrayInputStream(body);
        gibt neuen ServletInputStream() zurück {

            @Überschreiben
            öffentliche int read() wirft IOException {
                gibt bodyStream.read() zurück;
            }

            @Überschreiben
            public boolean istFertig() {
                gibt false zurück;
            }

            @Überschreiben
            öffentlicher Boolescher Wert istBereit() {
                gibt true zurück;
            }

            @Überschreiben
            öffentliche Leere setReadListener (ReadListener readListener) {

            }
        };
    }

    @Überschreiben
    öffentlicher BufferedReader getReader() wirft IOException {
        gibt einen neuen BufferedReader zurück (neuer InputStreamReader (getInputStream()));
    }
}

Anschließend müssen Sie einen Filter erstellen und "ServletRequest" durch "MyHttpServletRequestWrapper" ersetzen. Der Code lautet wie folgt:

importiere lombok.extern.slf4j.Slf4j;

importiere javax.servlet.*;
importiere javax.servlet.http.HttpServletRequest;
importiere java.io.IOException;

@Slf4j
öffentliche Klasse RepeatedlyReadFilter implementiert Filter {
    @Überschreiben
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Überschreiben
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        ServletRequest requestWrapper = null;
        if (servletRequest-Instanz von HttpServletRequest) {
            requestWrapper = neuer MyHttpServletRequestWrapper((HttpServletRequest) servletRequest);
        }
        wenn(requestWrapper == null) {
            filterChain.doFilter(servletAnfrage, servletAntwort);
        } anders {
            filterChain.doFilter(requestWrapper, servletResponse);
        }

    }

    @Überschreiben
    öffentliche Leere zerstören() {

    }
}

Erstellen Sie dann eine benutzerdefinierte Konfiguration, CorsConfig.java, und fügen Sie der Konfiguration Filter und Interceptors hinzu:

importiere com.xyf.interceptor.MyInterceptor;
importiere com.xyf.interceptor.RepeatedlyReadFilter;
importiere org.springframework.beans.factory.annotation.Autowired;
importiere org.springframework.boot.web.servlet.FilterRegistrationBean;
importiere org.springframework.context.annotation.Bean;
importiere org.springframework.context.annotation.Configuration;
importiere org.springframework.web.servlet.config.annotation.InterceptorRegistry;
importiere org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

@Konfiguration
öffentliche Klasse CorsConfig erweitert WebMvcConfigurationSupport {

    privater MyInterceptor meinInterceptor;

    @Autowired
    öffentliche CorsConfig (MyInterceptor myInterceptor) {
        dies.meinInterceptor = meinInterceptor;
    }

    //Filter registrieren@Bean
    öffentliche FilterRegistrationBean<RepeatedlyReadFilter> wiederholtReadFilter() {
        FilterRegistrationBean-Registrierung = neue FilterRegistrationBean();
        WiederholtesLesenFilter wiederholtLesenFilter = neuer wiederholtesLesenFilter();
        Registrierung.setFilter(wiederholtReadFilter);
        Registrierung.addUrlPatterns("/*");
        Rückmeldewesen;
    }


    @Überschreiben
    geschützt void addInterceptors(InterceptorRegistry registry) {
        // addPathPatterns fügt den Namespace hinzu, der abgefangen werden muss;
        // excludePathPatterns fügt den Namespace für die Ausschluss-Interception hinzu registry.addInterceptor(myInterceptor).addPathPatterns("/**");
        //.excludePathPatterns("/api/sys/login")
    }

}

Schließen Sie abschließend die Signaturprüfung ab. Der Code lautet wie folgt:

importiere cn.hutool.core.codec.Base64;
importiere cn.hutool.crypto.SecureUtil;
importiere cn.hutool.crypto.asymmetric.Sign;
importiere cn.hutool.crypto.asymmetric.SignAlgorithm;


byte[] data = "Ich bin eine Testzeichenfolge 2".getBytes();
        Zeichenfolge öffentlicher Schlüssel = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC35wxzdTzseajkYL06hEKBCEJu\n" +
                "JQ/nySId2oTnsxbLiSTEjpAESSbML1lqkKaIwjrSFZzyLMH6DirsoEQcATqqoCDU\n" +
                "/H9QNVb5jMSAxxdQusQkTWz6k07bEuy1ppVjpGxNi8o2OGNd+lwPC/hOSDR7lpfm\n" +
                „aXLIjEwKSXzil7YAHQIDAQAB“;

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

//Vom Client gesendete Signaturzeichenfolge qm = "IhY3LNuFn0isud1Pk6BL2eJV3Jl/UzDCYsdG9CYyJwOGqwnzStsv/RiYLnVP4bnQh1NRPMazY6ux/5Zz5Ypcx6RI5W1p5BDbO2afuIZX7x/eIu5utwsanhbxEfvm3XOsyuTbnMDh6BQUrXb4gUz9qgt9IXWjQdqnQRRv3ywzWcA=";
byte[] signiert = Base64.decode(qm);

//Überprüfen Sie die Signatur boolean verify = sign.verify(data, signed);

3. Generierung öffentlicher und privater Schlüssel

Sie können öffentliche und private Schlüssel online auf einigen Websites generieren: https://www.bejson.com/enc/rsa/

bejson generiert öffentliche und private Schlüssel online

4. Andere Probleme

Weil der Client die Signatur hinzufügt und der Server die Signatur überprüft. Daher muss die Methode zum Hinzufügen und Überprüfen von Signaturen konsistent sein, da die Signatur sonst nicht überprüft werden kann. Vue und Java verfügen über unterschiedliche Signatur-Toolbibliotheken. Testen Sie diese daher unbedingt vor der Verwendung.

Dies ist das Ende dieses Artikels über den Beispielcode von Vue+Springboot zur Implementierung der Schnittstellensignatur. Weitere verwandte Inhalte zur Springboot-Schnittstellensignatur finden Sie in den vorherigen Artikeln von 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen!

Das könnte Sie auch interessieren:
  • Lösung für das 404-Problem nach dem SpringBoot-Schnittstellenaufruf
  • Ein einfaches Tutorial zur Verwendung des visuellen SpringBoot-Schnittstellenentwicklungstools magic-api
  • Implementierungsmethode zur Verschlüsselung und Entschlüsselung von Spring Boot-Schnittstellenparametern
  • Gängige Algorithmen und Merkmale der Strombegrenzung der Spring Boot-Schnittstelle
  • Detaillierte Erläuterung zum Erstellen geplanter Aufgaben in Springboot durch Anmerkungen und Schnittstellen
  • Mit der Java Springboot-Oberfläche können Sie schnell loslegen und in einer halben Stunde loslegen.

<<:  So installieren Sie die Standalone-Version von Spark in einer Linux-Umgebung ohne Verwendung von Hadoop

>>:  Laden Sie MySQL 5.7 herunter und sehen Sie sich das detaillierte Installationsdiagramm für MySql auf dem Mac an.

Artikel empfehlen

Fallstricke basierend auf MySQL-Standardsortierregeln

Der Standardtyp varchar in MySQL ist case-insensi...

CentOS 7.2 erstellt einen Nginx-Webserver zum Bereitstellen des Uniapp-Projekts

Panther begann als Anfänger und ich bin immer noc...

Beispiel für die Konfiguration mehrerer virtueller Hosts in nginx

Es ist sehr praktisch, den virtuellen Host vhost ...

Detaillierte Erklärung asynchroner Iteratoren in nodejs

Inhaltsverzeichnis Vorwort Was sind asynchrone It...

Toolkit: Ein leistungsfähigeres Front-End-Framework als Bootstrap

Hinweis: Die derzeit beliebtesten Front-End-Frame...

MySQL-Sortierprinzipien und Fallanalyse

Vorwort Das Sortieren ist eine grundlegende Funkt...

jQuery implementiert den Tabellen-Paging-Effekt

In diesem Artikel wird der spezifische Code von j...

Verwenden Sie CSS, um die Breite von INPUT in TD festzulegen

Als ich kürzlich mit C# ein Webprogramm erstellte,...

So verwenden Sie vite zum Erstellen einer Vue3-Anwendung

1. Installation Tipp: Derzeit gibt es kein offizi...