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

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

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
    <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>456</p>
</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,例如<div id="login_container"></div>或<span id="login_container"></span>
        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&timestamp=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&timestamp=%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

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值