增加WebSocket签名机制与php签名示例
This commit is contained in:
parent
495fd10d45
commit
326ac341bc
@ -9,3 +9,6 @@ Go编写定时获取sftp文件,并解析文件入库,完成后发送邮件
|
|||||||
正式环境启动
|
正式环境启动
|
||||||
./iniDataForMacOs -env prod
|
./iniDataForMacOs -env prod
|
||||||
|
|
||||||
|
PHP WebSocket 指令与签名demo
|
||||||
|
sign_message.php
|
||||||
|
|
||||||
|
|||||||
BIN
iniDataForMacOs
BIN
iniDataForMacOs
Binary file not shown.
76
main.go
76
main.go
@ -4,8 +4,11 @@ import (
|
|||||||
"archive/zip"
|
"archive/zip"
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha256"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/csv"
|
"encoding/csv"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -103,34 +106,40 @@ func handleWebSocket(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Println("收到消息:", string(message))
|
fmt.Println("收到消息:", string(message))
|
||||||
|
|
||||||
task := Task{}
|
|
||||||
var returnMessage []byte
|
var returnMessage []byte
|
||||||
|
task := Task{}
|
||||||
|
|
||||||
err = json.Unmarshal([]byte(message), &task)
|
err = json.Unmarshal([]byte(message), &task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
returnMessage = []byte(`{"code": 2001,"err": "json指令解析失败"}`)
|
returnMessage = []byte(`{"code": 2001,"err": "json指令解析失败"}`)
|
||||||
conn.WriteMessage(websocket.TextMessage, returnMessage) //发送消息给客户端
|
conn.WriteMessage(websocket.TextMessage, returnMessage) //发送消息给客户端
|
||||||
} else {
|
} else {
|
||||||
switch task.Command {
|
if !verify_signature(task.Signature.Signature, task.Signature.Nonce, task.Signature.Timestamp, task.TaskData) { // 签名验证失败或超时
|
||||||
|
returnMessage = []byte(`{"code": 2401,"err": "Unauthorized"}`)
|
||||||
|
conn.WriteMessage(websocket.TextMessage, returnMessage)
|
||||||
|
conn.Close()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
switch task.TaskData.Command {
|
||||||
case "lastCall":
|
case "lastCall":
|
||||||
if !fileExists(path.Join(executableDir, lastCallPath, task.ExcludedFilename)) {
|
if !fileExists(path.Join(executableDir, lastCallPath, task.TaskData.ExcludedFilename)) {
|
||||||
returnMessage = []byte(`{"code": 2003,"err": "task.ExcludedFilename 不存在"}`)
|
returnMessage = []byte(`{"code": 2003,"err": "task.ExcludedFilename 不存在"}`)
|
||||||
conn.WriteMessage(websocket.TextMessage, returnMessage) //发送消息给客户端
|
conn.WriteMessage(websocket.TextMessage, returnMessage) //发送消息给客户端
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if !fileExists(path.Join(executableDir, txtPath, task.BatchFilename)) {
|
if !fileExists(path.Join(executableDir, txtPath, task.TaskData.BatchFilename)) {
|
||||||
returnMessage = []byte(`{"code": 2004,"err": "task.BatchFilename 不存在"}`)
|
returnMessage = []byte(`{"code": 2004,"err": "task.BatchFilename 不存在"}`)
|
||||||
conn.WriteMessage(websocket.TextMessage, returnMessage) //发送消息给客户端
|
conn.WriteMessage(websocket.TextMessage, returnMessage) //发送消息给客户端
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if !fileExists(path.Join(executableDir, txtPath, task.DataFilename)) {
|
if !fileExists(path.Join(executableDir, txtPath, task.TaskData.DataFilename)) {
|
||||||
returnMessage = []byte(`{"code": 2005,"err": "task.DataFilename 不存在"}`)
|
returnMessage = []byte(`{"code": 2005,"err": "task.DataFilename 不存在"}`)
|
||||||
conn.WriteMessage(websocket.TextMessage, returnMessage) //发送消息给客户端
|
conn.WriteMessage(websocket.TextMessage, returnMessage) //发送消息给客户端
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
returnMessage = []byte(`{"code": 2000,"err": "开始处理lastCall"}`)
|
returnMessage = []byte(`{"code": 2000,"err": "开始处理lastCall"}`)
|
||||||
conn.WriteMessage(websocket.TextMessage, returnMessage) //发送消息给客户端
|
conn.WriteMessage(websocket.TextMessage, returnMessage) //发送消息给客户端
|
||||||
lastCallKeys, err := readExcludedFile(path.Join(executableDir, lastCallPath, task.ExcludedFilename))
|
lastCallKeys, err := readExcludedFile(path.Join(executableDir, lastCallPath, task.TaskData.ExcludedFilename))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
returnMessage = []byte(`{"code": 2006,"err": "打开ExcludedFilename失败"}`)
|
returnMessage = []byte(`{"code": 2006,"err": "打开ExcludedFilename失败"}`)
|
||||||
conn.WriteMessage(websocket.TextMessage, returnMessage) //发送消息给客户端
|
conn.WriteMessage(websocket.TextMessage, returnMessage) //发送消息给客户端
|
||||||
@ -154,11 +163,11 @@ func handleWebSocket(w http.ResponseWriter, r *http.Request) {
|
|||||||
conn.WriteMessage(websocket.TextMessage, returnMessage) //发送消息给客户端
|
conn.WriteMessage(websocket.TextMessage, returnMessage) //发送消息给客户端
|
||||||
SendEmail(subject, body) //发送邮件
|
SendEmail(subject, body) //发送邮件
|
||||||
} else {
|
} else {
|
||||||
batchInsert(task.BatchFilename, true) //创建批次
|
batchInsert(task.TaskData.BatchFilename, true) //创建批次
|
||||||
returnMessage = []byte(`{"code": 2000,"err": "批次创建完成"}`)
|
returnMessage = []byte(`{"code": 2000,"err": "批次创建完成"}`)
|
||||||
conn.WriteMessage(websocket.TextMessage, returnMessage) //发送消息给客户端
|
conn.WriteMessage(websocket.TextMessage, returnMessage) //发送消息给客户端
|
||||||
batchDataInsert(task.DataFilename, lastCallKeys) //添加数据
|
batchDataInsert(task.TaskData.DataFilename, lastCallKeys) //添加数据
|
||||||
redisClient.Del("iniLastCallDataStatus") //删除任务执行中标记
|
redisClient.Del("iniLastCallDataStatus") //删除任务执行中标记
|
||||||
returnMessage = []byte(`{"code": 2000,"err": "结束处理lastCall"}`)
|
returnMessage = []byte(`{"code": 2000,"err": "结束处理lastCall"}`)
|
||||||
conn.WriteMessage(websocket.TextMessage, returnMessage) //发送消息给客户端
|
conn.WriteMessage(websocket.TextMessage, returnMessage) //发送消息给客户端
|
||||||
}
|
}
|
||||||
@ -181,6 +190,41 @@ func handleWebSocket(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func verify_signature(signature string, nonce int64, timestamp int64, data interface{}) bool {
|
||||||
|
key := "qZ6v1&H#Wjx+yRm2D@*sJF$tnfL83Ia"
|
||||||
|
|
||||||
|
fmt.Printf("Received signature: %s\n", signature)
|
||||||
|
fmt.Printf("Received timestamp: %d\n", timestamp)
|
||||||
|
fmt.Printf("Received nonce: %d\n", nonce)
|
||||||
|
fmt.Printf("Received data: %v\n", data)
|
||||||
|
|
||||||
|
received_signature := signature
|
||||||
|
received_timestamp, _ := strconv.ParseInt(fmt.Sprintf("%v", timestamp), 10, 64)
|
||||||
|
received_nonce, _ := strconv.Atoi(fmt.Sprintf("%v", nonce))
|
||||||
|
|
||||||
|
if time.Now().Unix()-received_timestamp > 7200 {
|
||||||
|
fmt.Println("Timestamp expired")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
received_data_bytes, _ := json.Marshal(data)
|
||||||
|
received_data := string(received_data_bytes)
|
||||||
|
expected_data := fmt.Sprintf("%d|%d|%s", received_timestamp, received_nonce, received_data)
|
||||||
|
fmt.Printf("Expected data: %s\n", expected_data)
|
||||||
|
|
||||||
|
mac := hmac.New(sha256.New, []byte(key))
|
||||||
|
mac.Write([]byte(expected_data))
|
||||||
|
expected_signature := hex.EncodeToString(mac.Sum(nil))
|
||||||
|
fmt.Printf("Expected signature: %s\n", expected_signature)
|
||||||
|
|
||||||
|
if received_signature != expected_signature {
|
||||||
|
fmt.Println("Signature does not match")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func readExcludedFile(filename string) (map[string]bool, error) {
|
func readExcludedFile(filename string) (map[string]bool, error) {
|
||||||
file, err := os.Open(filename)
|
file, err := os.Open(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1146,8 +1190,18 @@ type SmsData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Task struct {
|
type Task struct {
|
||||||
|
TaskData TaskData
|
||||||
|
Signature Signature
|
||||||
|
}
|
||||||
|
|
||||||
|
type TaskData struct {
|
||||||
Command string `json:"command"`
|
Command string `json:"command"`
|
||||||
ExcludedFilename string `json:"excluded_filename"`
|
ExcludedFilename string `json:"excluded_filename"`
|
||||||
BatchFilename string `json:"batch_filename"`
|
BatchFilename string `json:"batch_filename"`
|
||||||
DataFilename string `json:"data_filename"`
|
DataFilename string `json:"data_filename"`
|
||||||
}
|
}
|
||||||
|
type Signature struct {
|
||||||
|
Signature string `json:"signature"`
|
||||||
|
Timestamp int64 `json:"timestamp"`
|
||||||
|
Nonce int64 `json:"nonce"`
|
||||||
|
}
|
||||||
|
|||||||
28
sign_message.php
Normal file
28
sign_message.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
function sign_message($data) {
|
||||||
|
$timestamp = time();
|
||||||
|
$nonce = mt_rand(100000, 999999); // 生成一个六位随机数
|
||||||
|
$message = "$timestamp|$nonce|" . json_encode($data);
|
||||||
|
$key = 'qZ6v1&H#Wjx+yRm2D@*sJF$tnfL83Ia'; // 签名密钥,请自行设置
|
||||||
|
$signature = hash_hmac('sha256', $message, $key);
|
||||||
|
$signed_message = array(
|
||||||
|
'TaskData' => $data,
|
||||||
|
'signature' => array(
|
||||||
|
'signature' => $signature,
|
||||||
|
'timestamp' => $timestamp,
|
||||||
|
'nonce' => $nonce
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return json_encode($signed_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = array(
|
||||||
|
"command" => "lastCall",
|
||||||
|
"excluded_filename" => "lastCall.txt",
|
||||||
|
"batch_filename" => "Communication_definition_SMS_1_wemedia_20230303185518.txt",
|
||||||
|
"data_filename" => "Communication_targets_SMS_1_wemedia_20230303185518.txt"
|
||||||
|
);
|
||||||
|
|
||||||
|
echo sign_message($data);
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user