Browse Source

1、项目初始化

master
wangjian 3 years ago
commit
f981586224
24 changed files with 1655 additions and 0 deletions
  1. +71
    -0
      .drone.yml
  2. +38
    -0
      README.md
  3. +147
    -0
      cmd/main.go
  4. +52
    -0
      config/config.go
  5. +70
    -0
      config/job_risk_third.json
  6. +52
    -0
      discover/discover.go
  7. +15
    -0
      drone/tpl/index.md
  8. +20
    -0
      go.mod
  9. +77
    -0
      internal/endpoints/endpoints.go
  10. +75
    -0
      internal/proto/request.go
  11. +21
    -0
      internal/proto/response.go
  12. +86
    -0
      internal/services/instrument.go
  13. +151
    -0
      internal/services/services.go
  14. +21
    -0
      internal/transports/merror.go
  15. +106
    -0
      internal/transports/transports.go
  16. +119
    -0
      loggers/logs.go
  17. +70
    -0
      model/index.go
  18. +13
    -0
      model/tb_request_third_log.go
  19. +140
    -0
      pkg/utils/cryption.go
  20. +77
    -0
      pkg/utils/httpRequest.go
  21. +149
    -0
      pkg/utils/utils.go
  22. +18
    -0
      restart.sh
  23. +55
    -0
      test/test.http
  24. +12
    -0
      中研风险秘钥 - 副本 .txt

+ 71
- 0
.drone.yml View File

@@ -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

+ 38
- 0
README.md View File

@@ -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":{
}
}
```

+ 147
- 0
cmd/main.go View File

@@ -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)
}

+ 52
- 0
config/config.go View File

@@ -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
}

+ 70
- 0
config/job_risk_third.json View File

@@ -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"
}

+ 52
- 0
discover/discover.go View File

@@ -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, &reg, logger)
return
}

+ 15
- 0
drone/tpl/index.md View File

@@ -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])

+ 20
- 0
go.mod View File

@@ -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
)

+ 77
- 0
internal/endpoints/endpoints.go View File

@@ -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
}
}

+ 75
- 0
internal/proto/request.go View File

@@ -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{}

+ 21
- 0
internal/proto/response.go View File

@@ -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"`
}

+ 86
- 0
internal/services/instrument.go View File

@@ -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)
}

+ 151
- 0
internal/services/services.go View File

@@ -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
}

+ 21
- 0
internal/transports/merror.go View File

@@ -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)
}

+ 106
- 0
internal/transports/transports.go View File

@@ -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
}

+ 119
- 0
loggers/logs.go View File

@@ -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
}

+ 70
- 0
model/index.go View File

@@ -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
}

+ 13
- 0
model/tb_request_third_log.go View File

@@ -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:"请求返回的数据"`
}

+ 140
- 0
pkg/utils/cryption.go View File

@@ -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)
}

+ 77
- 0
pkg/utils/httpRequest.go View File

@@ -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)
}

+ 149
- 0
pkg/utils/utils.go View File

@@ -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
}

+ 18
- 0
restart.sh View File

@@ -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

+ 55
- 0
test/test.http View File

@@ -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"}

###

+ 12
- 0
中研风险秘钥 - 副本 .txt View File

@@ -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=

Loading…
Cancel
Save