一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務器之家 - 編程語言 - JavaScript - vue.js - Vue+Springboot實現(xiàn)接口簽名的示例代碼

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

2022-03-09 16:29shadow_2155 vue.js

這篇文章主要介紹了Vue+Springboot實現(xiàn)接口簽名的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

1、實現(xiàn)思路

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

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

接口簽名示意圖

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

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

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

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

簽名

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

2、代碼實現(xiàn)

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

?
1
npm install jsrsasign -save

安裝完成后,封裝sign.js

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import {KJUR, KEYUTIL, hex2b64, b64tohex} from 'jsrsasign'
 
// 簽名算法
const ALGORITHM = 'SHA256withRSA'
 
// 私鑰簽名
const RSA_SIGN = (privateKey, src) => {
    const signature = new KJUR.crypto.Signature({'alg': ALGORITHM})
    // 來解析密鑰
    const priKey = KEYUTIL.getKey(privateKey)
    signature.init(priKey)
    // 傳入待簽明文
    signature.updateString(src)
    const a = signature.sign()
    // 轉(zhuǎn)換成base64,返回
    return hex2b64(a)
}
// 公鑰驗簽
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
}

客戶端(Vue)通過sign.js進行加簽、驗簽。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const src = '我是一段測試字符串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('驗簽結(jié)果:', res)

服務端(Spring boot)接收請求后,需要對數(shù)據(jù)和簽名,進行驗證。

首先引入依賴——hutool工具包,Hutool是一個Java工具包,也只是一個工具包,它幫助我們簡化每一行代碼,減少每一個方法,讓Java語言也可以“甜甜的”。

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

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

?
1
2
3
4
5
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.3.5</version>
</dependency>

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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 {
        //獲取請求參數(shù)
        String queryString = request.getQueryString();
        log.info("請求參數(shù):{}", queryString);
 
        // 獲取header
        log.info("key:{}",request.getHeader("timestamp"));
 
        MyHttpServletRequestWrapper myRequestWrapper = new MyHttpServletRequestWrapper(request);
        //獲取請求body
        byte[] bodyBytes = StreamUtils.copyToByteArray(myRequestWrapper.getInputStream());
        String body = new String(bodyBytes, request.getCharacterEncoding());
 
        log.info("請求體:{}", body);
 
        return true;
    }
}

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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 {
 
    /**
     * 緩存下來的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()));
    }
}

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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,將過濾器、攔截器加入配置:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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;
    }
 
    // 注冊過濾器
    @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")
    }
 
}

最后,完成驗簽,代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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 = "我是一段測試字符串2".getBytes();
        String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC35wxzdTzseajkYL06hEKBCEJu\n" +
                "JQ/nySId2oTnsxbLiSTEjpAESSbML1lqkKaIwjrSFZzyLMH6DirsoEQcATqqoCDU\n" +
                "/H9QNVb5jMSAxxdQusQkTWz6k07bEuy1ppVjpGxNi8o2OGNd+lwPC/hOSDR7lpfm\n" +
                "aXLIjEwKSXzil7YAHQIDAQAB";
 
Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA,null,publicKey);
 
//客戶端傳來的簽名
String qm = "IhY3LNuFn0isud1Pk6BL2eJV3Jl/UzDCYsdG9CYyJwOGqwnzStsv/RiYLnVP4bnQh1NRPMazY6ux/5Zz5Ypcx6RI5W1p5BDbO2afuIZX7x/eIu5utwsanhbxEfvm3XOsyuTbnMDh6BQUrXb4gUz9qgt9IXWjQdqnQRRv3ywzWcA=";
byte[] signed = Base64.decode(qm);
 
//驗證簽名
boolean verify = sign.verify(data, signed);

3、公鑰、私鑰生成

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

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

bejson在線生成公鑰、私鑰

4、其他問題

由于客戶端加簽、服務端驗簽。所以加簽、驗簽的方式務必一致,否則將無法驗證簽名。Vue、Java有不同的簽名工具庫,使用前要做好測試。

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

原文鏈接:https://www.jianshu.com/p/e051944eab8f

延伸 · 閱讀

精彩推薦
  • vue.jsVue項目中實現(xiàn)帶參跳轉(zhuǎn)功能

    Vue項目中實現(xiàn)帶參跳轉(zhuǎn)功能

    最近做了一個手機端系統(tǒng),其中遇到了父頁面需要攜帶參數(shù)跳轉(zhuǎn)至子頁面的問題,現(xiàn)已解決,下面分享一下實現(xiàn)過程,感興趣的朋友一起看看吧...

    YiluRen丶4302022-03-03
  • vue.jsVue中引入svg圖標的兩種方式

    Vue中引入svg圖標的兩種方式

    這篇文章主要給大家介紹了關于Vue中引入svg圖標的兩種方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的...

    十里不故夢10222021-12-31
  • vue.js用vite搭建vue3應用的實現(xiàn)方法

    用vite搭建vue3應用的實現(xiàn)方法

    這篇文章主要介紹了用vite搭建vue3應用的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下...

    Asiter7912022-01-22
  • vue.jsVue2.x 項目性能優(yōu)化之代碼優(yōu)化的實現(xiàn)

    Vue2.x 項目性能優(yōu)化之代碼優(yōu)化的實現(xiàn)

    這篇文章主要介紹了Vue2.x 項目性能優(yōu)化之代碼優(yōu)化的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋...

    優(yōu)小U9632022-02-21
  • vue.jsVue多選列表組件深入詳解

    Vue多選列表組件深入詳解

    這篇文章主要介紹了Vue多選列表組件深入詳解,這個是vue的基本組件,有需要的同學可以研究下...

    yukiwu6752022-01-25
  • vue.js詳解vue 表單綁定與組件

    詳解vue 表單綁定與組件

    這篇文章主要介紹了vue 表單綁定與組件的相關資料,幫助大家更好的理解和學習使用vue框架,感興趣的朋友可以了解下...

    Latteitcjz6432022-02-12
  • vue.js梳理一下vue中的生命周期

    梳理一下vue中的生命周期

    看過很多人講vue的生命周期,但總是被繞的云里霧里,尤其是自學的同學,可能js的基礎也不是太牢固,聽起來更是吃力,那我就已個人之淺見,以大白話...

    CRMEB技術團隊7992021-12-22
  • vue.jsVue2.x-使用防抖以及節(jié)流的示例

    Vue2.x-使用防抖以及節(jié)流的示例

    這篇文章主要介紹了Vue2.x-使用防抖以及節(jié)流的示例,幫助大家更好的理解和學習使用vue框架,感興趣的朋友可以了解下...

    Kyara6372022-01-25
主站蜘蛛池模板: 国产一区二区精品 | 亚洲国产成人久久综合区 | aaaa黄色片| 免费全看男女拍拍拍的视频 | 78成人网 | av在线色 | 私人影院在线免费观看 | 亚洲国产欧美久久香综合 | 国产午夜精品不卡视频 | 97青草香蕉依人在线播放 | 亚洲国产精品综合久久网络 | 成年人福利视频 | 禁忌第一季第3季 | 国产91青青成人a在线 | 久久久亚洲国产精品主播 | 日韩精品一区二区三区老鸭窝 | 公妇乱淫在线播放免费观看 | 韩国三级在线 | 动漫美女3d被爆漫画 | 婚前试爱免费看 | 天天射寡妇射 | 乳女教师欲乱动漫无修版动画3d | 亚洲午夜精品久久久久久成年 | 国产欧美日韩精品一区二区三区 | 冰漪丰满大乳人体图片欣赏 | 波多野结衣作品在线观看 | 黄网国产 | 男女姓交大视频免费观看 | 免费一级片在线 | 国产成人精品一区二区仙踪林 | 青草视频网站在线观看 | 和两个男人玩3p好爽视频 | 精品国产乱码久久久久久免费流畅 | 污网站免费观看在线高清 | 精品综合久久久久久8888 | 亚洲国产精品综合久久一线 | 2020年最新国产精品视频免费 | 欧美亚洲高清日韩成人 | 国产精品久久久久久爽爽爽 | 成人免费体验区福利云点播 | 成人午夜毛片 |