钉钉扫码登陆后台代码golang实现

首先获取appid 和 appsecret
钉钉文档有讲解

我使用的是将钉钉二维码嵌入到自己的页面


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>logintitle>
    <script src="https://g.alicdn.com/dingding/dinglogin/0.0.5/ddLogin.js">script>

head>
<body>
<p>123{{.title}}p>
<div id="login_container">div>
<p>456p>
body>
<script>
    /*
* 解释一下goto参数,参考以下例子:
* var url = encodeURIComponent('http://localhost.me/index.php?test=1&aa=2');
* var goto = encodeURIComponent('https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=appid&response_type=code&scope=snsapi_login&state=STATE&redirect_uri='+url)
*/
    var baseurl = "http://127.0.0.1:8080";
    var urlapi = "/api/work/LoginByQRcode"
    
    var goto = encodeURIComponent(
        'https://oapi.dingtalk.com/connect/oauth2/sns_authorize?' +
        'appid=' + "appid" +
        '&response_type=code&' +
        'scope=snsapi_login&' +
        'state=STATE&redirect_uri=' + baseurl + urlapi);

    var obj = DDLogin({
        id:"login_container",//这里需要你在自己的页面定义一个HTML标签并设置id,例如
goto: goto, //请参考注释里的方式 style: "border:none;background-color:#FFFFFF;", width : "365", height: "400" }); //扫完码就会执行下面这些代码 var handleMessage = function (event) { var origin = event.origin; console.log("origin", event.origin); if( origin == "https://login.dingtalk.com" ) { //判断是否来自ddLogin扫码事件。 var loginTmpCode = event.data; //拿到loginTmpCode后就可以在这里构造跳转链接进行跳转了 console.log("loginTmpCode", loginTmpCode); var url1 = "https://oapi.dingtalk.com/connect/oauth2/sns_authorize?" + "appid=" + "appid" + "&response_type=code" + "&scope=snsapi_login" + "&state=STATE" + "&redirect_uri=" + baseurl + urlapi + "&loginTmpCode=" + loginTmpCode; console.log("loginTmpCode", url1) window.location.href=url1; } }; //这时候页面会跳转到钉钉自己的服务器, //然后钉钉根据 redirecturl在跳转到你的页面 //并在url中包含了loginTmpcode, //这时候你获得了这个code把他传给后台来获取钉钉用户信息。。 if (typeof window.addEventListener != 'undefined') { console.log('message', handleMessage, false); window.addEventListener('message', handleMessage, false); } else if (typeof window.attachEvent != 'undefined') { console.log('onmessage', handleMessage); window.attachEvent('onmessage', handleMessage); }
script> html>

服务端通过临时授权码获取授权用户的个人信息
通过临时授权码Code获取用户信息,临时授权码只能使用一次。
这里面涉及到的几个钉钉后台接口
1
请求方式:POST(HTTPS)

请求地址:https://oapi.dingtalk.com/sns/getuserinfo_bycode?accessKey=xxx×tamp=xxx&signature=xxx
URL签名参数说明:

参数 说明
accessKey: 应用的appId,参见本篇文档获取appId及appSerect章节
timestamp: 当前时间戳,单位是毫秒
signature: 通过appSecret计算出来的签名值,签名计算方法这个方法我也用go实现了
请求包结构体:
{
    "tmp_auth_code": "23152698ea18304da4d0ce1xxxxx"
}

返回结果:

```javascript
{ 
    "errcode": 0,
    "errmsg": "ok",
    "user_info": {
        "nick": "张三",
        "openid": "liSii8KCxxxxx",
        "unionid": "7Huu46kk" // 这个是用来查user info的
    }
}

func LoginByQRcode(code string) (userid string, err error) {
	var resp *http.Response
	//fmt.Println("AppKey,AppSecret", AppKey, AppSecret)
	//服务端通过临时授权码获取授权用户的个人信息
	appKey := ""
	appSecret := ""
	timestamp := strconv.FormatInt(time.Now().UnixNano()/1000000, 10)  // 毫秒时间戳
	signature := EncodeSHA256(timestamp, appSecret)   // 加密签名  加密算法见我另一个函数
	url2 := fmt.Sprintf(
		"https://oapi.dingtalk.com/sns/getuserinfo_bycode?accessKey=%s×tamp=%s&signature=%s",
		appKey, timestamp, signature)
	//fmt.Println(3, url2, )
	p := struct {
		Tmp_auth_code string `json:"tmp_auth_code"`
	}{code} // post数据
	p1, _ := json.Marshal(p)
	p2 := string(p1)
	p3 := strings.NewReader(p2) //构建post数据
	resp, err = http.Post(url2, "application/json;charset=UTF-8", p3)
	//fmt.Println(1, resp, err)
	body, err := ioutil.ReadAll(resp.Body)
	//fmt.Println(2, string(body), err)
	var i map[string]interface{} 
	_ = json.Unmarshal(body, &i)  ///返回的数据给i
	errcode := i["errcode"].(float64)
	if  errcode != 0 {
		return "", errors.New(fmt.Sprintf("登录错误: %s, %s", errcode, i["errmsg"].(string)))
	}
	unionid := i["user_info"].(map[string]interface{})["unionid"].(string)  // unionid 可以用来查询userinfo
	accesstoken, err := GetAccesstoken()  // 获取accesstoken
	if err != nil {
		return "", errors.New(fmt.Sprintf("登录错误accesstoken获取失败: %s", err))
	}
	userid, err = GetUseridByUnionid(accesstoken,unionid)
	if err != nil {
		return "", errors.New(fmt.Sprintf("登录错误userid获取失败: %s", err))
	}
	return userid, nil
}
func GetUseridByUnionid (accesstoken, unionid string) (userid string, err error) {
	//根据unionid获取userid
	var resp *http.Response
	url := fmt.Sprintf("https://oapi.dingtalk.com/user/getUseridByUnionid?access_token=%s&unionid=%s",
		accesstoken, unionid)
	resp, err = http.Get(url)
	body, err := ioutil.ReadAll(resp.Body)
	//fmt.Println(1, string(body), err)
	var i map[string]interface{}
	_ = json.Unmarshal(body, &i)
	errcode := i["errcode"].(float64)
	if  errcode != 0 {
		return "", errors.New(fmt.Sprintf("userid获取错误: %s, %s", errcode, i["errmsg"].(string)))
	}
	return i["userid"].(string), nil
}

几乎钉钉每一个接口都需要accesstoken参数


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)
	//fmt.Println(resp)
	//fmt.Println(err)
	body, err := ioutil.ReadAll(resp.Body)
	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 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

}

你可能感兴趣的:(go,javascript)