我们小组用的是钉钉办公,所以我们开发一些网站都是服务于小组内成员,也就是企业内部钉钉用户,在之前已经实现了将钉钉用户信息同步在数据库中,所以我们直接根据钉钉开发文档实现第三方登录。
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
2.登录之后网址上会获取authCode=2091bc1e2d8630ae84bf06844721c5d4,这个码只能用一次,具有即时性,也有过期时间
当你还没有写后端逻辑,没有验证获取token的时候,他默认跳转到你给定的登录页面
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
}