@@ -0,0 +1,71 @@ | |||
kind: pipeline | |||
name: job_risk_third | |||
workspace: | |||
base: /var/goproject/src | |||
path: job_risk_third | |||
steps: | |||
- name: build | |||
image: golang:1.14.4 | |||
environment: | |||
GOOS: linux | |||
GOARCH: amd64 | |||
commands: | |||
- export GOPATH=/var/goproject | |||
- export PATH=$PATH:$GOROOT/bin | |||
- go env -w GO111MODULE=on | |||
- go env -w GOPROXY=https://goproxy.cn,direct | |||
- go version | |||
- go env | |||
- go mod tidy | |||
- go build -i -o bin/job_risk_third cmd/main.go | |||
- name: develop deploy | |||
image: appleboy/drone-scp | |||
settings: | |||
host: | |||
from_secret: host | |||
port: | |||
from_secret: port | |||
username: | |||
from_secret: username | |||
password: | |||
from_secret: password | |||
target: | |||
from_secret: target | |||
source: ./bin | |||
rm: false | |||
when: | |||
branch: | |||
- deploy_develop | |||
- name: run | |||
image: appleboy/drone-ssh | |||
settings: | |||
host: | |||
from_secret: host | |||
port: | |||
from_secret: port | |||
username: | |||
from_secret: username | |||
password: | |||
from_secret: password | |||
command_timeout: 2m | |||
script: | |||
- cd /server/job_risk_third/ | |||
- rm -rf job_risk_third | |||
- cp bin/job_risk_third job_risk_third | |||
- cp restart.sh restart.sh | |||
- ./restart.sh | |||
- nohup ./job_risk_third -f config/job_risk_third.json 1>/dev/null 2>&1 & | |||
- name: notification | |||
image: lddsb/drone-dingtalk-message | |||
settings: | |||
token: 840fed65878154561a096c03a516ded894ab1b91efbe1643fe492dd93593e7a3 | |||
type: markdown | |||
secret: SEC9fe40cc775658cbef7a30b43fd852b642201754fdrone15df42cd339627e05cfde41e | |||
tpl: ./drone/tpl/index.md | |||
tips_title: 宁达用户服务构建结果 | |||
success_pic: https://i.ibb.co/CB4HBLP/success-1.png | |||
failure_pic: https://i.ibb.co/wM2rbGS/fail-1.png | |||
trigger: | |||
branch: | |||
- deploy_develop |
@@ -0,0 +1,38 @@ | |||
## 职务风险防范第三方服务 | |||
### 请求中研接口 | |||
#### 中研接入公共单元 | |||
#### 1、风险特征处置结果接口 | |||
- 接口地址 | |||
> /ndToZy/pushFeatureDeal | |||
- 请求方法 | |||
> POST | |||
- 请求参数 | |||
参数 | 类型 | 是否必须 | 备注 | |||
----|----|----|---- | |||
featureId | String | 是 | 风险特征ID | |||
userId | String | 是 | 风险触发用户ID | |||
dealId | String | 是 | 处置人ID | |||
dealName | String | 是 | 处置人姓名 | |||
dealTime | String | 是 | 处置时间,格式YYYY-MM-DD HH:MI:SS | |||
dealStatus | String | 是 | 处置状态(1已处置、0未处置、2不处置) | |||
dealResult | String | 是 | 处置结果 | |||
- 接口返回数据 | |||
``` | |||
{ | |||
"status": 200, | |||
"message": "操作成功", | |||
"data":{ | |||
} | |||
} | |||
``` |
@@ -0,0 +1,147 @@ | |||
package main | |||
import ( | |||
"context" | |||
"flag" | |||
"fmt" | |||
"github.com/go-kit/kit/log" | |||
kitprometheus "github.com/go-kit/kit/metrics/prometheus" | |||
kitzipkin "github.com/go-kit/kit/tracing/zipkin" | |||
"github.com/openzipkin/zipkin-go" | |||
zipkinhttp "github.com/openzipkin/zipkin-go/reporter/http" | |||
stdprometheus "github.com/prometheus/client_golang/prometheus" | |||
"github.com/tal-tech/go-zero/core/logx" | |||
"gorm.io/gorm" | |||
"job_risk_third/config" | |||
"job_risk_third/discover" | |||
"job_risk_third/internal/endpoints" | |||
"job_risk_third/internal/services" | |||
"job_risk_third/internal/transports" | |||
"job_risk_third/loggers" | |||
"job_risk_third/model" | |||
"net/http" | |||
"os" | |||
"os/signal" | |||
"syscall" | |||
) | |||
var configFile = flag.String("f", "config/job_risk_third.json", "the config file") | |||
func main() { | |||
flag.Parse() | |||
errChan := make(chan error) | |||
ctx := context.Background() | |||
config.Cfg = config.LoadConfig(*configFile) | |||
logConf := logx.LogConf{ | |||
ServiceName: config.Cfg.Get("name").(string), | |||
Mode: config.Cfg.Get("log.mode").(string), | |||
Path: config.Cfg.Get("log.path").(string), | |||
Level: config.Cfg.Get("log.level").(string), | |||
Compress: config.Cfg.Get("log.compress").(bool), | |||
KeepDays: config.Cfg.GetInt("log.keep_days"), | |||
StackCooldownMillis: config.Cfg.GetInt("log.stack_cooldown_millis"), | |||
} | |||
zipkinConf := config.ZipkinConfig{ | |||
HostConfig: config.HostConfig{ | |||
Address: config.Cfg.Get("zipkin.host.address").(string), | |||
Port: config.Cfg.GetInt("zipkin.host.port"), | |||
}, | |||
ZipkinURL: config.Cfg.Get("zipkin.url").(string), | |||
} | |||
consulConf := config.ConsulConfig{ | |||
HostConfig: config.HostConfig{ | |||
Address: config.Cfg.Get("consul.host.address").(string), | |||
Port: config.Cfg.GetInt("consul.host.port"), | |||
}, | |||
ServiceId: config.Cfg.Get("consul.service_id").(string), | |||
} | |||
logx.MustSetup(logConf) | |||
var logger = loggers.New() | |||
dbConf := &gorm.Config{ | |||
SkipDefaultTransaction: false, | |||
Logger: logger, | |||
} | |||
//初始化数据库和连接缓存 | |||
model.New(config.Cfg.GetString("connstring"), dbConf) | |||
fieldKeys := []string{"method"} | |||
requestCount := kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{ | |||
Namespace: config.Cfg.Get("name").(string), | |||
Subsystem: "job_risk_third_service", | |||
Name: "request_count", | |||
Help: "收到的请求数", | |||
}, fieldKeys) | |||
requestLatency := kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{ | |||
Namespace: config.Cfg.Get("name").(string), | |||
Subsystem: "job_risk_third_service", | |||
Name: "request_latency", | |||
Help: "请求的总持续时间(以微秒为单位)", | |||
}, fieldKeys) | |||
var zipkinTracer *zipkin.Tracer | |||
{ | |||
var ( | |||
err error | |||
hostPort = fmt.Sprintf("%s:%d", zipkinConf.Address, zipkinConf.Port) | |||
serviceName = "insigma_service" | |||
useNoopTracer = zipkinConf.ZipkinURL == "" | |||
reporters = zipkinhttp.NewReporter(zipkinConf.ZipkinURL) | |||
) | |||
defer reporters.Close() | |||
zEP, _ := zipkin.NewEndpoint(serviceName, hostPort) | |||
zipkinTracer, err = zipkin.NewTracer( | |||
reporters, zipkin.WithLocalEndpoint(zEP), zipkin.WithNoopTracer(useNoopTracer), | |||
) | |||
if err != nil { | |||
logx.Error(err) | |||
os.Exit(1) | |||
} | |||
logx.Slow("Zipkin", "type", "Native", "URL", zipkinConf.ZipkinURL) | |||
} | |||
go func() { | |||
c := make(chan os.Signal, 1) | |||
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) | |||
errChan <- fmt.Errorf("%s", <-c) | |||
}() | |||
var svr services.JobRiskThirdServices | |||
svr = services.JobRiskThirdService{} | |||
svr = services.Metrics(requestCount, requestLatency)(svr) | |||
pushFeatureDealEndpoint := endpoints.MakePushFeatureDealEndpoint(svr) | |||
pushFeatureDealEndpoint = kitzipkin.TraceEndpoint(zipkinTracer, "push_feature_deal")(pushFeatureDealEndpoint) | |||
pushUserInfoEndpoint := endpoints.MakePushUserInfoEndpoint(svr) | |||
pushUserInfoEndpoint = kitzipkin.TraceEndpoint(zipkinTracer, "push_user_info")(pushUserInfoEndpoint) | |||
pushFeatureInfoEndpoint := endpoints.MakePushFeatureInfoEndpoint(svr) | |||
pushFeatureInfoEndpoint = kitzipkin.TraceEndpoint(zipkinTracer, "push_feature_info")(pushFeatureInfoEndpoint) | |||
//创建健康检查的Endpoint | |||
healthEndpoint := endpoints.MakeHealthCheckEndpoint(svr) | |||
healthEndpoint = kitzipkin.TraceEndpoint(zipkinTracer, "third_health_endpoint")(healthEndpoint) | |||
endpts := endpoints.JobRiskThirdEndpoint{ | |||
PushFeatureDealEndpoint: pushFeatureDealEndpoint, | |||
PushUserInfoEndpoint: pushUserInfoEndpoint, | |||
PushFeatureInfoEndpoint: pushFeatureInfoEndpoint, | |||
HealthCheckEndpoint: healthEndpoint, | |||
} | |||
r := transports.MakeHttpHandler(ctx, endpts, zipkinTracer) | |||
var l log.Logger | |||
{ | |||
l = log.NewLogfmtLogger(os.Stderr) | |||
l = log.With(l, "ts", log.DefaultTimestampUTC) | |||
l = log.With(l, "caller", log.DefaultCaller) | |||
} | |||
//创建注册对象 | |||
registar := discover.Register(consulConf.Address, fmt.Sprintf("%d", consulConf.Port), config.Cfg.Get("http.domain.address").(string), | |||
fmt.Sprintf("%d", config.Cfg.GetInt("http.domain.port")), consulConf.ServiceId, config.Cfg.Get("name").(string), l) | |||
go func() { | |||
fmt.Printf("Http Server start at port %.f \n", config.Cfg.Get("http.host.port")) | |||
//启动前执行注册 | |||
registar.Register() | |||
errChan <- http.ListenAndServe(fmt.Sprintf(":%.f", config.Cfg.Get("http.host.port")), r) | |||
}() | |||
err := <-errChan | |||
//服务退出取消注册 | |||
registar.Deregister() | |||
logx.Error(err) | |||
} |
@@ -0,0 +1,52 @@ | |||
package config | |||
import ( | |||
"github.com/spf13/viper" | |||
"github.com/tal-tech/go-zero/core/logx" | |||
) | |||
type HostConfig struct { | |||
Address string `json:"address"` | |||
Port int `json:"port"` | |||
} | |||
type ApplicationConfig struct { | |||
Name string `json:"name"` | |||
Rpc HostConfig `json:"rpc"` | |||
} | |||
type Prometheus struct { | |||
HostConfig | |||
} | |||
type ZipkinConfig struct { | |||
HostConfig | |||
ZipkinURL string `json:"url"` | |||
} | |||
type ConsulConfig struct { | |||
HostConfig | |||
ServiceId string `json:"service_id"` | |||
} | |||
type RedisConfig struct { | |||
HostConfig | |||
Pass string `json:"pass"` | |||
DB int `json:"db"` | |||
PoolSize int `json:"pool_size"` | |||
} | |||
var ( | |||
Cfg *viper.Viper | |||
) | |||
func LoadConfig(path string) (config *viper.Viper) { | |||
config = viper.New() | |||
config.SetConfigFile(path) | |||
// 读取配置 | |||
if err := config.ReadInConfig(); err != nil { | |||
logx.Error(err) | |||
} | |||
logx.Infof("config %#v", config.Get("http")) | |||
return | |||
} |
@@ -0,0 +1,70 @@ | |||
{ | |||
"name": "job_risk_third", | |||
"http": { | |||
"host": { | |||
"address": "0.0.0.0", | |||
"port": 8016 | |||
}, | |||
"is_ssl": false, | |||
"domain":{ | |||
"address": "172.17.0.1", | |||
"port": 8016 | |||
} | |||
}, | |||
"rpc": { | |||
"address": "0.0.0.0", | |||
"port": 8017 | |||
}, | |||
"prometheus":{ | |||
"host": { | |||
"address": "127.0.0.1", | |||
"port": 9091 | |||
}, | |||
"path": "/metrics" | |||
}, | |||
"zipkin": { | |||
"host": { | |||
"address": "127.0.0.1", | |||
"port": 9091 | |||
}, | |||
"url": "http://zipkin.ningdatech.com/api/v2/spans" | |||
}, | |||
"consul": { | |||
"host": { | |||
"address": "http://consul.ningdatech.com", | |||
"port": 80 | |||
}, | |||
"service_id": "453c150ad53744de9d479aea255079f1" | |||
}, | |||
"zy_host": { | |||
"address": "http://183.129.215.106", | |||
"port": 13422 | |||
}, | |||
"sign_server":{ | |||
"url": "http://sign.ningdatech.com/encrypt" | |||
}, | |||
"sso": { | |||
"url": "http://172.18.25.79:8080", | |||
"app_name": "ndzwfxff", | |||
"login": "/wsite/sso/verify", | |||
"logout": "/wsite/sso/logout" | |||
}, | |||
"log": { | |||
"mode": "console", | |||
"path": "/dev/log/job_risk", | |||
"level": "info", | |||
"compress": true, | |||
"keep_days": 1, | |||
"stack_cool_down_millis": 100 | |||
}, | |||
"redis":{ | |||
"host": { | |||
"address": "120.26.44.207", | |||
"port": 26379 | |||
}, | |||
"pass": "Ndkj1234", | |||
"db": 10, | |||
"pool_size": 10 | |||
}, | |||
"connstring": "root:NingdaKeji123!@tcp(120.26.44.207:23306)/ningda_dev_plat_new?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai" | |||
} |
@@ -0,0 +1,52 @@ | |||
package discover | |||
import ( | |||
"github.com/go-kit/kit/log" | |||
"github.com/go-kit/kit/sd" | |||
"github.com/go-kit/kit/sd/consul" | |||
"github.com/hashicorp/consul/api" | |||
"github.com/tal-tech/go-zero/core/logx" | |||
"os" | |||
"strconv" | |||
) | |||
func Register(consulHost, consulPort, svcHost, svcPort, svrId, svrName string, logger log.Logger) (registar sd.Registrar) { | |||
// 创建Consul客户端连接 | |||
var client consul.Client | |||
{ | |||
consulCfg := api.DefaultConfig() | |||
consulCfg.Address = consulHost + ":" + consulPort | |||
consulClient, err := api.NewClient(consulCfg) | |||
if err != nil { | |||
logx.Error("create consul client error:", err) | |||
os.Exit(1) | |||
} | |||
client = consul.NewClient(consulClient) | |||
} | |||
// 设置Consul对服务健康检查的参数 | |||
check := api.AgentServiceCheck{ | |||
HTTP: "http://" + svcHost + ":" + svcPort + "/health", | |||
Interval: "10s", | |||
Timeout: "1s", | |||
Notes: "Consul check service health status.", | |||
} | |||
port, _ := strconv.Atoi(svcPort) | |||
//设置微服务想Consul的注册信息 | |||
reg := api.AgentServiceRegistration{ | |||
ID: svrId, | |||
Name: "prometheus-" + svrName, | |||
Address: svcHost, | |||
Port: port, | |||
Tags: []string{svrName, "JobRiskBizServices"}, | |||
Check: &check, | |||
} | |||
// 执行注册 | |||
registar = consul.NewRegistrar(client, ®, logger) | |||
return | |||
} |
@@ -0,0 +1,15 @@ | |||
![结果]([TPL_STATUS_PIC]) | |||
仓库:[TPL_REPO_SHORT_NAME] | |||
分支:[TPL_COMMIT_BRANCH] | |||
commit: [查看]([TPL_COMMIT_LINK]) | |||
结果:[TPL_BUILD_STATUS] | |||
耗时:[TPL_BUILD_CONSUMING]s | |||
作者:[[TPL_AUTHOR_NAME]([TPL_AUTHOR_EMAIL])](mailto:[TPL_AUTHOR_EMAIL]) | |||
详情:[查看]([TPL_BUILD_LINK]) |
@@ -0,0 +1,20 @@ | |||
module job_risk_third | |||
go 1.14 | |||
require ( | |||
github.com/VividCortex/gohistogram v1.0.0 // indirect | |||
github.com/go-kit/kit v0.9.0 | |||
github.com/go-redis/redis v6.15.7+incompatible | |||
github.com/google/uuid v1.1.1 | |||
github.com/gorilla/mux v1.8.0 | |||
github.com/hashicorp/consul/api v1.1.0 | |||
github.com/juju/ratelimit v1.0.1 | |||
github.com/openzipkin/zipkin-go v0.2.5 | |||
github.com/prometheus/client_golang v1.5.1 | |||
github.com/spf13/viper v1.7.1 | |||
github.com/tal-tech/go-zero v1.0.20 | |||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 | |||
gorm.io/driver/mysql v1.0.2 | |||
gorm.io/gorm v1.20.2 | |||
) |
@@ -0,0 +1,77 @@ | |||
package endpoints | |||
import ( | |||
"context" | |||
"github.com/go-kit/kit/endpoint" | |||
"job_risk_third/internal/proto" | |||
"job_risk_third/internal/services" | |||
) | |||
type JobRiskThirdEndpoint struct { | |||
PushFeatureDealEndpoint endpoint.Endpoint | |||
PushUserInfoEndpoint endpoint.Endpoint | |||
PushFeatureInfoEndpoint endpoint.Endpoint | |||
HealthCheckEndpoint endpoint.Endpoint | |||
} | |||
// MakeHealthCheckEndpoint 创建健康检查Endpoint | |||
func MakeHealthCheckEndpoint(svc services.JobRiskThirdServices) endpoint.Endpoint { | |||
return func(ctx context.Context, request interface{}) (response interface{}, err error) { | |||
status := svc.HealthCheck() | |||
return proto.HealthResponse{Status: status}, nil | |||
} | |||
} | |||
//MakePushFeatureDealEndpoint 接收风险特征处置结果Endpoint | |||
func MakePushFeatureDealEndpoint(svc services.JobRiskThirdServices) endpoint.Endpoint { | |||
return func(ctx context.Context, request interface{}) (response interface{}, err error) { | |||
req := request.(proto.PushFeatureDealRequest) | |||
err = svc.PushFeatureDeal(req) | |||
if err != nil { | |||
return proto.BaseResponse{ | |||
RespCode: 500, | |||
RespMsg: "接收风险特征处置结果失败", | |||
}, err | |||
} | |||
return proto.BaseResponse{ | |||
RespCode: 200, | |||
RespMsg: "成功", | |||
}, err | |||
} | |||
} | |||
//MakePushUserInfoEndpoint 获取用户信息接口 | |||
func MakePushUserInfoEndpoint(svc services.JobRiskThirdServices) endpoint.Endpoint { | |||
return func(ctx context.Context, request interface{}) (response interface{}, err error) { | |||
req := request.(proto.PushUserInfoRequest) | |||
err = svc.PushUserInfo(req) | |||
if err != nil { | |||
return proto.BaseResponse{ | |||
RespCode: 500, | |||
RespMsg: "获取用户信息失败", | |||
}, err | |||
} | |||
return proto.BaseResponse{ | |||
RespCode: 200, | |||
RespMsg: "成功", | |||
}, err | |||
} | |||
} | |||
//MakePushFeatureInfoEndpoint 推送的风险结果信息 | |||
func MakePushFeatureInfoEndpoint(svc services.JobRiskThirdServices) endpoint.Endpoint { | |||
return func(ctx context.Context, request interface{}) (response interface{}, err error) { | |||
req := request.(proto.PushFeatureInfoRequest) | |||
err = svc.PushFeatureInfo(req) | |||
if err != nil { | |||
return proto.BaseResponse{ | |||
RespCode: 500, | |||
RespMsg: "推送风险结果信息失败", | |||
}, err | |||
} | |||
return proto.BaseResponse{ | |||
RespCode: 200, | |||
RespMsg: "成功", | |||
}, err | |||
} | |||
} |
@@ -0,0 +1,75 @@ | |||
package proto | |||
const ( | |||
//PushFeatureDeal 接收风险特征处置结果接口 | |||
PushFeatureDeal = "/ndToZy/pushFeatureDeal" | |||
//PushUserInfo 获取用户信息接口 | |||
PushUserInfo = "/ndToZy/pushUserInfo" | |||
//PushFeatureInfo 推送的风险结果信息 | |||
PushFeatureInfo = "/ndToZy/pushFeatureInfo" | |||
) | |||
//SignServiceRequest 签名服务接口请求格式 | |||
type SignServiceRequest struct { | |||
Obj string `json:"obj"` | |||
} | |||
//ZyBaseRequest 中研服务请求 | |||
type ZyBaseRequest struct { | |||
Data string `json:"data"` | |||
Sign string `json:"sign"` | |||
Source string `json:"source"` | |||
Salt string `json:"salt"` | |||
Key string `json:"key"` | |||
} | |||
//PushFeatureDealRequest 接收风险特征处置结果接口 | |||
type PushFeatureDealRequest struct { | |||
FeatureId string `json:"featureId" description:"风险特征ID"` | |||
UserId string `json:"userId" description:"风险触发用户ID"` | |||
ObjectId string `json:"objectId" description:"风险对象ID,4.1接口推送的objectId"` | |||
DealId string `json:"dealId" description:"处置人ID"` | |||
DealName string `json:"dealName" description:"处置人姓名"` | |||
DealTime string `json:"dealTime" description:"处置时间,格式YYYY-MM-DD HH:MI:SS"` | |||
DealStatus string `json:"dealStatus" description:"处置状态(1已处置、0未处置、2不处置)"` | |||
DealResult string `json:"dealResult" description:"处置结果"` | |||
} | |||
//PushUserInfoRequest 获取用户信息接口 | |||
type PushUserInfoRequest struct { | |||
UserId string `json:"userId" description:"用户ID"` | |||
UserName string `json:"userName" description:"用户名"` | |||
Name string `json:"name" description:"姓名"` | |||
Position string `json:"position" description:"岗位"` | |||
Job string `json:"job" description:"职务"` | |||
DeptId string `json:"deptId" description:"所在部门/业务处室编码"` | |||
DeptName string `json:"deptName" description:"所在部门/业务处室名称"` | |||
LogTime string `json:"logTime" description:"登录时间"` | |||
LogError string `json:"logError" description:"登录密码错误次数"` | |||
Regorg string `json:"regorg" description:"登记机关"` | |||
} | |||
//PushFeatureInfo 推送的风险结果信息 | |||
type PushFeatureInfoRequest struct { | |||
FeatureId string `json:"featureId" description:"风险特征ID"` | |||
FeatureName string `json:"featureName" description:"风险名称"` | |||
FeatureLevel string `json:"featureLevel" description:"风险等级"` | |||
FeatureDeptId string `json:"featureDeptId" description:"风险所属部门"` | |||
FeatureTime string `json:"featureTime" description:"触发时间,精确到时分秒"` | |||
ObjectList []struct { | |||
ObjId string `json:"objId" description:"对象ID(用户ID)"` | |||
ObjName string `json:"objName" description:"对象名称(用户姓名)"` | |||
ObjRegorg string `json:"objRegorg" description:"对象所在登记机关"` | |||
ObjDeptid string `json:"objDeptid" description:"对象所在部门"` | |||
ObjPosition string `json:"objPosition" description:"对象所在岗位"` | |||
IsDeal string `json:"isDeal" description:"是否处置(1已处置;0未处置)"` | |||
DealId string `json:"dealId" description:"处置人ID"` | |||
DealName string `json:"dealName" description:"处置人姓名"` | |||
DealTime string `json:"dealTime" description:"处置时间"` | |||
DealStatus string `json:"dealStatus" description:"处置状态(0未处置;1已处置)"` | |||
DealResult string `json:"dealResult" description:"处置结果"` | |||
} `json:"objectList" description:"风险对象列表"` | |||
} | |||
// HealthRequest 健康检查请求结构 | |||
type HealthRequest struct{} |
@@ -0,0 +1,21 @@ | |||
package proto | |||
type BaseResponse struct { | |||
RespCode int `json:"resp_code"` | |||
RespMsg string `json:"resp_msg"` | |||
Data interface{} `json:"data,omitempty"` | |||
} | |||
type SignResponse struct { | |||
Data string `json:"data"` | |||
} | |||
type ZyResponse struct { | |||
Status int `json:"status"` | |||
Message string `json:"message"` | |||
} | |||
// HealthResponse 健康检查响应结构 | |||
type HealthResponse struct { | |||
Status bool `json:"status"` | |||
} |
@@ -0,0 +1,86 @@ | |||
package services | |||
import ( | |||
"context" | |||
"fmt" | |||
"github.com/go-kit/kit/endpoint" | |||
"github.com/go-kit/kit/metrics" | |||
"github.com/juju/ratelimit" | |||
"golang.org/x/time/rate" | |||
"job_risk_third/internal/proto" | |||
"time" | |||
) | |||
var ErrLimitExceed = fmt.Errorf("Rate limit exceed!") | |||
// NewTokenBucketLimitterWithJuju 使用juju/ratelimit创建限流中间件 | |||
func NewTokenBucketLimitterWithJuju(bkt *ratelimit.Bucket) endpoint.Middleware { | |||
return func(next endpoint.Endpoint) endpoint.Endpoint { | |||
return func(ctx context.Context, request interface{}) (response interface{}, err error) { | |||
if bkt.TakeAvailable(1) == 0 { | |||
return nil, ErrLimitExceed | |||
} | |||
return next(ctx, request) | |||
} | |||
} | |||
} | |||
// NewTokenBucketLimitterWithBuildIn 使用x/time/rate创建限流中间件 | |||
func NewTokenBucketLimitterWithBuildIn(bkt *rate.Limiter) endpoint.Middleware { | |||
return func(next endpoint.Endpoint) endpoint.Endpoint { | |||
return func(ctx context.Context, request interface{}) (response interface{}, err error) { | |||
if !bkt.Allow() { | |||
return nil, ErrLimitExceed | |||
} | |||
return next(ctx, request) | |||
} | |||
} | |||
} | |||
// metricMiddleware 定义监控中间件,嵌入Service | |||
// 新增监控指标项:requestCount和requestLatency | |||
type metricMiddleware struct { | |||
JobRiskThirdServices | |||
requestCount metrics.Counter | |||
requestLatency metrics.Histogram | |||
} | |||
// Metrics 封装监控方法 | |||
func Metrics(requestCount metrics.Counter, requestLatency metrics.Histogram) ServiceMiddleware { | |||
return func(next JobRiskThirdServices) JobRiskThirdServices { | |||
return metricMiddleware{ | |||
next, | |||
requestCount, | |||
requestLatency} | |||
} | |||
} | |||
func (mw metricMiddleware) PushFeatureDeal(req proto.PushFeatureDealRequest) error { | |||
defer func(beign time.Time) { | |||
lvs := []string{"method", "PushFeatureDeal"} | |||
mw.requestCount.With(lvs...).Add(1) | |||
mw.requestLatency.With(lvs...).Observe(time.Since(beign).Seconds()) | |||
}(time.Now()) | |||
b := mw.JobRiskThirdServices.PushFeatureDeal(req) | |||
return b | |||
} | |||
func (mw metricMiddleware) PushUserInfo(req proto.PushUserInfoRequest) error { | |||
defer func(beign time.Time) { | |||
lvs := []string{"method", "PushUserInfo"} | |||
mw.requestCount.With(lvs...).Add(1) | |||
mw.requestLatency.With(lvs...).Observe(time.Since(beign).Seconds()) | |||
}(time.Now()) | |||
return mw.JobRiskThirdServices.PushUserInfo(req) | |||
} | |||
func (mw metricMiddleware) PushFeatureInfo(req proto.PushFeatureInfoRequest) error { | |||
defer func(beign time.Time) { | |||
lvs := []string{"method", "PushFeatureInfo"} | |||
mw.requestCount.With(lvs...).Add(1) | |||
mw.requestLatency.With(lvs...).Observe(time.Since(beign).Seconds()) | |||
}(time.Now()) | |||
return mw.JobRiskThirdServices.PushFeatureInfo(req) | |||
} |
@@ -0,0 +1,151 @@ | |||
package services | |||
import ( | |||
"encoding/json" | |||
"fmt" | |||
"github.com/tal-tech/go-zero/core/logx" | |||
"job_risk_third/config" | |||
"job_risk_third/internal/proto" | |||
"job_risk_third/model" | |||
"job_risk_third/pkg/utils" | |||
) | |||
//职务风险防范系统第三方请求业务模块 | |||
type JobRiskThirdServices interface { | |||
//PushFeatureDeal 接收风险特征处置结果接口 | |||
PushFeatureDeal(req proto.PushFeatureDealRequest) error | |||
//PushUserInfo 获取用户信息接口 | |||
PushUserInfo(req proto.PushUserInfoRequest) error | |||
//PushFeatureInfo 推送的风险结果信息 | |||
PushFeatureInfo(req proto.PushFeatureInfoRequest) error | |||
// HealthCheck check service health status | |||
HealthCheck() bool | |||
} | |||
type ServiceMiddleware func(JobRiskThirdServices) JobRiskThirdServices | |||
type JobRiskThirdService struct { | |||
} | |||
// HealthCheck implement Service method | |||
// 用于检查服务的健康状态,这里仅仅返回true。 | |||
func (s JobRiskThirdService) HealthCheck() bool { | |||
return true | |||
} | |||
//PushFeatureDeal 接收风险特征处置结果接口 | |||
func (s JobRiskThirdService) PushFeatureDeal(req proto.PushFeatureDealRequest) error { | |||
jsBody, _ := json.Marshal(req) | |||
body, err := RequestSign(jsBody, proto.PushFeatureDeal) | |||
if err != nil { | |||
return err | |||
} | |||
res := new(proto.ZyResponse) | |||
err = json.Unmarshal(body, res) | |||
if err != nil { | |||
logx.Errorf("PushFeatureDeal call error: %s", err) | |||
return err | |||
} | |||
if res.Status != 200 { | |||
logx.Errorf("PushFeatureDeal call error: %s", res.Message) | |||
return fmt.Errorf(res.Message) | |||
} | |||
return nil | |||
} | |||
//PushUserInfo 获取用户信息接口 | |||
func (s JobRiskThirdService) PushUserInfo(req proto.PushUserInfoRequest) error { | |||
jsBody, _ := json.Marshal(req) | |||
body, err := RequestSign(jsBody, proto.PushUserInfo) | |||
if err != nil { | |||
return err | |||
} | |||
res := new(proto.ZyResponse) | |||
err = json.Unmarshal(body, res) | |||
if err != nil { | |||
logx.Errorf("PushUserInfo call error: %s", err) | |||
return err | |||
} | |||
if res.Status != 200 { | |||
logx.Errorf("PushUserInfo call error: %s", res.Message) | |||
return fmt.Errorf(res.Message) | |||
} | |||
return nil | |||
} | |||
//PushFeatureInfo 推送的风险结果信息 | |||
func (s JobRiskThirdService) PushFeatureInfo(req proto.PushFeatureInfoRequest) error { | |||
jsBody, _ := json.Marshal(req) | |||
body, err := RequestSign(jsBody, proto.PushFeatureInfo) | |||
if err != nil { | |||
return err | |||
} | |||
res := new(proto.ZyResponse) | |||
err = json.Unmarshal(body, res) | |||
if err != nil { | |||
logx.Errorf("PushFeatureInfo call error: %s", err) | |||
return err | |||
} | |||
if res.Status != 200 { | |||
logx.Errorf("PushFeatureInfo call error: %s", res.Message) | |||
return fmt.Errorf(res.Message) | |||
} | |||
return nil | |||
} | |||
func RequestSign(data []byte, url string) (body []byte, err error) { | |||
item := new(model.TbRequestThirdLog) | |||
reqMap := make(map[string]string) | |||
reqMap["obj"] = string(data) | |||
headerMap := make(map[string]string) | |||
headerMap["Content-Type"] = "application/x-www-form-urlencoded" | |||
b, err := utils.HttpDo(config.Cfg.GetString("sign_server.url"), "POST", reqMap, headerMap) | |||
if err != nil { | |||
logx.Error(err) | |||
return nil, err | |||
} | |||
item.SourceData = string(data) | |||
item.CryptoData = string(b) | |||
signResponse := new(proto.SignResponse) | |||
err = json.Unmarshal(b, signResponse) | |||
if err != nil { | |||
logx.Error(err) | |||
return nil, err | |||
} | |||
requestStruct := new(proto.ZyBaseRequest) | |||
err = json.Unmarshal([]byte(signResponse.Data), requestStruct) | |||
if err != nil { | |||
logx.Error(err) | |||
return nil, err | |||
} | |||
requestMap := make(map[string]string) | |||
requestId := utils.NewId() | |||
requestMap["data"] = requestStruct.Data | |||
requestMap["key"] = requestStruct.Key | |||
requestMap["salt"] = requestStruct.Salt | |||
requestMap["sign"] = requestStruct.Sign | |||
requestMap["source"] = requestStruct.Source | |||
//decryptMap := make(map[string]string) | |||
//decryptMap["reqData"]=string(b) | |||
//b, err = utils.HttpDo("http://sign.ningdatech.com/decrypt","POST",decryptMap,headerMap) | |||
//if err!= nil{ | |||
// logx.Error(err) | |||
//} | |||
//logx.Info(string(b)) | |||
headerMap["Content-Type"] = "application/json" | |||
resBody, err := utils.HttpDo(fmt.Sprintf("%s:%d%s", config.Cfg.GetString("zy_host.address"), | |||
config.Cfg.GetInt("zy_host.port"), url), "POST", requestMap, headerMap) | |||
if err != nil { | |||
logx.Error(err) | |||
return nil, err | |||
} | |||
item.RequestId = requestId | |||
item.RequestUri = fmt.Sprintf("%s:%d%s", config.Cfg.GetString("zy_host.address"), | |||
config.Cfg.GetInt("zy_host.port"), url) | |||
item.ResultData = string(resBody) | |||
go model.DB.Create(item) | |||
return resBody, err | |||
} |
@@ -0,0 +1,21 @@ | |||
package transports | |||
import ( | |||
"context" | |||
"encoding/json" | |||
"job_risk_third/internal/proto" | |||
"net/http" | |||
) | |||
//自定义一个解码error函数 | |||
func MyErrorEncoder(_ context.Context, err error, w http.ResponseWriter) { | |||
res := proto.BaseResponse{ | |||
RespCode: 500, | |||
RespMsg: err.Error(), | |||
} | |||
contentType := "application/json,charset=utf-8" | |||
w.Header().Set("content-type", contentType) | |||
w.WriteHeader(200) | |||
body, _ := json.Marshal(res) | |||
w.Write(body) | |||
} |
@@ -0,0 +1,106 @@ | |||
package transports | |||
import ( | |||
"context" | |||
"encoding/json" | |||
"github.com/go-kit/kit/tracing/zipkin" | |||
kithttp "github.com/go-kit/kit/transport/http" | |||
"github.com/gorilla/mux" | |||
gozipkin "github.com/openzipkin/zipkin-go" | |||
"github.com/prometheus/client_golang/prometheus/promhttp" | |||
"github.com/tal-tech/go-zero/core/logx" | |||
"job_risk_third/internal/endpoints" | |||
"job_risk_third/internal/proto" | |||
"job_risk_third/pkg/utils" | |||
"net/http" | |||
) | |||
// MakeHttpHandler make http handler use mux | |||
func MakeHttpHandler(_ context.Context, endpoint endpoints.JobRiskThirdEndpoint, zipkinTracer *gozipkin.Tracer) http.Handler { | |||
r := mux.NewRouter() | |||
zipkinServer := zipkin.HTTPServerTrace(zipkinTracer, zipkin.Name("http-transport")) | |||
options := []kithttp.ServerOption{ | |||
kithttp.ServerErrorEncoder(MyErrorEncoder), | |||
zipkinServer, | |||
} | |||
r.Methods("POST").Path("/api/v1/push/feature_deal").Handler(kithttp.NewServer( | |||
endpoint.PushFeatureDealEndpoint, | |||
decodePushFeatureDealRequest, | |||
encodeResponse, | |||
options..., | |||
)) | |||
r.Methods("POST").Path("/api/v1/push/user_info").Handler(kithttp.NewServer( | |||
endpoint.PushUserInfoEndpoint, | |||
decodePushUserInfoRequest, | |||
encodeResponse, | |||
options..., | |||
)) | |||
r.Methods("POST").Path("/api/v1/push/feature_info").Handler(kithttp.NewServer( | |||
endpoint.PushFeatureInfoEndpoint, | |||
decodePushFeatureInfoRequest, | |||
encodeResponse, | |||
options..., | |||
)) | |||
// create health check handler | |||
r.Methods("GET").Path("/health").Handler(kithttp.NewServer( | |||
endpoint.HealthCheckEndpoint, | |||
decodeHealthCheckRequest, | |||
encodeResponse, | |||
options..., | |||
)) | |||
r.Path("/metrics").Handler(promhttp.Handler()) | |||
return r | |||
} | |||
// decodeHealthCheckRequest decode request | |||
func decodeHealthCheckRequest(_ context.Context, _ *http.Request) (interface{}, error) { | |||
return proto.HealthRequest{}, nil | |||
} | |||
func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { | |||
w.Header().Set("Content-Type", "application/json;charset=utf-8") | |||
return json.NewEncoder(w).Encode(response) | |||
} | |||
func decodePushFeatureDealRequest(_ context.Context, r *http.Request) (interface{}, error) { | |||
if err := utils.Validation(r); err != nil { | |||
return nil, err | |||
} | |||
body := utils.Param(r, "__json_param__") | |||
var item proto.PushFeatureDealRequest | |||
err := json.Unmarshal([]byte(body), &item) | |||
if err != nil { | |||
logx.Error(err) | |||
return nil, utils.ErrorBadRequest | |||
} | |||
return item, nil | |||
} | |||
func decodePushUserInfoRequest(_ context.Context, r *http.Request) (interface{}, error) { | |||
if err := utils.Validation(r); err != nil { | |||
return nil, err | |||
} | |||
body := utils.Param(r, "__json_param__") | |||
var item proto.PushUserInfoRequest | |||
err := json.Unmarshal([]byte(body), &item) | |||
if err != nil { | |||
logx.Error(err) | |||
return nil, utils.ErrorBadRequest | |||
} | |||
return item, nil | |||
} | |||
func decodePushFeatureInfoRequest(_ context.Context, r *http.Request) (interface{}, error) { | |||
if err := utils.Validation(r); err != nil { | |||
return nil, err | |||
} | |||
body := utils.Param(r, "__json_param__") | |||
var item proto.PushFeatureInfoRequest | |||
err := json.Unmarshal([]byte(body), &item) | |||
if err != nil { | |||
logx.Error(err) | |||
return nil, utils.ErrorBadRequest | |||
} | |||
return item, nil | |||
} |
@@ -0,0 +1,119 @@ | |||
package loggers | |||
import ( | |||
"context" | |||
"github.com/tal-tech/go-zero/core/logx" | |||
ll "gorm.io/gorm/logger" | |||
"gorm.io/gorm/utils" | |||
"time" | |||
) | |||
// LogLevel | |||
type LogLevel int | |||
// Writer log writer interface | |||
type Writer interface { | |||
Printf(string, ...interface{}) | |||
} | |||
// Interface logger interface | |||
type Interface interface { | |||
LogMode(LogLevel) Interface | |||
Info(context.Context, string, ...interface{}) | |||
Warn(context.Context, string, ...interface{}) | |||
Error(context.Context, string, ...interface{}) | |||
Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) | |||
} | |||
var ( | |||
//Discard = New(log.New(ioutil.Discard, "", log.LstdFlags), Config{}) | |||
//Default = New(log.New(os.Stdout, "\r\n", log.LstdFlags), Config{ | |||
// SlowThreshold: 100 * time.Millisecond, | |||
// LogLevel: Warn, | |||
// Colorful: true, | |||
//}) | |||
//Recorder = traceRecorder{Interface: Default} | |||
) | |||
func New() ll.Interface { | |||
return &logger{} | |||
} | |||
type logger struct { | |||
Writer | |||
ll.Config | |||
infoStr, warnStr, errStr string | |||
traceStr, traceErrStr, traceWarnStr string | |||
} | |||
// LogMode log mode | |||
func (l logger) LogMode(level ll.LogLevel) ll.Interface { | |||
newlogger := l | |||
newlogger.LogLevel = level | |||
return &newlogger | |||
} | |||
// Info print info | |||
func (l logger) Info(ctx context.Context, msg string, data ...interface{}) { | |||
logx.Infof(l.infoStr+msg, data...) | |||
} | |||
// Warn print warn messages | |||
func (l logger) Warn(ctx context.Context, msg string, data ...interface{}) { | |||
logx.Infof(l.warnStr+msg, data...) | |||
} | |||
// Error print error messages | |||
func (l logger) Error(ctx context.Context, msg string, data ...interface{}) { | |||
logx.Errorf(l.errStr+msg, data...) | |||
} | |||
// Trace print sql message | |||
func (l logger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) { | |||
if l.LogLevel > 0 { | |||
elapsed := time.Since(begin) | |||
switch { | |||
case err != nil && l.LogLevel >= ll.Error: | |||
sql, rows := fc() | |||
if rows == -1 { | |||
logx.Error(l.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, "-", sql) | |||
//l.Printf(l.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, "-", sql) | |||
} else { | |||
logx.Error(l.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, rows, sql) | |||
//l.Printf(l.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, rows, sql) | |||
} | |||
case elapsed > l.SlowThreshold && l.SlowThreshold != 0 && l.LogLevel >= ll.Warn: | |||
sql, rows := fc() | |||
if rows == -1 { | |||
logx.Info(l.traceWarnStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, "-", sql) | |||
} else { | |||
logx.Info(l.traceWarnStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, rows, sql) | |||
} | |||
case l.LogLevel >= ll.Info: | |||
sql, rows := fc() | |||
if rows == -1 { | |||
logx.Info(l.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, "-", sql) | |||
} else { | |||
logx.Info(l.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, rows, sql) | |||
} | |||
} | |||
} | |||
} | |||
type traceRecorder struct { | |||
Interface | |||
BeginAt time.Time | |||
SQL string | |||
RowsAffected int64 | |||
Err error | |||
} | |||
func (l traceRecorder) New() *traceRecorder { | |||
return &traceRecorder{Interface: l.Interface} | |||
} | |||
func (l *traceRecorder) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) { | |||
l.BeginAt = begin | |||
l.SQL, l.RowsAffected = fc() | |||
l.Err = err | |||
} |
@@ -0,0 +1,70 @@ | |||
package model | |||
import ( | |||
"fmt" | |||
"github.com/go-redis/redis" | |||
"github.com/tal-tech/go-zero/core/logx" | |||
"gorm.io/driver/mysql" | |||
"gorm.io/gorm" | |||
"job_risk_third/config" | |||
"os" | |||
"time" | |||
) | |||
var ( | |||
DB *gorm.DB | |||
Redis *redis.Client | |||
) | |||
func New(dsn string, cfg *gorm.Config) { | |||
DB, _ = newDbConnection(dsn, cfg) | |||
batchSyncTable([]interface{}{ | |||
&TbRequestThirdLog{}, | |||
}) | |||
} | |||
func NewRedis(redisConfig config.RedisConfig) { | |||
Redis = connectRedis(redisConfig) | |||
} | |||
func newDbConnection(dsn string, cfg *gorm.Config) (db *gorm.DB, err error) { | |||
db, err = gorm.Open(mysql.Open(dsn), cfg) | |||
if err != nil { | |||
logx.Error(err) | |||
os.Exit(-1) | |||
} | |||
return | |||
} | |||
func batchSyncTable(tables []interface{}) { | |||
if len(tables) > 0 { | |||
for _, v := range tables { | |||
if err := DB.AutoMigrate(v); err != nil { | |||
logx.Error(err) | |||
return | |||
} | |||
} | |||
} | |||
return | |||
} | |||
func connectRedis(c config.RedisConfig) *redis.Client { | |||
client := redis.NewClient(&redis.Options{ | |||
Addr: fmt.Sprintf("%s:%d", c.Address, c.Port), | |||
Password: c.Pass, // no password set | |||
DB: c.DB, // use default DB | |||
PoolSize: c.PoolSize, // Redis连接池大小 | |||
MaxRetries: 3, // 最大重试次数 | |||
IdleTimeout: 10 * time.Second, // 空闲链接超时时间 | |||
}) | |||
pong, err := client.Ping().Result() | |||
if err == redis.Nil { | |||
logx.Error("Redis异常,redis.Nil") | |||
} else if err != nil { | |||
logx.Errorf("Redis失败,%v", err) | |||
} else { | |||
logx.Infof("Redis连接成功,%s", pong) | |||
} | |||
return client | |||
} |
@@ -0,0 +1,13 @@ | |||
package model | |||
import "gorm.io/gorm" | |||
//第三方请求日志(中研) | |||
type TbRequestThirdLog struct { | |||
gorm.Model | |||
RequestId string `gorm:"type:VARCHAR(40)" description:"请求编号"` | |||
RequestUri string `gorm:"type:VARCHAR(200)" description:"请求地址"` | |||
SourceData string `gorm:"type:TEXT" description:"原始数据"` | |||
CryptoData string `gorm:"type:TEXT" description:"加密后的数据"` | |||
ResultData string `gorm:"type:TEXT" description:"请求返回的数据"` | |||
} |
@@ -0,0 +1,140 @@ | |||
package utils | |||
import ( | |||
"bytes" | |||
"crypto" | |||
"crypto/aes" | |||
"crypto/cipher" | |||
"crypto/rand" | |||
"crypto/rsa" | |||
"crypto/sha256" | |||
"crypto/x509" | |||
"encoding/base64" | |||
"fmt" | |||
"github.com/tal-tech/go-zero/core/logx" | |||
"math" | |||
"math/big" | |||
r "math/rand" | |||
"time" | |||
) | |||
// RSAEncrypt RSA加密 | |||
// plainText 要加密的数据 | |||
// publicKey 公钥匙内容 | |||
func RSAEncrypt(plainText []byte, publicKey string) (string, error) { | |||
key, _ := base64.StdEncoding.DecodeString(publicKey) | |||
pubKey, _ := x509.ParsePKIXPublicKey(key) | |||
logx.Infof("%v", pubKey) | |||
//解密pem格式的公钥 | |||
//block, _ := pem.Decode([]byte(publicKey)) | |||
//if block == nil { | |||
// return "", fmt.Errorf("public key error") | |||
//} | |||
//// 解析公钥 | |||
//pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) | |||
//if err != nil { | |||
// return "", err | |||
//} | |||
// 类型断言 | |||
pub := pubKey.(*rsa.PublicKey) | |||
encryptedData, err := rsa.EncryptPKCS1v15(rand.Reader, pub, plainText) | |||
return base64.StdEncoding.EncodeToString(encryptedData), err | |||
} | |||
// RSADecrypt RSA解密 | |||
// cipherText 需要解密的byte数据 | |||
// privateKey 私钥匙内容 | |||
func RSADecrypt(cipherText, privateKey string) (string, error) { | |||
encryptedDecodeBytes, err := base64.StdEncoding.DecodeString(cipherText) | |||
if err != nil { | |||
return "", err | |||
} | |||
key, _ := base64.StdEncoding.DecodeString(privateKey) | |||
prvKey, _ := x509.ParsePKCS1PrivateKey(key) | |||
originalData, err := rsa.DecryptPKCS1v15(rand.Reader, prvKey, encryptedDecodeBytes) | |||
return string(originalData), err | |||
} | |||
func RSAPriEncrypt(cipherText, privateKey string) (string, error) { | |||
key, _ := base64.StdEncoding.DecodeString(privateKey) | |||
prvKey, _ := x509.ParsePKCS1PrivateKey(key) | |||
rng := rand.Reader | |||
hashed := sha256.Sum256([]byte(cipherText)) | |||
signature, err := rsa.SignPKCS1v15(rng, prvKey, crypto.SHA256, hashed[:]) | |||
if err != nil { | |||
logx.Errorf("Error from signing: %s\n", err) | |||
return "", err | |||
} | |||
return fmt.Sprintf("%x", signature), nil | |||
} | |||
//RangeRand 生成区间[-m, n]的安全随机数 | |||
func RangeRand(min, max int64) string { | |||
if min > max { | |||
panic("the min is greater than max!") | |||
} | |||
if min < 0 { | |||
f64Min := math.Abs(float64(min)) | |||
i64Min := int64(f64Min) | |||
result, _ := rand.Int(rand.Reader, big.NewInt(max+1+i64Min)) | |||
return fmt.Sprintf("%d", result.Int64()-i64Min) | |||
} else { | |||
result, _ := rand.Int(rand.Reader, big.NewInt(max-min+1)) | |||
return fmt.Sprintf("%d", min+result.Int64()) | |||
} | |||
} | |||
// Krand 随机字符串 | |||
func Krand(size int, kind int) []byte { | |||
ikind, kinds, result := kind, [][]int{{10, 48}, {26, 97}, {26, 65}}, make([]byte, size) | |||
is_all := kind > 2 || kind < 0 | |||
r.Seed(time.Now().UnixNano()) | |||
for i := 0; i < size; i++ { | |||
if is_all { // random ikind | |||
ikind = r.Intn(3) | |||
} | |||
scope, base := kinds[ikind][0], kinds[ikind][1] | |||
result[i] = uint8(base + r.Intn(scope)) | |||
} | |||
return result | |||
} | |||
//AESEncrypt AES加密 | |||
func AESEncrypt(origData, key, iv []byte) (string, error) { | |||
block, err := aes.NewCipher(key) | |||
if err != nil { | |||
return "", err | |||
} | |||
blockSize := block.BlockSize() | |||
origData = PKCS5Padding(origData, blockSize) | |||
blockMode := cipher.NewCFBEncrypter(block, iv) | |||
crypted := make([]byte, len(origData)) | |||
blockMode.XORKeyStream(crypted, origData) | |||
return base64.StdEncoding.EncodeToString(crypted), nil | |||
} | |||
func PKCS5Padding(ciphertext []byte, blockSize int) []byte { | |||
padding := blockSize - len(ciphertext)%blockSize | |||
padtext := bytes.Repeat([]byte{byte(padding)}, padding) | |||
return append(ciphertext, padtext...) | |||
} | |||
/** | |||
* 计算sha256值 | |||
* | |||
* @param paramMap | |||
* @return 签名后的所有数据,原始数据+签名 | |||
*/ | |||
func Sha256(requestMap map[string]string) string { | |||
str := "" | |||
for k, v := range requestMap { | |||
str += fmt.Sprintf("%s=%s&", k, v) | |||
} | |||
logx.Infof("requestMap %s", str) | |||
sum := sha256.Sum256([]byte(str)) | |||
return fmt.Sprintf("%x", sum) | |||
} |
@@ -0,0 +1,77 @@ | |||
package utils | |||
import ( | |||
"encoding/json" | |||
"fmt" | |||
"github.com/tal-tech/go-zero/core/logx" | |||
"io/ioutil" | |||
"net/http" | |||
"net/url" | |||
"strings" | |||
) | |||
type Callback func(result []byte) interface{} | |||
func HttpDoCallBack(reqUrl, method string, params map[string]string, header map[string]string, callback Callback) (data interface{}, err error) { | |||
body, err := HttpDo(reqUrl, method, params, header) | |||
if err != nil { | |||
logx.Errorf("method %s, reqUrl %s error %s", method, reqUrl, err) | |||
return nil, err | |||
} | |||
if len(body) > 0 { | |||
data = callback(body) | |||
return data, err | |||
} | |||
return nil, err | |||
} | |||
func HttpDo(reqUrl, method string, params map[string]string, header map[string]string) (data []byte, err error) { | |||
var paramStr []byte | |||
paramStr, _ = json.Marshal(params) | |||
client := &http.Client{} | |||
req, err := http.NewRequest(strings.ToUpper(method), reqUrl, strings.NewReader(string(paramStr))) | |||
if err != nil { | |||
logx.Errorf("method %s, reqUrl %s error %s", method, reqUrl, err) | |||
return nil, err | |||
} | |||
for k, v := range header { | |||
req.Header.Set(k, v) | |||
} | |||
resp, err := client.Do(req) | |||
if err != nil { | |||
logx.Errorf("method %s, reqUrl %s error %s", method, reqUrl, err) | |||
} | |||
defer resp.Body.Close() | |||
body, err := ioutil.ReadAll(resp.Body) | |||
if err != nil { | |||
logx.Errorf("method %s, reqUrl %s error %s", method, reqUrl, err) | |||
return nil, err | |||
} | |||
return body, nil | |||
} | |||
func GetParameterString(params map[string][]string) string { | |||
var paramStr = "" | |||
for k, v := range params { | |||
s, _ := url.QueryUnescape(strings.Join(v, ",")) | |||
if len(paramStr) == 0 { | |||
paramStr = fmt.Sprintf("%s=%s", k, s) | |||
} else { | |||
paramStr = fmt.Sprintf("%s&%s=%s", paramStr, k, s) | |||
} | |||
} | |||
return paramStr | |||
} | |||
func GetSign(data, url string) string { | |||
reqMap := make(map[string]string) | |||
reqMap["obj"] = data | |||
headerMap := make(map[string]string) | |||
headerMap["Content-Type"] = "application/json" | |||
b, err := HttpDo(url, "POST", reqMap, headerMap) | |||
if err != nil { | |||
logx.Error(err) | |||
} | |||
return string(b) | |||
} |
@@ -0,0 +1,149 @@ | |||
package utils | |||
import ( | |||
"crypto/hmac" | |||
"crypto/sha1" | |||
"fmt" | |||
"github.com/google/uuid" | |||
"github.com/tal-tech/go-zero/core/logx" | |||
"io/ioutil" | |||
"job_risk_third/model" | |||
"mime" | |||
"net/http" | |||
"net/url" | |||
"sort" | |||
"strconv" | |||
"strings" | |||
"time" | |||
) | |||
var ( | |||
ErrorBadRequest = fmt.Errorf("无效的请求参数") | |||
) | |||
func Validation(r *http.Request) error { | |||
if err := ParseHttpParams(r); err != nil { | |||
return err | |||
} | |||
//vars := mux.Vars(r) | |||
timestamp, err := strconv.ParseInt(Param(r, "timestamp"), 10, 64) | |||
if err != nil { | |||
return ErrorBadRequest | |||
} | |||
now := time.Now().UnixNano() / 1e6 | |||
if timestamp > now+100000 || now >= timestamp+6000000 { | |||
return fmt.Errorf("请求过期") | |||
} | |||
sign := Param(r, "sign") | |||
if len(sign) == 0 { | |||
return ErrorBadRequest | |||
} | |||
nonce := Param(r, "nonce") | |||
if len(nonce) == 0 { | |||
return ErrorBadRequest | |||
} | |||
Params := r.Form | |||
var keys []string | |||
for k := range Params { | |||
keys = append(keys, k) | |||
} | |||
sort.Strings(keys) | |||
str := "" | |||
for _, v := range keys { | |||
if v != "sign" && v != "nonce" && v != "__json_param__" { | |||
udata := url.Values{} | |||
udata.Set(v, Params.Get(v)) | |||
strUrl := udata.Encode() | |||
str += "&" + strUrl | |||
} | |||
if v == "__json_param__" { | |||
udata := url.Values{} | |||
udata.Set(Params.Get(v), "") | |||
str += "&" + udata.Encode() | |||
} | |||
} | |||
if len(str) > 1 && str[len(str)-1:] == "=" { | |||
str = r.Method + str[1:len(str)-1] | |||
} | |||
logx.Infof("str : %s", str) | |||
our := Sha1(str, nonce) | |||
if sign != strings.Trim(our, " ") { | |||
logx.Infof("our:[%s] sign: [%s] ", our, sign) | |||
return fmt.Errorf("错误的签名") | |||
} | |||
logx.Info(r.RemoteAddr[:9]) | |||
if r.RemoteAddr[:9] != "127.0.0.1" && r.RemoteAddr[:9] != "localhost" { | |||
//判断是否重放请求 | |||
hExists := model.Redis.Exists(nonce).Val() | |||
if hExists > 0 { | |||
return fmt.Errorf("请勿重复请求") | |||
} | |||
//防止业务数据重复提交 | |||
hExists = model.Redis.Exists(sign).Val() | |||
if hExists > 0 { | |||
return fmt.Errorf("请勿重复提交数据") | |||
} | |||
model.Redis.Set(nonce, timestamp, time.Minute*5) | |||
model.Redis.Set(sign, timestamp, time.Minute*5) | |||
} | |||
return nil | |||
} | |||
func ParseHttpParams(r *http.Request) (err error) { | |||
ct := r.Header.Get("Content-Type") | |||
if ct == "" { | |||
ct = "application/octet-stream" | |||
} | |||
ct, _, err = mime.ParseMediaType(ct) | |||
switch { | |||
case ct == "application/json": | |||
result, err := ioutil.ReadAll(r.Body) | |||
if err != nil { | |||
logx.Errorf("ParseHttpParams error info : %v", err) | |||
return err | |||
} | |||
if r.Form == nil { | |||
r.Form = url.Values{} | |||
} | |||
r.Form.Set("__json_param__", string(result)) | |||
return nil | |||
} | |||
return err | |||
} | |||
//sha1加签 | |||
func Sha1(query string, priKey string) string { | |||
key := []byte(priKey) | |||
mac := hmac.New(sha1.New, key) | |||
mac.Write([]byte(query)) | |||
//query = base64.StdEncoding.EncodeToString(mac.Sum(nil)) | |||
//query = url.QueryEscape(query) | |||
query = fmt.Sprintf("%x", mac.Sum(nil)) | |||
return query | |||
} | |||
func Param(r *http.Request, key string) string { | |||
var value string | |||
value = r.FormValue(key) | |||
if len(value) > 0 { | |||
return value | |||
} | |||
value = r.URL.Query().Get(key) | |||
if len(value) > 0 { | |||
return value | |||
} | |||
value = r.Header.Get(key) | |||
if len(value) > 0 { | |||
return value | |||
} | |||
if cookie, _ := r.Cookie(key); cookie != nil { | |||
return cookie.Value | |||
} | |||
return value | |||
} | |||
func NewId() string { | |||
id := uuid.New().String() | |||
id = strings.Replace(id, "-", "", -1) | |||
return id | |||
} |
@@ -0,0 +1,18 @@ | |||
#!/bin/bash | |||
echo "Input process name first" | |||
port=8016 | |||
#一、根据端口号查询对应的pid,两种都行 | |||
pid=$(netstat -nlp | grep :$port | awk '{print $7}' | awk -F"/" '{ print $1 }'); | |||
#pid=$(ps -ef | grep 你的进程或端口 | grep -v grep | awk '{print $2}') | |||
#二、杀掉对应的进程,如果pid不存在,则不执行 | |||
if [ -n "$pid" ]; then | |||
kill -9 $pid; | |||
fi | |||
if [ $? -eq 0 ];then | |||
echo "kill $pid success" | |||
else | |||
echo "kill $pid fail" | |||
fi |
@@ -0,0 +1,55 @@ | |||
POST http://localhost:8888/api/v1/push/feature_info | |||
Content-Type: application/json | |||
timestamp:1603417115338 | |||
nonce:jahvuwygw91 | |||
sign:cb9ba0a24ffca47e91059877005faae9e4d35d49 | |||
{ | |||
"featureId": "aaaaa", | |||
"featureName": "bbbbbb", | |||
"featureLevel": "C", | |||
"featureDeptId": "dddddd", | |||
"featureTime": "2020-10-22 15:00:00", | |||
"objectList": [{ | |||
"objId": "eeeee", | |||
"objName": "ffffff", | |||
"objRegorg": "gggggg", | |||
"objDeptid": "hhhhhh", | |||
"objPosition": "iiiiii", | |||
"isDeal": "1", | |||
"dealId": "jjjjjj", | |||
"dealName": "kkkkkk", | |||
"dealTime": "2020-10-22 15:00:00", | |||
"dealStatus": "1", | |||
"dealResult": "已处置,属于正常工作情况" | |||
}] | |||
} | |||
### | |||
POST http://localhost:8888/api/v1/push/feature_deal | |||
Content-Type: application/json | |||
timestamp:1603417115338 | |||
nonce:jahvuwygw91 | |||
sign:e611e34594c395de0a92686feee1ec9ecde71552 | |||
{ | |||
"featureId": "111111", | |||
"userId": "222222", | |||
"objectId": "333333", | |||
"dealId": "444444", | |||
"dealName": "李四", | |||
"dealTime": "2020-10-24 15:00:00", | |||
"dealStatus": "1", | |||
"dealResult": "已处置,属于正常工作情况" | |||
} | |||
### | |||
POST http://localhost:8888/api/v1/push/user_info | |||
Content-Type: application/json | |||
timestamp:1603331042040 | |||
nonce:jahvuwygw91 | |||
sign:d997907f2b3d593178802de7deef44b3d8bb2d0f | |||
{"userId": "1","userName": "zhiwux","name": "职务","position": "测试","job": "","deptId": "3300000000","deptName": "浙江浙大网新中研软件有限公司","logTime": "2020-09-10 16:20:20","logError": "3","regorg": "3300000000"} | |||
### |
@@ -0,0 +1,12 @@ | |||
中研公钥: | |||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAszV1Idb7/Fcmpc+i2BVpBrJkWe9IT9g250uuOaYinjnWLkA9oORx/YLbcNbi99HcnD89quZN4Wqy9q2qDJNyJubbOdqSFVSjr9+TnRXiCVspoHjM6imWz+poXUZ4HSAbs/1YWioOt76kTxCx82McyNwQLVKKYSobjV/x77QlD6KUrDJEfQoTWWyy4YKUc/mjPrzTYbrClgfAsuPNClCuDrPkwx+8nFlqGJrXdQJGJRyxNjkvTCfNctEZYSUJemJyUQBbXH2hLpyrQG9pF5URrToXSAksiTdCdPxLM60NS3knxV4cm2gip0x5MyOGqqX9MLPCFqjlNO3WyaPUNmwUgQIDAQAB | |||
中研私钥: | |||
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCzNXUh1vv8Vyalz6LYFWkGsmRZ70hP2DbnS645piKeOdYuQD2g5HH9gttw1uL30dycPz2q5k3harL2raoMk3Im5ts52pIVVKOv35OdFeIJWymgeMzqKZbP6mhdRngdIBuz/VhaKg63vqRPELHzYxzI3BAtUophKhuNX/HvtCUPopSsMkR9ChNZbLLhgpRz+aM+vNNhusKWB8Cy480KUK4Os+TDH7ycWWoYmtd1AkYlHLE2OS9MJ81y0RlhJQl6YnJRAFtcfaEunKtAb2kXlRGtOhdICSyJN0J0/EszrQ1LeSfFXhybaCKnTHkzI4aqpf0ws8IWqOU07dbJo9Q2bBSBAgMBAAECggEAIeTLaYIKmJg3FAcoSmwKOB0HQ8cwywEeqTI0Gm0kgP55VrgJr+Nk98iHDllmBe7oJZkEZc03D5opjOQdlFFStq7U6aVAGc6vQrUravtXi+N1BQez4dnJzzsLUBDi6MdI1grlafAoZnIlC1sh/OFS8V5FpPzGdUgMe/mYfXh5xfHt0SPAjQsvYTKztOg1VddVYp1C2fJjwv+gxQgv1hCyGAMGq9k9yMQ6yGeN9C2m2a2AgbmNPmH45pdgQE/AvV4URJRtj9sMhFkt6Mtzi0o7684Gbl0xE2bDST9o+h8F/qewVB7CVKFObaVGFRH8h18/6JADOG+RwfcTE4IcDZm7QQKBgQDdnZ8+GGiTyR7Kbrhz0MddDB30nqx0tDHlcgDssFQ2moFRJVW9p/VzRpQB9DO7dmQhLWYi4eu2+bR3NTWVd3bS7I21sYJtgKJfhA9dKAxQmS4smhti1MVysZsOperIZbhAbLGQxsfqnKK7G8BnTdFxcJ8n6eJO3QTuj+VXsVsTeQKBgQDPA3i9Tfq7uCnzxksagJvPEcnxl/e8aWBNNK5Q4x1IH0SXz8W1I5ARkwGExjClLJN3FJM1jt6ar2ItUhUP5sX/3zKjmMCUXvwBN/VNaZ8eGc9bFpvI0z4E4j4PGueg/36LXBR8ZPW+agwJwjX2LBJq/20l8s5EMYS3WO1RIf7/SQKBgQDJwmOks7IZwcOfhpe1EQE/6/UlrIPTJ+45NsYytgGlSJqs1rGtncjvbvT2pm2moI1eSyeuYEIp7kHnOXEUJ5PtSWFmZjoZGUA6d09Jf1le02ZfQtnl61HrLli9SD5svXa2aH5sER0Wsg3RDN3o7sbcYSz0uJDJPZzs1+JzKMuC+QKBgQCAynMiq1IT2ebX0AVHrr3A3RtbYCVzpceRIPZWQoYkKbfeDxi8sixekqv+M+Ntz8bK7hUL3B/n8rdM5OVPqE6E+xKhL1aYuGNmSq8lg1HIQ1x7Ghy/m5TZKvxbH2z+ABZ1k0r3fURaO9XTeG1kA1VOFi2Mz3u+d2RPQVccA9+GaQKBgQDFjxlIgXrU3HXmy6lyuMHzbNChSvrR2pgOBCrAs/GmY4VG/jC8TVSvdjMhBakuLL5pyCDWWzcb4b7FAIfds+OR6CfQ6M7DBCVIhF1kT4K1UGF/Od0mtIwn3/pzLieIu+Pme+2EIvK/yA2LSE9iqJTTfQdM4ttbX0N8KkwyCkhBcQ== | |||
宁达公钥: | |||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwTkJpYvb+n96f/heVUmdLX1dt+l8V9/NOkbFxG4nSdZmcAaAmrlE1/+Kw2i3i+LaqQTw8a80TTVCTl3w83mwxzwExtQkB1KkxdPNTxOINVKuurE4fD6tzi3ooRC/7QLBb1Q+NSsDOdheSkLlC67URmKtW2IMwX/uCwQ0mpPBI0IcAVF42xMDx4PK9PkwZQe16d8x9Aa+rVpn8AoFGSqT0OoSm5Z20QrUs6tRyWV+B0JGEzc1Mg1oCu6880nCCMlAfzHXC9QXRWnFjJthF99NQNZNww7pKYlCDhYe5G/nl1aWo/o3e5zVu1uo2vF/bT+/hXaVNcSXkM56Z057fCJMNQIDAQAB | |||
宁达私钥: | |||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDBOQmli9v6f3p/+F5VSZ0tfV236XxX3806RsXEbidJ1mZwBoCauUTX/4rDaLeL4tqpBPDxrzRNNUJOXfDzebDHPATG1CQHUqTF081PE4g1Uq66sTh8Pq3OLeihEL/tAsFvVD41KwM52F5KQuULrtRGYq1bYgzBf+4LBDSak8EjQhwBUXjbEwPHg8r0+TBlB7Xp3zH0Br6tWmfwCgUZKpPQ6hKblnbRCtSzq1HJZX4HQkYTNzUyDWgK7rzzScIIyUB/MdcL1BdFacWMm2EX301A1k3DDukpiUIOFh7kb+eXVpaj+jd7nNW7W6ja8X9tP7+FdpU1xJeQznpnTnt8Ikw1AgMBAAECggEBAIc2R8bd8SkBLhMBFdou8luT4BJDxGylwzKltd04jCvCadq44iPjxAY2377Qt6ifLg6a05T82uewfl7ipCttG8S//kO4ziGFtqJtDb3pWCagXn9sZq+jGPMv8xtK4lOT2xLx67o/CDnhbFIhL7EWPZunj9Jj8bMyt7xjy//jp4Lol7ZGb8tedGOF8fxT+BMVWELKvDvATm563qEGnbB1Ca8JosNecZGH+D9ITvZq9dbZtePAKmzMKILoNMhJUwAYAXBedi+u4KnqBSK4uvIcUlnVmBRrASq6UnrYUvaXZ+CtVh2Dkvsd9qnP/aE7qwYoCnziv2pnKWVj1UfGIFdAan0CgYEA51qGpjnuzycHOVZnK3TVLzXGgggURgIJ8L/dGGV4oVUDmQpw1EroXEz17oQhfBGxzKNze2QShZKgzHe5cg7WL3JDYwPnziDTCmKsgaly0Fa/N5RD98+PqJTCj0kDYnBO3sKyS9RBQIkryr9DnOtQkbfgZVIi0gXejrq4QK9soEMCgYEA1c6bw/GvFtXfLdlqv0BQj7wLm7TLC0iqgQY/QI+qDag7PtrGB+UPglu1b8gToFRiWHA0ievz2uZ37ffNuCWbX+mApRua5aBt2mzHgRKaQirtKPuxoV4E74EMKsuOYOEuKctg6hH1ibWYxlxVubnPg4Qym0g2WHXKfS3SLNB9dicCgYABOn3UjCI0f2SObWMG3Av1wDdZoWlaJdCfsqUd6AwH70ehnGiU+ADb3JzBs3nqCr4C9Cs80H84rlqkO06EyIdioRyyfebRNWNpfrSjy56MdKl3RhZGTpfYsVGHKUAXWblRfX8s3+eozBGrdfCJ+MXowC003IbKzrUr1Nn9nfDZuQKBgFYy5A3NhJ+aPk5H14efsFsinzN5Ylr8QvGdySaIRTEYYDppDWnlaalOvAmDCpabLsMlCamJXVkljbh9LY1ObCPxChKG3J4zXdawAIcDLvn6QH9Dakv6kdbVmkgupQpd/rSO8FWuQ+XvNtbSJyWnygfl5llAddiYNLjfHls++zYFAoGAY3tMwRuTgHE0WR/N0TulvmbZCUz6y3lhQveQsi6hNqAMPz7cpvh9bwZgzZG2JHTUJOfC4lSlcy67YcF1qifgm8OjST0JiwhIlQ84XhW/TJe8obSTTddnX0hjPyL1Ocom8EYb7qY6ZWyohywMNIEG9EYQGehXlbDBVN/IBnX08mw= |