123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632 |
- // ERP 代码, light的逻辑, 废弃!!!!!
- // ERP 代码, light的逻辑, 废弃!!!!!
- package utils
- import (
- "bytes"
- "crypto/md5"
- "encoding/binary"
- "encoding/hex"
- "encoding/json"
- "errors"
- "fmt"
- "io/ioutil"
- "log"
- "net"
- "net/http"
- "strconv"
- "strings"
- "sync"
- "time"
- "git.i2edu.net/i2/go-zero/core/logx"
- "git.i2edu.net/i2/i2-bill-erp/internal/config"
- )
- type Token struct {
- Lock *sync.RWMutex
- Result int `json:"-"`
- UserId string `json:"user_id"`
- AccessToken string `json:"access_token"`
- RefreshToken string `json:"refresh_token"`
- LoginID string `json:"login_id"`
- TimeStamp uint64 `json:"time_stamp"`
- ServerIp string `json:"server_ip"`
- Domain string `json:"domain"`
- Password string `json:"-"`
- Map map[string]interface{} `json:"map"`
- }
- type TokenStore struct {
- storeServiceUrl string
- name string
- lock *sync.RWMutex
- tokens map[string]*Token
- }
- type IAuth interface {
- Init()
- }
- var globalTokenStore *TokenStore = nil
- func Init(c *config.Config) {
- globalTokenStore = &TokenStore{name: "sso", lock: new(sync.RWMutex), tokens: make(map[string]*Token)}
- if strings.HasPrefix(c.Erp.AuthServer, "http") {
- globalTokenStore.storeServiceUrl = c.Erp.AuthServer
- } else {
- iauthMap = make(map[string]IAuth)
- go globalTokenStore.startTokenCheckProcess()
- lightAuth := &LightAuth{}
- RegisterAuth("qianqiusoft.com", lightAuth)
- erpClient := NewTcpClient(c)
- erpClient.Start()
- }
- }
- type LightAuth struct {
- }
- func (la *LightAuth) Init() {
- }
- var iauthMap map[string]IAuth
- /**
- * @brief: 注册自定登录对象, 会调用Init进行初始化
- * @param1 t: key
- * @param2 a: 认证对象
- * @return none
- */
- func RegisterAuth(t string, a IAuth) {
- if t == "" || a == nil {
- return
- }
- var ok bool
- if _, ok = iauthMap[t]; ok {
- return
- } else {
- a.Init()
- iauthMap[t] = a
- }
- }
- func GetGlobalTokenStore() *TokenStore {
- return globalTokenStore
- }
- func (t *TokenStore) Get(key string) string {
- if t.storeServiceUrl == "" {
- t.lock.RLock()
- defer t.lock.RUnlock()
- if val, ok := t.tokens[key]; ok {
- //log.Println(key, "获取Token:", val.AccessToken, val.RefreshToken, val.LoginID)
- return val.UserId
- }
- } else {
- resp, err := http.Get(t.storeServiceUrl + key)
- if err != nil {
- return ""
- }
- b, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return ""
- }
- token := &Token{}
- err = json.Unmarshal(b, &token)
- if err != nil {
- return ""
- }
- return token.UserId
- }
- return ""
- }
- func (t *TokenStore) Set(key string, v *Token) {
- t.lock.Lock()
- defer t.lock.Unlock()
- if val, ok := t.tokens[key]; !ok {
- t.tokens[key] = v
- } else if val != v {
- t.tokens[key] = v
- }
- }
- func (t *TokenStore) Remove(key string) {
- t.lock.Lock()
- defer t.lock.Unlock()
- delete(t.tokens, key)
- log.Println(key, "删除Key")
- }
- func (t *TokenStore) Refresh(key string) {
- t.lock.Lock()
- defer t.lock.Unlock()
- val, ok := t.tokens[key]
- if ok {
- val.TimeStamp = uint64(time.Now().UnixNano())
- }
- }
- func (t *TokenStore) startTokenCheckProcess() {
- }
- const (
- __KEY = "Light#dauth-@*I2"
- CMD_NEW = "new"
- CMD_REMOVE = "remove"
- CMD_PINGPONG = "pg"
- CMD_PINGPONG_RESP = "pg_resp"
- )
- var TCPClient *TcpClient
- type authPackage struct {
- Cmd string
- TokenStr string
- Content []byte
- }
- func (ap *authPackage) toBytes() []byte {
- buf := bytes.NewBuffer([]byte{})
- b := []byte(ap.Cmd)
- buf.Write(uint32ToBytes(len(b)))
- buf.Write(b)
- buf.Write(uint32ToBytes(len(ap.Content)))
- buf.Write(ap.Content)
- return buf.Bytes()
- }
- type TcpClient struct {
- conn net.Conn // 连接
- c *config.Config
- pchan chan *authPackage // 包chan
- done chan bool // 是否done
- exited bool // 退出
- verified bool // 验证是否
- }
- // 创建client
- func NewTcpClient(cfg *config.Config) *TcpClient {
- c := &TcpClient{
- c: cfg,
- pchan: make(chan *authPackage, 100),
- done: make(chan bool),
- exited: false,
- verified: false,
- }
- return c
- }
- // 启动
- func (c *TcpClient) Start() {
- go func() {
- defer func() {
- if p := recover(); p != nil {
- fmt.Println("ecover", p)
- }
- if c.conn != nil {
- c.conn.Close()
- }
- c.restart()
- }()
- var err error = nil
- address := c.c.Erp.AuthServer
- // fmt.Println("auth client start, dial address is", address)
- c.conn, err = net.Dial("tcp", address)
- if err != nil {
- fmt.Println("Error dialing erp client", err.Error())
- return
- }
- fmt.Println("发送验证")
- sendVerify(c.conn) // 发送验证,不需要读取返回值,如果验证错误立刻关掉
- fmt.Println("读取验证结果")
- vresp, err := readString(c.conn)
- if err != nil {
- fmt.Println("Error dialing", err.Error())
- return
- }
- if vresp != "ok" {
- // 验证失败
- fmt.Println("verify is not ok", vresp)
- return
- }
- fmt.Println("验证成功")
- c.verified = true
- // send
- go func() {
- for {
- select {
- case data := <-c.pchan:
- logx.Info("写入数据")
- c.conn.SetWriteDeadline(time.Now().Add(time.Second * 2))
- _, err := c.conn.Write(data.toBytes())
- if err != nil {
- fmt.Println("写入内容错误", err.Error())
- return
- }
- case <-c.done:
- logx.Info("发送数据done退出")
- return
- }
- }
- }()
- // receive
- for {
- cmd, err := readString(c.conn) // 读取命令
- if err != nil {
- c.done <- true
- fmt.Println("读取命令错误", err.Error())
- break
- }
- if cmd == CMD_NEW {
- err = c.newHandler()
- } else if cmd == CMD_REMOVE {
- err = c.removeHandler()
- } else if cmd == CMD_PINGPONG_RESP {
- } else {
- fmt.Println("未知cmd", cmd)
- continue
- }
- if err != nil {
- c.done <- true
- fmt.Println("处理错误", err.Error())
- break
- }
- }
- }()
- }
- // 停止
- func (c *TcpClient) Stop() {
- c.exited = true
- c.conn.Close()
- }
- // 检测
- func (c *TcpClient) restart() {
- if c.exited {
- // 已退出则不重启
- return
- }
- go func() {
- c.verified = false
- c.done = make(chan bool)
- c.pchan = make(chan *authPackage, 100)
- c.exited = false
- time.Sleep(3 * time.Second)
- c.Start()
- }()
- }
- // 发送bytes
- func (c *TcpClient) Send(cmd string, bytess []byte) {
- if !c.verified {
- fmt.Println("未认证")
- return
- }
- logx.Info("发送指令1", cmd)
- c.pchan <- &authPackage{
- Cmd: cmd,
- Content: bytess,
- }
- logx.Info("发送指令2", cmd)
- }
- // 发送token
- func (c *TcpClient) SendToken(token *Token) {
- // logx.Info("发送新建token")
- bytess := tokenToBytes(token)
- c.Send(CMD_NEW, bytess)
- }
- // 处理创建
- func (c *TcpClient) newHandler() error {
- // fmt.Println("处理新建")
- bytess, err := readBytes(c.conn)
- if err != nil {
- fmt.Println("读取token内容错误", err.Error())
- return err
- }
- // 新建
- token, err := bytesToToken(bytess)
- if err != nil {
- logx.Info("bytesToToken 错误", err.Error())
- return err
- }
- GetGlobalTokenStore().Set(token.AccessToken, token)
- return nil
- }
- // 处理删除
- func (c *TcpClient) removeHandler() error {
- fmt.Println("处理删除")
- bytess, err := readBytes(c.conn)
- if err != nil {
- fmt.Println("读取token内容错误", err.Error())
- return err
- }
- // 移除,此时bytess为tokenstring
- GetGlobalTokenStore().Remove(string(bytess))
- return nil
- }
- // 读取字符串
- func readString(conn net.Conn) (string, error) {
- // 读长度
- size, err := readUInt32(conn)
- if err != nil {
- fmt.Println("读取长度失败,", err.Error())
- return "", err
- }
- // 读字符串
- b := make([]byte, size)
- n, err := conn.Read(b)
- if n != int(size) {
- return "", errors.New("读取长度不是" + strconv.Itoa(int(size)))
- }
- return string(b), nil
- }
- // 写入字符串
- func writeString(conn net.Conn, str string) error {
- if str == "" {
- return errors.New("字符串为空")
- }
- bytess := []byte(str)
- size := len(bytess)
- // 发送长度
- err := writeUInt32(conn, uint32(size))
- if err != nil {
- fmt.Println("发送长度失败,", err.Error())
- return err
- }
- // 发送内容
- n, err := conn.Write(bytess)
- if err != nil {
- fmt.Println("发送内容失败,", err.Error())
- return err
- }
- if n != size {
- return errors.New("发送长度不是" + strconv.Itoa(int(size)))
- }
- return nil
- }
- // 读取bytes
- func readBytes(conn net.Conn) ([]byte, error) {
- // 读长度
- size, err := readUInt32(conn)
- if err != nil {
- fmt.Println("读取长度失败,", err.Error())
- return nil, err
- }
- // 读字符串
- b := make([]byte, size)
- n, err := conn.Read(b)
- if n != int(size) {
- return nil, errors.New("读取长度不是" + strconv.Itoa(int(size)))
- }
- return b, nil
- }
- // 读取uint64
- func readUInt32(conn net.Conn) (uint32, error) {
- b := make([]byte, 4)
- n, err := conn.Read(b)
- if err != nil {
- fmt.Println("读取长度失败,", err.Error())
- return 0, err
- }
- if n != 4 {
- return 0, errors.New("读取长度不是4")
- }
- size := binary.BigEndian.Uint32(b)
- return size, nil
- }
- // 写入长度
- func writeUInt32(conn net.Conn, v uint32) error {
- // 发送长度
- b := make([]byte, 4)
- binary.BigEndian.PutUint32(b, v)
- n, err := conn.Write(b)
- if err != nil {
- fmt.Println("发送长度失败,", err.Error())
- return err
- }
- if n != 4 {
- return errors.New("发送长度不是4")
- }
- return nil
- }
- // 写入长度
- func writeUInt64(conn net.Conn, v uint64) error {
- // 发送长度
- b := make([]byte, 8)
- binary.BigEndian.PutUint64(b, v)
- n, err := conn.Write(b)
- if err != nil {
- fmt.Println("发送长度失败,", err.Error())
- return err
- }
- if n != 4 {
- return errors.New("发送长度不是4")
- }
- return nil
- }
- // 读取uint64
- func readStringByBytes(bytess []byte) (string, int, error) {
- size := binary.BigEndian.Uint32(bytess)
- return string(bytess[4 : 4+size]), int(size), nil
- }
- // int转bytes
- func uint32ToBytes(v int) []byte {
- b := make([]byte, 4)
- binary.BigEndian.PutUint32(b, uint32(v))
- return b
- }
- // int转bytes
- func uint64ToBytes(v int) []byte {
- b := make([]byte, 8)
- binary.BigEndian.PutUint32(b, uint32(v))
- return b
- }
- // 转token
- func bytesToToken(content []byte) (*Token, error) {
- token := &Token{Lock: new(sync.RWMutex)}
- var index int = 0
- var size int
- var err error = nil
- // fmt.Println("读取userid")
- token.UserId, size, err = readStringByBytes(content)
- if err != nil {
- fmt.Println("读取userid错误")
- return nil, err
- }
- index += 4 + size
- // fmt.Println("读取AccessToken")
- token.AccessToken, size, err = readStringByBytes(content[index:])
- if err != nil {
- fmt.Println("读取AccessToken错误")
- return nil, err
- }
- index += 4 + size
- // fmt.Println("读取RefreshToken")
- token.RefreshToken, size, err = readStringByBytes(content[index:])
- if err != nil {
- fmt.Println("读取RefreshToken错误")
- return nil, err
- }
- index += 4 + size
- // fmt.Println("读取LoginID")
- token.LoginID, size, err = readStringByBytes(content[index:])
- if err != nil {
- fmt.Println("读取LoginID错误")
- return nil, err
- }
- index += 4 + size
- // fmt.Println("读取timestamp")
- token.TimeStamp = binary.BigEndian.Uint64(content[index:])
- index += 8
- // fmt.Println("读取ServerIp")
- token.ServerIp, size, err = readStringByBytes(content[index:])
- if err != nil {
- fmt.Println("读取ServerIp错误")
- return nil, err
- }
- index += 4 + size
- // fmt.Println("读取Domain")
- token.Domain, size, err = readStringByBytes(content[index:])
- if err != nil {
- fmt.Println("读取Domain错误")
- return nil, err
- }
- index += 4 + size
- return token, nil
- }
- // 转bytes,包括token开头
- func tokenToBytes(token *Token) []byte {
- buf := bytes.NewBuffer([]byte{})
- t := []byte(token.UserId)
- buf.Write(uint32ToBytes(len(t)))
- buf.Write(t)
- t = []byte(token.AccessToken)
- buf.Write(uint32ToBytes(len(t)))
- buf.Write(t)
- t = []byte(token.RefreshToken)
- buf.Write(uint32ToBytes(len(t)))
- buf.Write(t)
- t = []byte(token.LoginID)
- buf.Write(uint32ToBytes(len(t)))
- buf.Write(t)
- buf.Write(uint64ToBytes(int(token.TimeStamp)))
- fmt.Println(token.ServerIp)
- t = []byte(token.ServerIp)
- buf.Write(uint32ToBytes(len(t)))
- buf.Write(t)
- fmt.Println(token.Domain)
- t = []byte(token.Domain)
- buf.Write(uint32ToBytes(len(t)))
- buf.Write(t)
- bytess := buf.Bytes()
- buf = bytes.NewBuffer([]byte{}) // 这里用reset是错误的
- tokenstrbytes := []byte(token.AccessToken)
- buf.Write(uint32ToBytes(len(tokenstrbytes)))
- buf.Write(tokenstrbytes)
- buf.Write(uint32ToBytes(len(bytess)))
- buf.Write(bytess)
- return buf.Bytes()
- }
- // 发送验证
- func sendVerify(conn net.Conn) {
- timestamp := time.Now().UnixNano()
- timestampStr := strconv.Itoa(int(timestamp))
- seed := timestampStr + __KEY
- hashVal := hash(seed)
- writeUInt64(conn, uint64(timestamp))
- writeString(conn, hashVal)
- }
- // md5 哈希
- func hash(str string) string {
- h := md5.New()
- h.Write([]byte(str))
- return hex.EncodeToString(h.Sum(nil))
- }
|