一、前言

公司作为企业微信第三方应用服务商,想要获取到授权企业的通讯录信息中的用户信息和部门信息,以及授权企业的成员可以扫码进行登录。

二、流程梳理

1.后台配置


红色箭头标记的是最基本的需要的东西。
可信域名:设置可信域名后支持应用的OAuth2授权、JSSDK调用、通讯录名称转义等大部分操作都必须在这个域名下发起才能成功。
指令回调URL:系统将会把此应用的授权变更事件、ticket参数、通讯录变更信息等推送给此URL
TOKEN:主要是用来进行校验回调请求的合法性。
EncodingAESKey:回调消息加解密参数,是AES密钥的Base64编码,用于解密回调消息内容对应的密文。后续所有托管的企业产生的回调消息都使用该值来解密。
这里的TOKEN和EncodingAESKey主要是用来校验数据回调URL和指令回调URL是否能够被企业微信服务器调用成功。
校验URL
企业微信验证URL是否能够被调用是GET请求,各项信息的通知是相同URL下的POST请求。也就是需要用配置的URL
写一个GET用来校验,一个POST请求接受信息。
校验信息

router.GET("/wx/cmdback", func(c *gin.Context) {/*数据回调验证*///企业微信加密签名msgSignature := cast.ToString(c.Query("msg_signature"))//时间戳timestamp := cast.ToInt64(c.Query("timestamp"))//随机数nonce := cast.ToString(c.Query("nonce"))//加密字符串echostr, err := url.PathUnescape(c.Query("echostr"))if err != nil {fmt.Println("url解码失败")return}//企业微信api 详情可以看企业微信文档wxcpt := wxbizmsgcrypt.NewWXBizMsgCrypt(model.Token, model.EncodingAesKey, model.CorpId, wxbizmsgcrypt.XmlType)echoStr, cryptErr := wxcpt.VerifyURL(msgSignature, cast.ToString(timestamp), nonce, echostr)if nil != cryptErr {fmt.Println("verifyUrl fail", cryptErr)return}fmt.Println("verifyUrl success echoStr")c.String(util.Success, string(echoStr))//返回解密出来的字符串给企业微信校验})

接收信息

router.POST("/wx/cmdback", func(c *gin.Context) {/*指令回调URL: 微信服务器推送suite_ticket以及安装应用时推送auth_code时。*///企业微信加密签名msgSignature := cast.ToString(c.Query("msg_signature"))//时间戳timestamp := cast.ToString(c.Query("timestamp"))//随机数nonce := cast.ToString(c.Query("nonce"))// post请求的密文数据defer c.Request.Body.Close()con, _ := ioutil.ReadAll(c.Request.Body) //获取post的数据// 访问应用和企业回调传不同的IDwxcpt := wxbizmsgcrypt.NewWXBizMsgCrypt(model.Token, model.EncodingAesKey, model.SuitId, wxbizmsgcrypt.XmlType)msg, cryptErr := wxcpt.DecryptMsg(msgSignature, timestamp, nonce, con)if nil != cryptErr {fmt.Println("DecryptMsg fail", cryptErr)return}fmt.Println(string(msg))var content MsgContentxml.Unmarshal(msg, &content)var changeContent ChangeContentxml.Unmarshal(msg, &changeContent)fmt.Println(changeContent)//业务逻辑,根据信息需要进行的业务逻辑'''c.String(util.Success, "success")//需要返回"success"不然企业微信认为此次请求错误
})

2.安装应用

  1. 企业首先需要安装第三方应用和授权,企业有两种方式进行安装授权。从第三方服务商发起授权比应用商店授权相比,无非是需要第三方服务商自己生成跳转到微信授权网站的链接
  • 从第三方服务商

(1) 获取第三方应用凭证(suite_access_token)

企业微信服务器会定时(每十分钟)推送ticket。ticket会实时变更,并用于后续接口的调用。

请求地址: https://qyapi.weixin.qq.com/cgi-bin/service/get_suite_token

请求包体:

{"suite_id":"wwddddccc7775555aaa" ,"suite_secret": "ldAE_H9anCRN21GKXVfdAAAAAAAAAAAAAAAAAA", "suite_ticket": "Cfp0_givEagXcYJIztF6sfbdmIZCmpaR8ZBsvJEFFNBrWmnD5-CGYJ3_NhYexMyw"
}

参数说明:

参数 是否必须 说明
suite_id 以ww或wx开头应用id(对应于旧的以tj开头的套件id)
suite_secret 应用secret
suite_ticket 企业微信后台推送的ticket

代码实现:

func GetSuiteAccessToken(ticket string) {result, err := util.Post(util.PostSuiteAccessToken, util.WxSuite{SuiteId: model.SuitId, SuiteTicket: ticket, SuiteSecret: model.SuitSecret})if err != nil {fmt.Println("Post Suite Token Fail")}var wxRspSuiteToken util.WxRspSuiteTokenerr = json.Unmarshal([]byte(result), &wxRspSuiteToken)if err != nil {fmt.Println(err)}if wxRspSuiteToken.ErrCode == 0 {model.GetRedis().Set("suiteAccessToken", wxRspSuiteToken.SuiteAccessToken, time.Minute*30)fmt.Println("获取成功,suiteAccessToken==>", cast.ToString(wxRspSuiteToken.SuiteAccessToken))} else {fmt.Println("errCode==>", wxRspSuiteToken.ErrCode)fmt.Println("errMsg==>", wxRspSuiteToken.ErrMsg)}
}

获取到的suite_access_token有效期为2小时,应当进行缓存,接下来各项操作需要携带。

(2) 获取预授权码

请求方式: GET(HTTPS
请求地址: https://qyapi.weixin.qq.com/cgi-bin/service/get_pre_auth_code?suite_access_token=SUITE_ACCESS_TOKEN

参数说明:

参数 是否必须 说明
suite_access_token 第三方应用access_token,最长为512字节

返回结果:

{"errcode":0 ,"errmsg":"ok" ,"pre_auth_code":"Cx_Dk6qiBE0Dmx4EmlT3oRfArPvwSQ-oa3NL_fwHM7VI08r52wazoZX2Rhpz1dEw","expires_in":1200
}

代码实现:

/*预授权码
*/
func GetAuthCode(suiteAccessToken string) string {data, err := util.Get(util.GetAuthCode + "?suite_access_token=" + suiteAccessToken)if err != nil {fmt.Println("预授权码wx请求失败")return ""}var rsp util.WxRspAuthorizationCodeerr = json.Unmarshal(data, &rsp)if err != nil {fmt.Println("预授权码解析失败")return ""}if rsp.ErrCode != 0 {fmt.Println("ErrorCode==>", rsp.ErrCode)fmt.Println("ErrMsg==>", rsp.ErrMsg)return ""}return rsp.PreAuthCode}

*注意:因为是测试应用,还未进行发布,所以要对预授权设置授权,让其支持测试,正式应用不需要此操作。

设置授权配置

该接口可对某次授权进行配置。可支持测试模式(应用未发布时)。

请求方式: POST(HTTPS
请求地址: https://qyapi.weixin.qq.com/cgi-bin/service/set_session_info?suite_access_token=SUITE_ACCESS_TOKEN

请求包体:

{"pre_auth_code":"xxxxx","session_info":{"appid":[1,2,3],"auth_type":1}
}

参数说明:

参数 是否必须 说明
suite_access_token 第三方应用access_token
pre_auth_code 预授权码
session_info 本次授权过程中需要用到的会话信息
appid 允许进行授权的应用id,如1、2、3, 不填或者填空数组都表示允许授权套件内所有应用(仅旧的多应用套件可传此参数,新开发者可忽略)
auth_type 授权类型:0 正式授权, 1 测试授权。 默认值为0。注意,请确保应用在正式发布后的授权类型为“正式授权”

返回结果:

{"errcode": 0,"errmsg": "ok"
}

代码实现:

PreAuthCode := GetAuthCode(suiteAccessToken)
//应用未发布时。测试
req := map[string]interface{}{"pre_auth_code": PreAuthCode,"session_info": map[string]interface{}{"auth_type": 1,},
}
util.Post("https://qyapi.weixin.qq.com/cgi-bin/service/set_session_info"+"?suite_access_token="+suiteAccessToken, &req)

(3) 获取永久授权码

该API用于使用临时授权码换取授权方的永久授权码,并换取授权信息、企业access_token,临时授权码一次有效。

请求方式: POST(HTTPS
请求地址: https://qyapi.weixin.qq.com/cgi-bin/service/get_permanent_code?suite_access_token=SUITE_ACCESS_TOKEN

请求包体:

{"auth_code": "auth_code_value"
}

代码实现:

/*永久授权码
*/
func GetPermanentCode(suiteAccessToken string, authCode string) (string, util.AuthCorpInfo) {post, err := util.Post(util.PostPermanentCode+"?suite_access_token="+suiteAccessToken, util.WxAuthCode{AuthCode: authCode})if err != nil {fmt.Println("Post PermanentCode Fail")return "", util.AuthCorpInfo{}}var wxAuthCode util.WxRspAuthCodeerr = json.Unmarshal([]byte(post), &wxAuthCode)if err != nil {fmt.Println("解析失败")return "", util.AuthCorpInfo{}}if wxAuthCode.ErrCode != 0 {fmt.Println(wxAuthCode.ErrCode)fmt.Println(wxAuthCode.ErrMsg)return "", util.AuthCorpInfo{}} else {return wxAuthCode.PermanentCode, wxAuthCode.AuthCorpInfo}
}

当企业成功安装应用后,企业微信会通过第三方应用后台配置的数据回调URL,将企业的各项信息返回,开发者可以根据自己需要存储信息,最重要的存储授权企业的id(corp_id)永久授权码(permanent_code),后面需要根据指定企业的id,取到相应的永久授权码,从而获取到能获取到指定企业的access_token

3.获取通讯录信息


*注意:在企业安装应用时,在同意安装页面记得需要可见范围范围,不然获取不到整个企业的部门和成员信息

(1)获取企业凭证(access_token)

第三方服务商在取得企业的永久授权码后,通过此接口可以获取到企业的access_token。
获取后可通过通讯录、应用、消息等企业接口来运营这些应用。
此处获得的企业access_token与企业获取access_token拿到的token,本质上是一样的,只不过获取方式不同。获取之后,就跟普通企业一样使用token调用API接口。
*注意:因权限问题获取的信息可能不同。如三方无法直接获取用户名称等

请求方式: POST(HTTPS
请求地址: https://qyapi.weixin.qq.com/cgi-bin/service/get_corp_token?suite_access_token=SUITE_ACCESS_TOKEN

请求包体:

 {"auth_corpid": "auth_corpid_value","permanent_code": "code_value"}

参数说明:

参数 是否必须 说明
auth_corpid 授权方corpid
permanent_code 永久授权码,通过get_permanent_code获取

返回结果:

{"errcode":0 ,"errmsg":"ok" ,"access_token": "xxxxxx", "expires_in": 7200
}

参数说明:

参数 说明
access_token 授权方(企业)access_token,最长为512字节
expires_in 授权方(企业)access_token超时时间

代码实现:

/*第三方应用获取指定企业凭证*/
func GetAccessToken(companyId int) string {var company model.Companymodel.GetDB().Where("company_id = ?", companyId).First(&company)if company.CompanyId == 0 {fmt.Println("公司匹配失败")}preCode := company.PermanentCodeCorpId := company.CorPidsuitToken := model.GetRedis().Get("suiteAccessToken").Val()wxReq := util.WxReqDepartment{AuthCorpid: CorpId, PermanentCode: preCode}data, err := util.Post(util.PostAccessToken+"?suite_access_token="+suitToken, wxReq)if err != nil {fmt.Println(err)}var wxAccessToken util.WxRspAccessTokenjson.Unmarshal([]byte(data), &wxAccessToken)fmt.Println(wxAccessToken)if wxAccessToken.ErrCode != 0 {fmt.Println(wxAccessToken.ErrMsg)return ""} else {fmt.Println("获取成功,AccessToken==>", wxAccessToken.AccessToken)return wxAccessToken.AccessToken}
}

拿到access_token需要先缓存起来,因为企业微信做了频率校验,超过次数将无法获取access_token,token有效期为两个小时,两个小时内获取到的access_token是一样的。有了token就可以访问通讯录的各项信息。

(2)获取部门成员详情

请求方式: GET(HTTPS
请求地址: https://qyapi.weixin.qq.com/cgi-bin/user/list?access_token=ACCESS_TOKEN&department_id=DEPARTMENT_ID&fetch_child=FETCH_CHILD

参数说明:

参数 必须 说明
access_token 调用接口凭证
department_id 获取的部门id
fetch_child 1/0:是否递归获取子部门下面的成员

权限说明:

应用须拥有指定部门的查看权限。
返回结果:

{"errcode": 0,"errmsg": "ok","userlist": [{"userid": "userid","name": "name","department": [1],"gender": "0","avatar": "https://rescdn.qqmail.com/node/wwmng/wwmng/style/images/independent/DefaultAvatar$73ba92b5.png","status": 1,"order": [0],"main_department": 1,"is_leader_in_dept": [],"thumb_avatar": "https://rescdn.qqmail.com/node/wwmng/wwmng/style/images/independent/DefaultAvatar$73ba92b5.png","open_userid": "","direct_leader": []},]
}

第三方应用能拿到企业成员的信息不多,详情可以参照企业微信文档https://developer.work.weixin.qq.com/document/path/90337

(3)获取部门列表

请求方式: GET(HTTPS
请求地址: https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token=ACCESS_TOKEN&id=ID

参数说明 :

参数 必须 说明
access_token 调用接口凭证
id 部门id。获取指定部门及其下的子部门(以及子部门的子部门等等,递归)。 如果不填,默认获取全量组织架构

权限说明:

只能拉取token对应的应用的权限范围内的部门列表

返回结果:

{"errcode": 0,"errmsg": "ok","department": [{"id": 2,"name": "广州研发中心","name_en": "RDGZ","department_leader":["zhangsan","lisi"],"parentid": 1,"order": 10},{"id": 3,"name": "邮箱产品部","name_en": "mail","department_leader":["lisi","wangwu"],"parentid": 2,"order": 40}]
}

(4)通讯录转义

当第三方拉取到信息时会发现,部门名和成员名都等于部门id和成员id,无法显示真实的名称,主要是因为企业微信为了保护隐私,第三方将不再直接获取到授权企业的通讯录数据(接口将不再返回人名与部门名)。
所以开发者如果需要展示名称就需要对名称进行转义,有两种方法可以进行转义。

通讯录组件转换名称

这种方法主要是前端实现,后端只需要返回前端需要的相关配置信息。
详情参照企业微信文档 https://developer.work.weixin.qq.com/document/path/91958

通讯录ID转义

需要前后端配合实现,详情参照企业微信文档 https://developer.work.weixin.qq.com/document/path/91889

实现流程


实现步骤
1.需要先创建一个文件(txt,csv,xls,xlsx,doc,docx),并替换模板,效果如下图所示:


要获取部门名称同理,模板如下:
$departmentName=DEPARTMENT_ID$
$userName=USERID$
将你要查的id替换大写英文的部分,只能转义同一公司的id,不然不会进行转义。
2.上传文件到企业微信,这里是在后端进行上传。

client := http.Client{}
bodyBuf := &bytes.Buffer{}
bodyWrite := multipart.NewWriter(bodyBuf)
//上传给企业微信
//创建请求并设置内容类型
fileWrite, err := bodyWrite.CreateFormFile("media", "file.xlsx")
_, err = io.Copy(fileWrite, excel)
if err != nil {log.Println("err")
}
bodyWrite.Close() //要关闭,会将w.w.boundary刷写到w.writer中
// 创建请求
contentType := bodyWrite.FormDataContentType()
req, err := http.NewRequest(http.MethodPost, util.PostMediaFile+"?provider_access_token="+token+"&type=file", bodyBuf)
if err != nil {log.Println("err")
}
// 设置头
req.Header.Set("Content-Type", contentType)
resp, err := client.Do(req)
if err != nil {log.Println("err")
}
defer resp.Body.Close()
var data1 util.WxRspUploadFile
all, err := ioutil.ReadAll(resp.Body)
if err == nil {//解析responsejson.Unmarshal(all, &data1)
}//返回
{"errcode": 0,"errmsg": "ok. Warning: wrong json format. ","type": "file","media_id": "3zwYR2FyKTQZuuCvvVyrCGb9j8yNrUqjwqA97cXHQBoZF46rDsIWX4l4fzZCBDYzp","created_at": "1652335969"
}

素材上传得到media_id,该media_id仅三天内有效
media_id在同一企业内应用之间可以共享

3.异步通讯录id转译

post, err := util.Post(util.PostTransId+"?provider_access_token="+token,map[string]interface{}{"auth_corpid":      "ww*******",//授权企业corpid ,也就是需要转义的用户、部门id的所属企业的corpid,安装应用时进行了存储。"media_id_list":    []string{data1.MediaId},//上一步上传文件得到的媒体id(media_id),可以上传多个。"output_file_name": "trans_id",//输出的文件名//"output_file_format": "xlsx"//输出格式,若不指定,则输出格式跟输入格式相同。})
fmt.Println(post)
if err != nil {fmt.Println(err)
}var data2 util.WxRspTranId
json.Unmarshal([]byte(post), &data2)
fmt.Println(data2.JobId)//结果
{"errcode": 0,"errmsg": "ok","jobid": "Xq24rw360-NyvhqHnK9ztC_Nr4zeHPyqMbJF-SjwGL0"
}

注:若生成的文件不需要压缩,则 media_id_list列表只能指定一项,同时 output_file_name 不需要传值

4.获取异步任务的结果

get, err := util.Get(util.GetJobResult + "?provider_access_token=" + token + "&jobid=" + data2.JobId + "&debug=1")
var data3 util.WxRspJobResult
json.Unmarshal(get, &data3)
result := cast.ToString(data3.Result["contact_id_translate"].(map[string]interface{})["url"])
fmt.Println(result)//结果
{"errcode": 0,"errmsg": "ok","status": 3,"type": "contact_id_translate","result": {"contact_id_translate": {"url": "https://open.work.weixin.qq.com/wwopen/openData/getTranslateContactOpenData?dataid=j9otnBMVKUDSf4xrAxxxxxxxxxxxxxxxxxxxxxx"}}
}

注:返回的url参数,开发者在使用时以a标签引用,download属性不可指定(浏览器兼容性问题)

5.下载转义后文件,这是最后也是最麻烦的一步,能够下载的条件是:
1.当前浏览器页面进行了授权登录,存在登录态。
可以通过https://open.work.weixin.qq.com/wwopen/openData/debug 来检查当前登录态。

2.需要在配置好的可信域名下进行访问。(不是直接在浏览器中输入打开链接)
满足这两个条件后才会下载id转义后的文件。

4.扫码登录

这里主要讲从第三方进行单点登录,需要构造登录链接以及登录成功回调url大致流程如图所示:

\

(1)构造链接

1、用户进入服务商网站。
2、服务商网站引导用户进入登录授权页。
服务商可以在自己的网站首页中放置“企业微信登录”的入口,引导用户进入登录授权页。网址为:

https://open.work.weixin.qq.com/wwopen/sso/3rd_qrConnect?appid=ww100000a5f2191&redirect_uri=http%3A%2F%2Fwww.oa.com&state=web_login@gyoss9&usertype=admin

3、用户确认并同意授权。
用户进入登录授权页后,需要确认并同意将自己的企业微信和登录账号信息授权给企业或服务商,完成授权流程。
4、授权后回调URI,得到授权码和过期时间。
登录授权发起域名和授权成功回调域名需要在服务商后台进行配置,只能在该域名下才能发起授权和完成授权回调。

参数 是否必须 说明
appid 服务商的CorpID
redirect_uri 授权登录之后目的跳转网址,需要做urlencode处理。所在域名需要与授权完成回调域名一致
state 用于企业或服务商自行校验session,防止跨域攻击
usertype 支持登录的类型。admin代表管理员登录(使用微信扫码),member代表成员登录(使用企业微信扫码),默认为admin
lang 自定义语言,支持zh、en;lang为空则从Headers读取Accept-Language,默认值为zh

代码实现

encode := url.QueryEscape("http://qr-login.xxxxxxxx/wx/returnLogin")//回调地址,需要做urlencode处理
redirect := "https://open.work.weixin.qq.com/wwopen/sso/3rd_qrConnect?appid=" + model.CorpId + "&redirect_uri=" + encode + "&state=" + key + "&usertype=member"
//这里是后端直接跳转到扫码页面
c.Header("Content-Type", "text/html")
c.String(200, "<script type="text/javascript"> window.location.href = ""+redirect+""</script>")

(2)获取登录用户信息

1.先获取服务商凭证(provider_access_token),需要先从服务商后台拿到CorpID和ProviderSecret


2.第三方可通过如下接口,获取登录用户的信息。建议用户以返回信息中的corpid及userid为主键匹配用户。

请求方式: POST(HTTPS
请求地址: https://qyapi.weixin.qq.com/cgi-bin/service/get_login_info?access_token=PROVIDER_ACCESS_TOKEN

请求包体:

 {"auth_code":"xxxxx" //扫码登录成功回调url携带参数}

参数说明:

参数 是否必须 说明
access_token 授权登录服务商的网站时,使用应用提供商的provider_access_token,获取方法参见服务商的凭证
auth_code oauth2.0授权企业微信管理员登录产生的code,最长为512字节。只能使用一次,5分钟未被使用自动过期

代码实现

data, err := util.Post(util.GetLoginInfo+"?access_token="+corpToken, map[string]interface{}{"auth_code": authCode,
})
fmt.Println(data)
if err != nil {fmt.Println("post获取用户信息失败")return
}
var result util.WxRspLoginInfo
json.Unmarshal([]byte(data), &result)
if result.ErrCode != 0 {fmt.Println("获取用户信息失败")return
}

返回结果中可以获取到成员id就可以进行身份校验。

企业微信三方应用服务商获取通讯录及扫码登录(测试应用)相关推荐

  1. 微信小程序使用场景延伸:扫码登录、扫码支付

    微信小程序使用场景延伸:扫码登录.扫码支付 小程序最适合的使用场景有哪些?相比大家能列举出来很多,但这个场景,大家可能多数没想到_^ 笔者团队近期接到了一个PC项目:转转游戏租号PC官网,该项目要求在 ...

  2. 微信公众号开发(4)-实现PC扫码登录

    一.PC微信扫码登录原理简介 PC端调用微信服务端的ticket接口,微信服务端获取ticket,PC端拿到ticket之后,生成带参数登录二维码,用户扫码之后会发送扫码事件消息到微信服务端,这个消息 ...

  3. 企业微信实现扫码登录

    一:获取扫码登陆所需的参数:appid,secret,agentid 登录企业微信:https://work.weixin.qq.com/ 扫码登录文档:https://work.weixin.qq. ...

  4. 微信开放平台开发——网页微信扫码登录(OAuth2.0)

    1.OAuth2.0 OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. 允许用户提供 ...

  5. 微信网页扫码登录与微信公众号授权登录的区别

    最近着手开发了微信网页扫码登录和公众号授权登录收获颇丰,两者的开发很类似.以下是我个人摸索过程中发现的两者的异同: 两者都可以通过微信客户端扫码授权的方式,让第三方页面获得微信用户的一些基本信息(昵称 ...

  6. 微信扫码登录实战(附代码)

    来源:JAVA葵花宝典 导读:由于微信端流量比较足,所以扫码登录系统功能也受到了很多系统的青睐,本文就来详细的解开该技术的面纱. 演示效果 准备工作 1. 需要一个微信开放平台账号,并创建一个网站应用 ...

  7. 企业微信三方开发:注册企业微信服务商

    其他链接 初识微信开发 企业微信三方开发:注册企业微信服务商 企业微信三方开发(一):回调验证及重要参数获取 企业微信三方开发(二):获取access_token 企业微信三方开发(三):网页授权登录 ...

  8. 企业微信三方开发(三):网页授权登录

    其他链接 初识微信开发 企业微信三方开发:注册企业微信服务商 企业微信三方开发(一):回调验证及重要参数获取 企业微信三方开发(二):获取access_token 企业微信三方开发(三):网页授权登录 ...

  9. 企业微信三方开发(五):扫码登录

    其他链接 初识微信开发 企业微信三方开发:注册企业微信服务商 企业微信三方开发(一):回调验证及重要参数获取 企业微信三方开发(二):获取access_token 企业微信三方开发(三):网页授权登录 ...

  10. 企业微信服务商扫码登录

    准备步骤 申请注册企业微信: 企业注册后,需要申请微信服务商 企业微信服务商官网: PS:上述不是本章的主要内容,不做过多详解 进入服务商后台 应用管理–> 登录授权–>设置登录授权发起域 ...

最新文章

  1. 今天是周一,又是热的天气笼罩。
  2. 【转】[iOS] 关于 self = [super init];
  3. mysql数据库优化语句_mysql数据库优化语句
  4. 资深架构专家聊架构之道:规划、简化和演化
  5. 滴滴老板:程维的故事
  6. 论文中图片加方框 matlab代码
  7. netlify支持php吗,用 hugo 和 netlify 搭建blog【转】
  8. Maven实战(高清完整带书签)
  9. 暴风影音 android 电视,暴风影音飞屏版电视端
  10. python打开浏览本地html文件_python解析本地HTML文件
  11. python化学公式配平_如何用矩阵知识配平化学方程式?
  12. HTML5游戏实战 1 50行代码实现正面跑酷游戏
  13. SEO入门知识1:网站改版后怎么做SEO
  14. Unity 引擎开始从 Mono 迁移到 .NET CoreCLR
  15. android锁屏密码文件夹,深入理解Android M 锁屏密码存储方式
  16. 华为让全球震惊:5G基站出货已过万
  17. SQL 左连接中on后面加where和加and的区别
  18. 超分算法小合集之SRCNN、DCSCN、SRDenseNet、SRGAN
  19. 编码理解 | 卷积的实现和卷积神经网络
  20. C语言中关于强制类型转换问题

热门文章

  1. 棋牌app开发需要多少钱
  2. C语言 数组排序 – 冒泡排序
  3. 淘宝店铺介绍范文如何写的技巧详细分析!
  4. 802.1x准入控制技术
  5. gitbub(cp:http://www.linuxidc.com/Linux/2014-03/97821.htm)
  6. html 适合手机浏览器,三款主流手机浏览器HTML5性能横向评测
  7. 算法时间复杂度分析(一)
  8. java-php-python-ssm医院诊疗信息管理计算机毕业设计
  9. 求解会议安排问题 C++实现
  10. CATIA二次开发—定制搜索功能