commit 829259f72fb7650751d9e8b14056f0c9c307933f Author: wyhwyhwyh <573805736@qq.com> Date: Wed Nov 17 11:17:31 2021 +0800 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..091eca0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.sum +*.yaml \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..9662f03 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // 使用 IntelliSense 了解相关属性。 + // 悬停以查看现有属性的描述。 + // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Package", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "E://dingd" + } + ] +} \ No newline at end of file diff --git a/dingtalk/dingtalk-service.go b/dingtalk/dingtalk-service.go new file mode 100644 index 0000000..9278ec8 --- /dev/null +++ b/dingtalk/dingtalk-service.go @@ -0,0 +1,27 @@ +package dingtalk + +import ( + "github.com/hugozhu/godingtalk" + "github.com/spf13/viper" +) + +var _client *godingtalk.DingTalkClient +var _appkey = viper.GetString("app.AppKey") +var _appsecret = viper.GetString("app.AppSecret") +var _agentid = viper.GetString("app.AgentId") + +//getDingtalkClient 获取钉钉client +func getDingtalkClient(appkey *string, appsecret *string, agentid *string) *godingtalk.DingTalkClient { + if _client != nil { + _client.RefreshAccessToken() + return _client + } + _client = godingtalk.NewDingTalkClient(*appkey, *appsecret) + _client.AgentID = *agentid + _client.RefreshAccessToken() + return _client +} + +func GET() *godingtalk.DingTalkClient { + return getDingtalkClient(&_appkey, &_appsecret, &_agentid) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..c4115e9 --- /dev/null +++ b/go.mod @@ -0,0 +1,26 @@ +module myschools.me/wyh/dingd.git + +go 1.17 + +require ( + github.com/hugozhu/godingtalk v1.0.6 + github.com/sirupsen/logrus v1.8.1 + github.com/spf13/viper v1.9.0 +) + +require ( + github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/magiconair/properties v1.8.5 // indirect + github.com/mitchellh/mapstructure v1.4.2 // indirect + github.com/pelletier/go-toml v1.9.4 // indirect + github.com/spf13/afero v1.6.0 // indirect + github.com/spf13/cast v1.4.1 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.2.0 // indirect + golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect + golang.org/x/text v0.3.6 // indirect + gopkg.in/ini.v1 v1.63.2 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect +) diff --git a/main.go b/main.go new file mode 100644 index 0000000..e3df814 --- /dev/null +++ b/main.go @@ -0,0 +1,176 @@ +package main + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/base64" + "encoding/json" + "errors" + "flag" + "fmt" + "io/ioutil" + "log" + "net/http" + "net/url" + "strconv" + "strings" + "time" + + "github.com/sirupsen/logrus" + "github.com/spf13/viper" + "myschools.me/wyh/dingd.git/model" +) + +const ( + AuthCode = "bdbc74ebecaf30259895b145d3c48d35" + Appkey = "dinguipztmzpv8sog933" + AppSecret = "kUYbKHxNixdMhTmW6IrdTE-yVnWfQLs1C7RQIAsrlwz8BYlVmceFs-3JRBmU32rQ" +) + +func main() { + cf := flag.String("config", "config.yaml", "file of config") + flag.Parse() + viper.SetConfigFile(*cf) + if err := viper.ReadInConfig(); err != nil { + logrus.WithFields(logrus.Fields{ + "func": "main", + }).Errorf("%s", err.Error()) + return + } + timestamp := strconv.FormatInt(time.Now().UnixNano()/1000000, 10) // 毫秒时间戳 + signature := EncodeSHA256(timestamp, AppSecret) // 加密签名 加密算法见我另一个函数 + url := fmt.Sprintf("https://oapi.dingtalk.com/sns/getuserinfo_bycode?accessKey=%s×tamp=%s&signature=%s", + Appkey, timestamp, signature) + p := struct { + Tmp_auth_code string `json:"tmp_auth_code"` + }{AuthCode} // post数据 + p1, _ := json.Marshal(p) + p2 := string(p1) + p3 := strings.NewReader(p2) //构建post数据 + + resp, err := http.Post(url, "application/json;charset=UTF-8", p3) + if err != nil { + log.Fatal(err) + } + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Fatal(err) + } + i := make(map[string]interface{}) + _ = json.Unmarshal(body, &i) + fmt.Println(i) + errcode := i["errcode"].(float64) + if errcode != 0 { + log.Fatal("errcode ==0") + } + unionid := i["user_info"].(map[string]interface{})["unionid"].(string) + accesstoken, err := GetAccesstoken() + if err != nil { + log.Fatal(err) + } + userid, err := GetUseridByUnionid(accesstoken, unionid) + if err != nil { + log.Fatal(err) + } + userinfo, err := GETUserInfo(accesstoken, userid) + if err != nil { + log.Fatal(err) + } + fmt.Println(userinfo) +} +func EncodeSHA256(message, secret string) string { + // 钉钉签名算法实现 + h := hmac.New(sha256.New, []byte(secret)) + h.Write([]byte(message)) + sum := h.Sum(nil) // 二进制流 + message1 := base64.StdEncoding.EncodeToString(sum) + + uv := url.Values{} + uv.Add("0", message1) + message2 := uv.Encode()[2:] + return message2 + +} + +func GetAccesstoken() (accesstoken string, err error) { + var resp *http.Response + //var AppKey, AppSecret string + //获取access_token + url := fmt.Sprintf("https://oapi.dingtalk.com/gettoken?appkey=%s&appsecret=%s", Appkey, AppSecret) + resp, err = http.Get(url) + if err != nil { + return "", err + } + //fmt.Println(resp) + //fmt.Println(err) + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + var i map[string]interface{} + _ = json.Unmarshal(body, &i) + //fmt.Println(1, string(body), i["errmsg"]) + if i["errcode"].(float64) == 0 { + return i["access_token"].(string), nil + } + return "", errors.New("accesstoken获取错误:" + i["errmsg"].(string)) + +} + +func GetUseridByUnionid(accesstoken, unionid string) (userid string, err error) { + //根据unionid获取userid + var resp *http.Response + url := fmt.Sprintf("https://oapi.dingtalk.com/topapi/user/getbyunionid?access_token=%s", accesstoken) + p := struct { + Unionid string `json:"unionid"` + }{unionid} // post数据 + p1, _ := json.Marshal(p) + p2 := string(p1) + p3 := strings.NewReader(p2) //构建post数据 + resp, err = http.Post(url, "application/json;charset=UTF-8", p3) + if err != nil { + return "", nil + } + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", nil + } + //fmt.Println(1, string(body), err) + var i map[string]interface{} + _ = json.Unmarshal(body, &i) + errcode := i["errcode"].(float64) + if errcode != 0 { + return "", fmt.Errorf("userid获取错误: %f, %s", errcode, i["errmsg"].(string)) + } + return i["result"].(map[string]interface{})["userid"].(string), nil +} + +func GETUserInfo(accesstoken, userid string) (*model.DingtalkUserInfoResponse, error) { + var resp *http.Response + url := fmt.Sprintf("https://oapi.dingtalk.com/topapi/v2/user/get?access_token=%s", accesstoken) + p := struct { + UserID string `json:"userid"` + Language string `json:"language"` + }{ + UserID: userid, + Language: "zh_CN", + } + p1, _ := json.Marshal(p) + p2 := string(p1) + p3 := strings.NewReader(p2) //构建post数据 + resp, err := http.Post(url, "application/json;charset=UTF-8", p3) + if err != nil { + return nil, err + } + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + userinfo := &model.DingtalkUserInfoResponse{} + _ = json.Unmarshal(body, userinfo) + errcode := userinfo.ErrCode + if errcode != 0 { + log.Fatal("errcode!=0") + } + return userinfo, nil +} diff --git a/model/dingtalk-model.go b/model/dingtalk-model.go new file mode 100644 index 0000000..9f10ebf --- /dev/null +++ b/model/dingtalk-model.go @@ -0,0 +1,69 @@ +package model + +type DingtalkUserInfoResponse struct { + RequestID string `json:"request_id"` + ErrCode int `json:"errcode"` + ErrMsg string `json:"errmsg"` + Result DingtalkUserGetResponse +} + +type DingtalkUserGetResponse struct { + UserID string `json:"userid"` + Unionid string `json:"unionid"` + Name string `json:"name"` + Avatar string `json:"avatar"` + StateCode string `json:"state_code"` + ManagerUserID string `json:"manager_userid"` + Mobile string `json:"mobile"` + HideMobile bool `json:"hide_mobile"` + Telephone string `json:"telephone"` + JobNumber string `json:"job_number"` + Title string `json:"title"` + Email string `json:"email"` + WorkPlace string `json:"work_place"` + Remark string `json:"remark"` + LoginID string `json:"login_id"` + ExclusiveAccountType string `json:"exclusive_account_type"` + ExclusiveAccount bool `json:"exclusive_account"` + DeptIDList []int `json:"dept_id_list"` + DeptOrderList []DingtalkDeptOrder + Extension string `json:"extension"` + HiredDate int `json:"hired_date"` + Active bool `json:"active"` + RealAuthed bool `json:"real_authed"` + OrgEmail string `json:"org_email"` + OrgEmailType string `json:"org_email_type"` + Senior bool `json:"senior"` + Admin bool `json:"admin"` + Boss bool `json:"boss"` + LeaderInDept []DingtalkDeptLeader + RoleList []DingtalkUserRole + UnionEmpExt UnionEmpExt +} + +type DingtalkDeptOrder struct { + DeptID int `json:"dept_id"` + Order int `json:"order"` +} + +type DingtalkDeptLeader struct { + DeptID int `json:"dept_id"` + Leader bool `json:"leader"` +} + +type DingtalkUserRole struct { + ID int + Name string + GroupName string +} + +type UnionEmpExt struct { + UserID string `json:"userid"` + UnionEmpMapList []DingtalkUnionEmpMapVo + CorpId string `json:"corp_id"` +} + +type DingtalkUnionEmpMapVo struct { + UserID string `json:"userid"` + CorpID string `json:"corpid"` +}