钉钉实现扫码登录

实现背景

我们小组用的是钉钉办公,所以我们开发一些网站都是服务于小组内成员,也就是企业内部钉钉用户,在之前已经实现了将钉钉用户信息同步在数据库中,所以我们直接根据钉钉开发文档实现第三方登录。

具体思路

1.数据库已经同步到企业内部所有成员的信息,等于说所有用户都已经注册过了
2.实现扫码登录,通过用户钉钉登录或钉钉扫码登录获取用户信息,然后根据获取的信息在数据库中验证身份,得到完整信息,并生成该用户登录的token,并将用户信息存入token请求头,实现完整登录过程。

参考文档和在线接口测试

第三方登录文档

获取用户token

企业内部api在线测试上面这个接口

获取通讯录个人信息

企业内部api在线测试上面这个接口

具体演示过程

1.根据钉钉官方给定的网址(网址中包含你最后要跳转到的你的项目地址)进入,让用户授权
我的网址:

https://login.dingtalk.com/oauth2/challenge.htm?redirect_uri=http://47.98.212.252/&response_type=code&client_id=dingjfxu75nqiffmdbb8&scope=openid&prompt=consent

钉钉实现扫码登录_第1张图片

2.登录之后网址上会获取authCode=2091bc1e2d8630ae84bf06844721c5d4,这个码只能用一次,具有即时性,也有过期时间
当你还没有写后端逻辑,没有验证获取token的时候,他默认跳转到你给定的登录页面
钉钉实现扫码登录_第2张图片

3.前端获取这个码传给后端,然后你根据你写的接口,返回给前端这个用户的所有信息和token
也就是直接进入展示页面,而不是登录页面

实现代码

type Code struct {
	AuthCode string `json:"authCode"`
}
func SweepLogin(code *models.Code) (list models.UserList, err error) {
	accessToken, err := GetAccessToken(code)
	var client *http.Client
	var request *http.Request
	var resp *http.Response
	var body []byte
	URL := "https://api.dingtalk.com/v1.0/contact/users/me"
	client = &http.Client{Transport: &http.Transport{ //对客户端进行一些配置
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: true,
		},
	}, Timeout: time.Duration(time.Second * 5)}
	request, err = http.NewRequest("GET", URL, nil)
	if err != nil {
		return
	}
	// Set the header parameter
	request.Header.Set("x-acs-dingtalk-access-token", accessToken)
	request.Header.Set("Content-Type", "application/json")
	// Send the request
	resp, err = client.Do(request)
	if err != nil {
		// Handle error
	}
	defer resp.Body.Close()
	// Read the response body
	body, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		// Handle error
	}
	r := struct {
		AvatarURL string `json:"avatarUrl"`
		Mobile    string `json:"mobile"`
		Nick      string `json:"nick"`
		OpenID    string `json:"openId"`
		StateCode string `json:"stateCode"`
		UnionID   string `json:"unionId"`
	}{}
	//把请求到的结构反序列化到专门接受返回值的对象上面
	err = json.Unmarshal(body, &r)
	if err != nil {
		return
	}
	u := db.Table("user_lists").Where("unionid = ?", r.UnionID).Find(&user)
	if u.RowsAffected == 0 {
		// 用户不存在
		return list, ErrorUserNotExit
	}
	db.Table("user_lists").Where("unionid = ?", r.UnionID).Find(&list)
	return list, err
}

func GetAccessToken(code *models.Code) (accessToken string, err error) {
	var client *http.Client
	var request *http.Request
	var resp *http.Response
	var body []byte
	URL := "https://api.dingtalk.com/v1.0/oauth2/userAccessToken"
	client = &http.Client{Transport: &http.Transport{ //对客户端进行一些配置
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: true,
		},
	}, Timeout: time.Duration(time.Second * 5)}
	//此处是post请求的请求题,我们先初始化一个对象
	b := struct {
		ClientID     string `json:"clientId"`
		ClientSecret string `json:"clientSecret"`
		Code         string `json:"code"`
		GrantType    string `json:"grantType"`
	}{
		ClientID:     "dingjfxu75nqiffmdbb8",
		ClientSecret: "X-ZVvfCTSl8qPWZEBI2VzJVQnkHoiikZ90gceJnZpIzhDGw5a3wFpXcy6Ce85c1x",
		Code:         code.AuthCode,
		GrantType:    "authorization_code",
	}
	//然后把结构体对象序列化一下
	bodymarshal, err := json.Marshal(&b)
	if err != nil {
		return
	}
	//再处理一下
	reqBody := strings.NewReader(string(bodymarshal))
	//然后就可以放入具体的request中的
	request, err = http.NewRequest(http.MethodPost, URL, reqBody)
	if err != nil {
		return
	}
	request.Header.Set("Content-Type", "application/json")
	resp, err = client.Do(request)
	if err != nil {
		return
	}
	defer resp.Body.Close()
	body, err = ioutil.ReadAll(resp.Body) //把请求到的body转化成byte[]
	if err != nil {
		return
	}
	r := struct {
		AccessToken  string `json:"accessToken"`
		Code         string `json:"code"`
		ExpireIn     int64  `json:"expireIn"`
		Message      string `json:"message"`
		RefreshToken string `json:"refreshToken"`
		Requestid    string `json:"requestid"`
	}{}
	//把请求到的结构反序列化到专门接受返回值的对象上面
	err = json.Unmarshal(body, &r)
	if err != nil {
		return
	}
	if r.Code != "" {
		return "", errors.New(r.Message)
	}
	return r.AccessToken, nil
}

你可能感兴趣的:(钉钉,数据库)