首先要通过钉钉开放平台创建H5微应用,得到企业id(CorpId),和H5微应用凭证:微应用的ID(AgentId)、微应用的唯一标识key(AppKey)、密钥(AppSecret)。
钉钉开放平台链接
https://open-dev.dingtalk.com
钉钉免登录流程:
1、前端通过CorpId获取免登授权码code;
2、后端通过AppKey和AppSecret获取access_token;
3、使用免登授权码code和access_token去获取用户userid;
4、通过access_token和userid去获取用户详情userinfo;
5、拿userinfo信息去和登录用户去比较,如果一致,则免登录成功。
注意事项
因为是企业内部应用免登录,所以不需要鉴权。免登授权码code每次请求返回的数据都不一样,请求一次的时效是5分钟,access_token有效期7200秒,自动续期。
前端代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="/webjars/jquery/jquery.min.js"></script>
<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>
<!-- 引入JSAPI -->
<script src="https://g.alicdn.com/dingding/dingtalk-jsapi/2.10.3/dingtalk.open.js"></script>
<title>企业内部应用钉钉免登录</title>
</head>
<script type="text/javascript">
function relevance(){
// 此方法必须在钉钉环境下才能执行
dd.ready(function() {
// 获取免登授权码code
dd.runtime.permission.requestAuthCode({
corpId : "dingxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" , // 企业id
onSuccess : function(result) {
var code = result.code;
getUserInfo(code); //通过该code可以获取用户身份
},
onFail : function(err) {
alert('获取授权码失败: ' + JSON.stringify(err));
}
});
});
}
function getUserInfo(code) {
$.ajax({
type : "GET",
url : "/ddUser/getUserInfo?code=" + code,
contentType : "application/json;charset=utf-8",
success : (function(res) {
if(res.isLogin){
alert("登陆成功!")
}else{
alert("登录失败!");
}
}),
error: (function (err) {
alert("调用getUserInfo失败 err为:" + JSON.stringify(err));
}),
});
}
</script>
<body style="padding-top: 52px;text-align: center;">
<button onclick="relevance()">立即绑定</button>
</body>
</html>
后端代码
将钉钉开放平台中得到的CorpId,AgentId,AppKey,AppSecret放到application.yml里面。
azure:
corpid: dingxxxxxxxxxxxxxxxxxxxxxxxxxxx
appkey: dingxxxxxxxxxxxxxxx
appsecret: RVYcJvDtymXWsD9lwXBJRd1qKxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
agentid: 9718xxxxx
创建工具类
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
public class HttpHelper {
@Value("${azure.corpid}")
private static String corpid;
@Value("${azure.appsecret}")
private static String appsecret;
@Value("${azure.agentid}")
private static String agentid;
@Value("${azure.appkey}")
private static String appkey;
public static JSONObject httpGet(String url){
//创建httpClient
CloseableHttpClient httpClient= HttpClients.createDefault();
HttpGet httpGet = new HttpGet(url); //生成一个请求
RequestConfig requestConfig = RequestConfig.custom(). //配置请求的一些属性
setSocketTimeout(2000).setConnectTimeout(2000).build();
httpGet.setConfig(requestConfig); //为请求设置属性
CloseableHttpResponse response = null;
try {
response=httpClient.execute(httpGet);
//如果返回结果的code不等于200,说明出错了
if (response.getStatusLine().getStatusCode() != 200) {
return null;
}
HttpEntity entity = response.getEntity(); //reponse返回的数据在entity中
if(entity!=null){
String resultStr= EntityUtils.toString(entity,"utf-8");//将数据转化为string格式
JSONObject result= JSONObject.parseObject(resultStr); //将结果转化为json格式
if(result.getInteger("errcode")==0){ //如果返回值得errcode值为0,则成功
//移除一些没用的元素
result.remove("errcode");
result.remove("errmsg");
return result; //返回有用的信息
}else{ //返回结果出错了,则打印出来
int errCode = result.getInteger("errcode");
String errMsg = result.getString("errmsg");
throw new Exception("ErrorCode:"+errCode+"ErrorMsg"+errMsg);
}
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (response != null) try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
// 调用httpGet方法获得access_token的代码实现:
public static String getAccess_Token(String appkey,String appsecret){
String url="https://oapi.dingtalk.com/gettoken?"+"appkey="+appkey+"&appsecret="+appsecret;
JSONObject res= HttpHelper.httpGet(url); //将httpGet方法封装在HttpHelper类中
String access_token="";
if(res!=null){
access_token=res.getString("access_token");
}else{
new Exception("获取token异常");
}
return access_token;
}
// 执行POST请求(如果免登录成功后不需要推送钉钉消息,则不需要此方法)
public static String httpPost(String url, Map<String, Object> params, String encoding) throws Exception {
String result = "";
// 创建默认的httpClient实例.
CloseableHttpClient httpclient = HttpClients.createDefault();
// 创建httppost
HttpPost httppost = new HttpPost(url);
//参数
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
if (params != null) {
Set<String> keys = params.keySet();
for (String key : keys) {
formparams.add(new BasicNameValuePair(key, params.get(key).toString()));
}
}
UrlEncodedFormEntity uefEntity;
try {
uefEntity = new UrlEncodedFormEntity(formparams, encoding);
httppost.setEntity(uefEntity);
CloseableHttpResponse response = httpclient.execute(httppost);
try {
Header[] headers = response.getAllHeaders();
for (Header header : headers) {
log.debug(header.getName() + "-->" + header.getValue());
}
HttpEntity entity = response.getEntity();
if (entity != null) {
result = EntityUtils.toString(entity, encoding);
}
} finally {
response.close();
}
} catch (IOException e) {
throw e;
} finally {
// 关闭连接,释放资源
try {
httpclient.close();
} catch (IOException e) {
}
}
return result;
}
}
Controller层
import com.alibaba.fastjson.JSONObject;
import com.totyu.mmc.controller.dingding2.model.contact.User;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/ddUser")
@Api(value = "/ddUser")
public class DingdingController {
@Value("${azure.corpid}")
private String corpid;
@Value("${azure.appkey}")
private String appkey;
@Value("${azure.appsecret}")
private String appsecret;
@Value("${azure.agentid}")
private String agentid;
private static final String GET_USERINFO_BYCODE_URL="https://oapi.dingtalk.com/user/getuserinfo?access_token=ACCESSTOKEN&code=CODE";
private static final String GET_USER_URL="https://oapi.dingtalk.com/user/get?access_token=ACCESSTOKEN&userid=USERID";
/** 根据免登授权码Code查询免登用户
* @param code
*/
@GetMapping("/getUserInfo")
public JSONObject getUserInfo(@RequestParam("code") String code) {
JSONObject jsonObject = new JSONObject();
try {
// 获取access_token
String accessToken = HttpHelper.getAccess_Token(appkey,appsecret);
// UserId的URL
String getUserIdURL = GET_USERINFO_BYCODE_URL.replace("ACCESSTOKEN", accessToken).replace("CODE", code);
// 发起GET请求,获取返回结果
jsonObject = HttpHelper.httpGet(getUserIdURL);
String userid = (String)jsonObject.get("userid");
// User详情的URL
String getUserURL = GET_USER_URL.replace("ACCESSTOKEN", accessToken).replace("USERID", userid);
// 发起GET请求,获取返回结果
jsonObject = HttpHelper.httpGet(getUserURL);
// 钉钉发送消息给用户
sendMessage(accessToken,userid,(String)jsonObject.get("name"));
jsonObject.put("isLogin",true);
} catch (Exception e) {
e.printStackTrace();
jsonObject.put("isLogin",false);
}
return jsonObject;
}
// 钉钉发送消息给用户
private void sendMessage(String token, String userid, String userName) throws Exception{
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);
map.put("userid_list", userid);
map.put("to_all_user", false);
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒");
String date = dateformat.format(new Date());
String content = "用户"+userName+"在"+ date +"时成功登录xxx!";
String msg = "{\"msgtype\":\"text\",\"text\":{\"content\":"+"\""+content+"\""+"}}";
JSONObject jsonObj = JSONObject.parseObject(msg);
map.put("msg",jsonObj);
HttpHelper.httpPost(messageUrl,map,"UTF-8");
}
}
到此就可以实现免登录钉钉了,业务层可以根据需求自己加。