使用java實(shí)現(xiàn)“釘釘微應(yīng)用免登進(jìn)入某H5系統(tǒng)首頁(yè)“功能”
一、前言
哈哈,這是我的第一篇博客。
先說(shuō)一下這個(gè)小功能的具體場(chǎng)景:
用戶登錄釘釘app,點(diǎn)擊微應(yīng)用,獲取當(dāng)前用戶的信息,與H5系統(tǒng)的數(shù)據(jù)庫(kù)的用戶信息對(duì)比,如果存在該用戶,則點(diǎn)擊后直接進(jìn)入H5系統(tǒng)的首頁(yè),否則顯示“您無(wú)權(quán)限”。
補(bǔ)充:又加了一個(gè)小需求,就是免登成功,會(huì)給該用戶發(fā)條消息
我是參考釘釘開發(fā)文檔實(shí)現(xiàn)的這個(gè)小功能,文檔地址:https://ding-doc.dingtalk.com/doc#/serverapi2/clotub
二、準(zhǔn)備工作
需要?jiǎng)?chuàng)建一個(gè)微應(yīng)用:https://open-dev.dingtalk.com

1.是在企業(yè)內(nèi)部開發(fā)中創(chuàng)建H5微應(yīng)用,不是第三方企業(yè)應(yīng)用中
企業(yè)內(nèi)部開發(fā):企業(yè)內(nèi)部開發(fā)是指“開發(fā)企業(yè)內(nèi)部應(yīng)用”供企業(yè)內(nèi)部的人員使用。企業(yè)可以選擇由企業(yè)內(nèi)部的開發(fā)者進(jìn)行開發(fā),或者由企業(yè)授權(quán)定制服務(wù)商進(jìn)行開發(fā)。
第三方企業(yè)應(yīng)用:第三方企業(yè)應(yīng)用開發(fā),是指開發(fā)者以釘釘、企業(yè)之外的第三方身份,基于釘釘?shù)拈_放能力開發(fā)應(yīng)用,并提供給釘釘上的其他組織使用。(哈哈,這個(gè)區(qū)別我是直接copy文檔中的)
2.H5工程中,創(chuàng)建的一個(gè)前端頁(yè)面ddNoLogin.html(哈哈,這個(gè)起名有點(diǎn)中文式英語(yǔ),因?yàn)槲覜]有找到合適的英文單詞):
該頁(yè)面是用來(lái)獲取免登授權(quán)碼,然后把該code傳遞給后臺(tái)接口的。
3.填寫公司服務(wù)器的公網(wǎng)IP
可以敲命令查看該ip:curl ifconfig.me
4.微應(yīng)用創(chuàng)建好,會(huì)生成三個(gè)參數(shù),
agentId、appKey、appSecret
外加一個(gè)corpId(釘釘開發(fā)者平臺(tái)的首頁(yè)中有顯示),這四個(gè)參數(shù)值是固定的,后續(xù)開發(fā)需用
5.接口權(quán)限
高級(jí)權(quán)限-企業(yè)通訊錄中的接口都需要給開通
6.最后發(fā)布應(yīng)用
三、功能開發(fā)
哈哈,要開始敲代碼了
1.獲取免登授權(quán)碼code
這里調(diào)用的是釘釘JS-API中的方法,本功能調(diào)用的方法是不需要鑒權(quán)的,如果需要鑒權(quán),則還需先dd.config。
關(guān)于功能方法是否需要鑒權(quán),可以去查看JSAPI總覽
ddNoLogin.html:
<!DOCTYPE html>
<html>
<head>
<title>微應(yīng)用登陸</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1 user-scalable=0" />
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" src="http://g.alicdn.com/dingding/open-develop/1.9.0/dingtalk.js"></script>
</head>
<body>
<div id="ddNoLogin"></div>
<script type="text/javascript">
dd.ready(function() {
//1.獲取免登授權(quán)碼code
dd.runtime.permission.requestAuthCode({
corpId : corpId , //企業(yè)id
onSuccess : function(result) {
var code = result.code;
getUserInfo(code); //通過該code可以獲取用戶身份
},
onFail : function(err) {
alert('出錯(cuò)了, ' + err);
}
});
});
function getUserInfo(code) {
$.ajax({
type : "GET",
url : "/xxx/noLogin?code=" + code,
async : false,
dataType : 'json',
contentType : "application/json;charset=utf-8",
success : (function(res) {
if(res.code == "0000"){
window.location.href = '/#/xxxxx';
}else{
$('#ddNoLogin').html(res.msg);
}
}),
});
}
</script>
</body>
</html>
獲取code的實(shí)現(xiàn)是需要用前端JS去寫的
2.獲取access_token
釘釘提供了開放的api后臺(tái)接口,這里通過appkey和appsecret獲取token,請(qǐng)求路徑:https://oapi.dingtalk.com/gettoken?appkey=key&appsecret=secret
該token有效期是2個(gè)小時(shí),有效期內(nèi)重復(fù)獲取,會(huì)返回相同結(jié)果,并自動(dòng)續(xù)期,
故這里我的實(shí)現(xiàn)是:定時(shí)刷新token,每隔1小時(shí)50分鐘去獲取釘釘?shù)膖oken,并緩存到redis中(我把釘釘?shù)南嚓P(guān)配置都放入到application.yml中了)
DdTokenTask.java:
/**
* 定時(shí)獲取釘釘?shù)膖oken
*/
@Component
@EnableScheduling
public class DdTokenTask {
@Autowired
private JedisClient jedisClient;
public static final long cacheTime = 1000 * 60 * 55 * 2;//1小時(shí)50分鐘
@Value("${dtalk.tokenUrl}")
private String tokenUrl;
@Value("${dtalk.app.key}")
private String appKey;
@Value("${dtalk.app.secret}")
private String appSecret;
@Value("${dtalk.redisTokenKey}")
private String tokenKey;
@Value("${dtalk.taskRun}")
private String taskRun;
/**
* 每隔1小時(shí)50分鐘獲取釘釘?shù)腶ccess_token
*/
@Scheduled(fixedRate = cacheTime)
@Async
public void getDdTokenTask(){
if("true".equals(taskRun)){
//刷新
System.out.println("--->>>>>-------------獲取釘釘token的定時(shí)任務(wù)開始了:"+ DateUtil.formatDateToString(new Date(), "HH:mm:ss"));
String accessTokenUrl = tokenUrl + "?appkey=" + appKey + "&appsecret=" + appSecret;
//訪問獲取access_token 有效期是2小時(shí)
String accessToken = JsonUtil.getJsonNode(HttpUtil.doGet(accessTokenUrl)).get("access_token").asText();
//放入到redis中
jedisClient.set(tokenKey, accessToken);
System.out.println("--->>>>>-------------獲取釘釘token的定時(shí)任務(wù)結(jié)束了,token:"+accessToken);
}
}
/*private String getAccessToken(){
//需引入SDK,公司私服沒有
DefaultDingTalkClient client = new
DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
OapiGettokenRequest request = new OapiGettokenRequest();
request.setAppkey("appkey");
request.setAppsecret("appsecret");
request.setHttpMethod("GET");
OapiGettokenResponse response = client.execute(request);
return "";
}*/
}
(哈哈,其實(shí)文檔中提供了釘釘SDK的java寫法,不過公司私服沒有該SDK,所以我就直接用htttp請(qǐng)求了)
3.獲取用戶userid
通過免登授權(quán)碼和access_token獲取用戶的userid,請(qǐng)求路徑:https://oapi.dingtalk.com/user/getuserinfo?access_token=access_token&code=code
4.獲取用戶詳情
請(qǐng)求路徑:https://oapi.dingtalk.com/user/get?access_token=ACCESS_TOKEN&userid=shaocui
會(huì)返回用戶的姓名、手機(jī)號(hào)等所有信息
DdLoginController.java:
@RestController
@RequestMapping("/ddUser")
@Api(value = "/ddUser", description = "釘釘H5微應(yīng)用登錄", tags = {"DdLoginController"})
public class DdLoginController {
@Autowired
private JedisClient jedisClient;
@Value("${dtalk.userUrl}")
private String userUrl;
@Value("${dtalk.userDetailUrl}")
private String userDetailUrl;
@Value("${dtalk.redisTokenKey}")
private String tokenKey;
@Value("${dtalk.agentId}")
private Integer agentId;
@GetMapping("/noLogin")
@ApiOperation( "釘釘免登")
@ApiImplicitParam(paramType = "query", name = "code", value = "免登授權(quán)碼", dataType = "String")
public WebResponse noLogin(@RequestParam("code") String code, HttpServletResponse response){
//2.獲取access_token
String accessToken = jedisClient.get(tokenKey);
//3.獲取用戶userid
String userIdUrl =userUrl + "?access_token=" + accessToken + "&code=" + code;
//訪問獲取userid
JsonNode user = JsonUtil.getJsonNode(HttpUtil.doGet(userIdUrl));
if(user.get("errcode").asInt() != 0){
//有些公司的公網(wǎng)ip不固定,導(dǎo)致微應(yīng)用中設(shè)置的不對(duì),這里就會(huì)報(bào)錯(cuò)
return WebResponse.resFail(user.get("errmsg").asText());
}
String userId = user.get("userid").asText();
//4.獲取用戶詳情 手機(jī)號(hào)
String userInfoUrl = userDetailUrl + "?access_token=" + accessToken + "&userid=" + userId;
//訪問獲取mobile
JsonNode userInfo = JsonUtil.getJsonNode(HttpUtil.doGet(userInfoUrl));
String mobile = userInfo.get("mobile").asText();
System.out.println("釘釘用戶的手機(jī)號(hào):"+mobile);
//通過手機(jī)號(hào)獲取該用戶
SysUser sysUser = 。。。。。;
if(sysUser == null){
//不存在該用戶
return WebResponse.resFail("您無(wú)權(quán)限訪問", null);
}
。。。。。。
//釘釘發(fā)送免登成功消息給用戶
sendMessage(accessToken, userId, userInfo.get("name").asText());
return WebResponse.resSuccess("免登成功", loginUserInfo);
}
//釘釘發(fā)送消息給用戶
private void sendMessage(String token, String userId, String userName){
String messageUrl = "https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2?access_token="+token;
Map<String, Object> map = new HashMap<>();
map.put("agent_id", agentId.longValue());
map.put("userid_list", userId);
map.put("to_all_user", false);
String content = "用戶"+userName+"在"+ DateUtil.formatDateToString(new Date(), "yyyy-MM-dd HH:mm:ss")+"時(shí)成功登錄xxH5端,并進(jìn)入到xxx頁(yè)面";
String msg = "{\"msgtype\":\"text\",\"text\":{\"content\":"+"\""+content+"\""+"}}";
JSONObject jsonObj = JSONObject.parseObject(msg);
map.put("msg",jsonObj);
HttpUtil.doPost(messageUrl, map, "UTF-8", 20000, null);
}
}
(哈哈,那個(gè)。。。。。處的代碼是實(shí)現(xiàn)系統(tǒng)認(rèn)證成功后的具體操作,故這里省略)
到此釘釘免登就實(shí)現(xiàn)了,然后免登成功后給用戶發(fā)送消息
5.工作通知消息
POST請(qǐng)求,請(qǐng)求路徑:https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2?access_token=ACCESS_TOKEN
請(qǐng)求體{agent_id、userid_list、dept_id_list、to_all_user、msg}
注意:
給同一個(gè)用戶發(fā)送相同的內(nèi)容,一天只能發(fā)一次;發(fā)送不同的內(nèi)容,一天可以500次,
故這里我在發(fā)送的消息中添加了當(dāng)前時(shí)間。
(哈哈,一些細(xì)節(jié)的東西我都寫在代碼的注釋里了,最后發(fā)現(xiàn)這個(gè)小功能好像就一點(diǎn)點(diǎn)代碼量)
總結(jié)
以上所述是小編給大家介紹的使用java實(shí)現(xiàn)“釘釘微應(yīng)用免登進(jìn)入某H5系統(tǒng)首頁(yè)“功能”,希望對(duì)大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會(huì)及時(shí)回復(fù)大家的!
相關(guān)文章
基于logback 實(shí)現(xiàn)springboot超級(jí)詳細(xì)的日志配置
java web 下有好幾種日志框架,比如:logback,log4j,log4j2(slj4f 并不是一種日志框架,它相當(dāng)于定義了規(guī)范,實(shí)現(xiàn)了這個(gè)規(guī)范的日志框架就能夠用 slj4f 調(diào)用)。這篇文章主要介紹了基于logback springboot超級(jí)詳細(xì)的日志配置,需要的朋友可以參考下2019-06-06
Java Socket編程實(shí)例(三)- TCP服務(wù)端線程池
這篇文章主要講解Java Socket編程中TCP服務(wù)端線程池的實(shí)例,希望能給大家做一個(gè)參考。2016-06-06
Java基于rest assured實(shí)現(xiàn)接口測(cè)試過程解析
這篇文章主要介紹了Java基于rest assured實(shí)現(xiàn)接口測(cè)試過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03
解決BufferedReader.readLine()遇見的坑
這篇文章主要介紹了解決BufferedReader.readLine()遇見的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
Spring?@Cacheable指定失效時(shí)間實(shí)例
這篇文章主要介紹了Spring?@Cacheable指定失效時(shí)間實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12

