最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue+Springboot實(shí)現(xiàn)接口簽名的示例代碼

 更新時(shí)間:2021年04月25日 09:30:42   作者:shadow_2155  
這篇文章主要介紹了Vue+Springboot實(shí)現(xiàn)接口簽名的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

1、實(shí)現(xiàn)思路

接口簽名目的是為了,確保請(qǐng)求參數(shù)不會(huì)被篡改,請(qǐng)求的數(shù)據(jù)是否已超時(shí),數(shù)據(jù)是否重復(fù)提交等。

接口簽名示意圖

客戶(hù)端提交請(qǐng)求時(shí),將以下參數(shù)按照約定簽名方式進(jìn)行簽名,隨后將參數(shù)和簽名一同提交服務(wù)端:

1.請(qǐng)求頭部分(header)
appid:針對(duì)不同的調(diào)用方分配不同的appid。
noce:請(qǐng)求的流水號(hào),防止重復(fù)提交。
timestamp:請(qǐng)求時(shí)間戳,驗(yàn)證請(qǐng)求是否已超時(shí)失效。

2.數(shù)據(jù)部分
Path:按照path中的參數(shù)將所有key=value進(jìn)行拼接。
Query:按照所有key=value進(jìn)行拼接。
Form:按照所有key=value進(jìn)行拼接
Body:Json,按照所有key=value進(jìn)行拼接。String,整個(gè)字符串作為一個(gè)拼接。

簽名

服務(wù)端提接收交請(qǐng)求后,同樣通過(guò)接收的“請(qǐng)求頭部分”、“數(shù)據(jù)部分”的參數(shù)進(jìn)行拼接。隨后驗(yàn)證客戶(hù)端提交的簽名是否正確。

2、代碼實(shí)現(xiàn)

客戶(hù)端(Vue)首先需要安裝“jsrsasign”庫(kù),以便實(shí)現(xiàn) RSA 加密、解密、簽名、驗(yàn)簽等功能。
官方地址:http://kjur.github.io/jsrsasign/
執(zhí)行以下命令:

npm install jsrsasign -save

安裝完成后,封裝sign.js

import {KJUR, KEYUTIL, hex2b64, b64tohex} from 'jsrsasign'

// 簽名算法
const ALGORITHM = 'SHA256withRSA'

// 私鑰簽名
const RSA_SIGN = (privateKey, src) => {
    const signature = new KJUR.crypto.Signature({'alg': ALGORITHM})
    // 來(lái)解析密鑰
    const priKey = KEYUTIL.getKey(privateKey) 
    signature.init(priKey)
    // 傳入待簽明文
    signature.updateString(src) 
    const a = signature.sign()
    // 轉(zhuǎn)換成base64,返回
    return hex2b64(a) 
}
// 公鑰驗(yàn)簽
const RSA_VERIFY_SIGN = (publicKey, src, data) => {
    const signature = new KJUR.crypto.Signature({'alg': ALGORITHM, 'prvkeypem': publicKey})
    signature.updateString(src) 
    return signature.verify(b64tohex(data))
}

export {
    RSA_SIGN,
    RSA_VERIFY_SIGN
}

客戶(hù)端(Vue)通過(guò)sign.js進(jìn)行加簽、驗(yàn)簽。

const src = '我是一段測(cè)試字符串2'

const publicKey = '-----BEGIN PUBLIC KEY-----\n' +
            'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC35wxzdTzseajkYL06hEKBCEJu\n' +
            'JQ/nySId2oTnsxbLiSTEjpAESSbML1lqkKaIwjrSFZzyLMH6DirsoEQcATqqoCDU\n' +
            '/H9QNVb5jMSAxxdQusQkTWz6k07bEuy1ppVjpGxNi8o2OGNd+lwPC/hOSDR7lpfm\n' +
            'aXLIjEwKSXzil7YAHQIDAQAB\n' +
            '-----END PUBLIC KEY-----'

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' +
            '-----END PRIVATE KEY-----\n'


console.log('明文:', src)
const data = RSA_SIGN(privateKey, src)
console.log('簽名后的結(jié)果:', data)

const res = RSA_VERIFY_SIGN(publicKey, src, data)
console.log('驗(yàn)簽結(jié)果:', res)

服務(wù)端(Spring boot)接收請(qǐng)求后,需要對(duì)數(shù)據(jù)和簽名,進(jìn)行驗(yàn)證。

首先引入依賴(lài)——hutool工具包,Hutool是一個(gè)Java工具包,也只是一個(gè)工具包,它幫助我們簡(jiǎn)化每一行代碼,減少每一個(gè)方法,讓Java語(yǔ)言也可以“甜甜的”。

官網(wǎng)地址:https://www.hutool.cn/

在pom.xml下增加如下配置:

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.3.5</version>
</dependency>

服務(wù)端(Spring boot)首先要獲取客戶(hù)端(Vue)請(qǐng)求的數(shù)據(jù),上文已經(jīng)描述了請(qǐng)求的數(shù)據(jù)有兩部分,分別是“請(qǐng)求頭部分”、“數(shù)據(jù)部分”。所以需要配置攔截器,對(duì)以上兩部分進(jìn)行獲取。

配置攔截器(MyInterceptor.java),代碼如下:

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

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Slf4j
@Component
public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //獲取請(qǐng)求參數(shù)
        String queryString = request.getQueryString();
        log.info("請(qǐng)求參數(shù):{}", queryString);

        // 獲取header
        log.info("key:{}",request.getHeader("timestamp"));

        MyHttpServletRequestWrapper myRequestWrapper = new MyHttpServletRequestWrapper(request);
        //獲取請(qǐng)求body
        byte[] bodyBytes = StreamUtils.copyToByteArray(myRequestWrapper.getInputStream());
        String body = new String(bodyBytes, request.getCharacterEncoding());

        log.info("請(qǐng)求體:{}", body);

        return true;
    }
}

在獲取“請(qǐng)求體body”時(shí),由于“HttpServletRequest”只能讀取一次,攔截器讀取后,后續(xù)Controller在讀取時(shí)為空,所以需要重寫(xiě)HttpServletRequestWrapper:

import org.springframework.util.StreamUtils;

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


public class MyHttpServletRequestWrapper extends HttpServletRequestWrapper {

    /**
     * 緩存下來(lái)的HTTP body
     */
    private byte[] body;

    public MyHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        body = StreamUtils.copyToByteArray(request.getInputStream());
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        InputStream bodyStream = new ByteArrayInputStream(body);
        return new ServletInputStream(){

            @Override
            public int read() throws IOException {
                return bodyStream.read();
            }

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return true;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }
        };
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }
}

之后,需要?jiǎng)?chuàng)建過(guò)濾器,將“MyHttpServletRequestWrapper” 替換“ServletRequest”,代碼如下:

import lombok.extern.slf4j.Slf4j;

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

@Slf4j
public class RepeatedlyReadFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        ServletRequest requestWrapper = null;
        if(servletRequest instanceof HttpServletRequest) {
            requestWrapper = new MyHttpServletRequestWrapper((HttpServletRequest) servletRequest);
        }
        if(requestWrapper == null) {
            filterChain.doFilter(servletRequest, servletResponse);
        } else {
            filterChain.doFilter(requestWrapper, servletResponse);
        }

    }

    @Override
    public void destroy() {

    }
}

之后創(chuàng)建自定義配置,CorsConfig.java,將過(guò)濾器、攔截器加入配置:

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

@Configuration
public class CorsConfig extends WebMvcConfigurationSupport {

    private MyInterceptor myInterceptor;

    @Autowired
    public CorsConfig (MyInterceptor myInterceptor){
        this.myInterceptor = myInterceptor;
    }

    // 注冊(cè)過(guò)濾器
    @Bean
    public FilterRegistrationBean<RepeatedlyReadFilter> repeatedlyReadFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        RepeatedlyReadFilter repeatedlyReadFilter = new RepeatedlyReadFilter();
        registration.setFilter(repeatedlyReadFilter);
        registration.addUrlPatterns("/*");
        return registration;
    }


    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        // addPathPatterns添加需要攔截的命名空間;
        // excludePathPatterns添加排除攔截命名空間

        registry.addInterceptor(myInterceptor).addPathPatterns("/**");
        //.excludePathPatterns("/api/sys/login")
    }

}

最后,完成驗(yàn)簽,代碼如下:

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


byte[] data = "我是一段測(cè)試字符串2".getBytes();
        String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC35wxzdTzseajkYL06hEKBCEJu\n" +
                "JQ/nySId2oTnsxbLiSTEjpAESSbML1lqkKaIwjrSFZzyLMH6DirsoEQcATqqoCDU\n" +
                "/H9QNVb5jMSAxxdQusQkTWz6k07bEuy1ppVjpGxNi8o2OGNd+lwPC/hOSDR7lpfm\n" +
                "aXLIjEwKSXzil7YAHQIDAQAB";

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

//客戶(hù)端傳來(lái)的簽名
String qm = "IhY3LNuFn0isud1Pk6BL2eJV3Jl/UzDCYsdG9CYyJwOGqwnzStsv/RiYLnVP4bnQh1NRPMazY6ux/5Zz5Ypcx6RI5W1p5BDbO2afuIZX7x/eIu5utwsanhbxEfvm3XOsyuTbnMDh6BQUrXb4gUz9qgt9IXWjQdqnQRRv3ywzWcA=";
byte[] signed = Base64.decode(qm);

//驗(yàn)證簽名
boolean verify = sign.verify(data, signed);

3、公鑰、私鑰生成

可通過(guò)一些網(wǎng)站在線(xiàn)生成公鑰、私鑰
網(wǎng)址:https://www.bejson.com/enc/rsa/

bejson在線(xiàn)生成公鑰、私鑰

4、其他問(wèn)題

由于客戶(hù)端加簽、服務(wù)端驗(yàn)簽。所以加簽、驗(yàn)簽的方式務(wù)必一致,否則將無(wú)法驗(yàn)證簽名。Vue、Java有不同的簽名工具庫(kù),使用前要做好測(cè)試。

到此這篇關(guān)于Vue+Springboot實(shí)現(xiàn)接口簽名的示例代碼的文章就介紹到這了,更多相關(guān)Springboot 接口簽名內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

最新評(píng)論

隆尧县| 邵阳县| 黄浦区| 青神县| 墨竹工卡县| 双峰县| 衡南县| 乐昌市| 张家川| 石家庄市| 庆安县| 正蓝旗| 安新县| 高密市| 翼城县| 玉树县| 波密县| 广昌县| 涿鹿县| 湘潭市| 安阳市| 海口市| 泸水县| 德清县| 陈巴尔虎旗| 广宗县| 石门县| 普陀区| 株洲县| 玉树县| 邹城市| 布尔津县| 宜阳县| 密山市| 资源县| 建阳市| 古蔺县| 昌平区| 龙岩市| 邵东县| 宜川县|