标签:auth erro 加密 cal mapping you eof input 远程
此类是HttpRequest.java
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/**
     * get请求
     * @param url 为接口地址参数
     * @return
     */
    public static JSONObject doGetStr(String url){
         CloseableHttpClient httpClient = HttpClients.createDefault();
         HttpGet httpGet = new HttpGet(url);
         CloseableHttpResponse response = null;
         JSONObject jsonObject = null;//接收结果
         try {
            response = httpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();//从消息体里获取结果
            if(entity!=null){
                String result = EntityUtils.toString(entity,"UTF-8");
                jsonObject = JSONObject.parseObject(result);
            }
            EntityUtils.consume(entity);
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(response != null){
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
         return jsonObject;
    }
    
    /**
     * post请求
     * @param url 为接口地址参数
     * @param outStr
     * @return
     */
    public static JSONObject doPostStr(String url,String outStr){
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(url);
        JSONObject jsonObject = null;
        try {
            httpPost.setEntity(new StringEntity(outStr, "UTF-8"));
            HttpResponse response = httpClient.execute(httpPost);
            String result = EntityUtils.toString(response.getEntity(), "UTF-8");
            jsonObject = JSONObject.parseObject(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return jsonObject;
    }
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2.Constants.java
/** 注册事件回调接口(请求方式:post) */
    public static final String REGISTER_CALL_BACK = "https://oapi.dingtalk.com/call_back/register_call_back?access_token=ACCESS_TOKEN";
    
    /** 查询事件回调接口(请求方式:get) */
    public static final String GET_CALL_BACK = "https://oapi.dingtalk.com/call_back/get_call_back?access_token=ACCESS_TOKEN";
    
    /** 更新事件回调接口(请求方式:post) */
    public static final String UPDATE_CALL_BACK = "https://oapi.dingtalk.com/call_back/update_call_back?access_token=ACCESS_TOKEN";
    
    /** 删除事件回调接口(请求方式:get) */
    public static final String DELETE_CALL_BACK = "https://oapi.dingtalk.com/call_back/delete_call_back?access_token=ACCESS_TOKEN";
    
    /** 获取回调失败的结果 (请求方式:get)*/
    public static final String GET_CALL_BACK_FAILED_RESULT = "https://oapi.dingtalk.com/call_back/get_call_back_failed_result?access_token=ACCESS_TOKEN";
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3.Utils.java
 
    /**
    *
    * @return
    */
   public static String getRandomStr(int count) {
       String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
       Random random = new Random();
       StringBuffer sb = new StringBuffer();
       for (int i = 0; i < count; i++) {
           int number = random.nextInt(base.length());
           sb.append(base.charAt(number));
       }
       return sb.toString();
   }
   /*
    * int转byte数组,高位在前
    */
   public static byte[] int2Bytes(int count) {
       byte[] byteArr = new byte[4];
       byteArr[3] = (byte) (count & 0xFF);
       byteArr[2] = (byte) (count >> 8 & 0xFF);
       byteArr[1] = (byte) (count >> 16 & 0xFF);
       byteArr[0] = (byte) (count >> 24 & 0xFF);
       return byteArr;
   }
   /**
    * 高位在前bytes数组转int
    * @param byteArr
    * @return
    */
   public static int bytes2int(byte[] byteArr) {
       int count = 0;
       for (int i = 0; i < 4; i++) {
           count <<= 8;
           count |= byteArr[i] & 0xff;
       }
       return count;
   }
 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   4.DingtalkController.java
   @CrossOrigin
	@ResponseBody
	@RequestMapping(value = "/join/dingtalk/callbackreceive.htm", method = RequestMethod.POST,produces = "application/json;charset=UTF-8")
	public String addCallbackreceive(HttpServletRequest request,HttpServletResponse response) {
		String result="false";
		try {
			/** url中的签名 **/
            String msgSignature = request.getParameter("signature");
            /** url中的时间戳 **/
            String timeStamp = request.getParameter("timestamp");
            /** url中的随机字符串 **/
            String nonce = request.getParameter("nonce");
            /** 取得JSON对象中的encrypt字段     **/
            String encrypt = "";
            
            ServletInputStream sis = request.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(sis));
            String line = null;
            StringBuilder sb = new StringBuilder();
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            JSONObject jsonEncrypt = JSONObject.parseObject(sb.toString());
            String res = "success";  //res是需要返回给钉钉服务器的字符串,一般为success;
            if(jsonEncrypt!=null&&jsonEncrypt.size()>0&&jsonEncrypt.containsKey("encrypt")){
            	 encrypt = jsonEncrypt.getString("encrypt");
            	 String decodeEncrypt = decodeEncrypt(msgSignature, timeStamp, nonce, encrypt); //密文解密
                 JSONObject decodeEncryptJson = JSONObject.parseObject(decodeEncrypt);
                 String eventType ="";
                 if(decodeEncryptJson!=null&&decodeEncryptJson.size()>0&&decodeEncryptJson.containsKey("EventType")){
                 	eventType = decodeEncryptJson.getString("EventType");  //回调类型
                 }
                
                 JSONObject jsonObjectData = new JSONObject();
                 //根据不同的回调类型,进行相应的操作
                 switch (eventType) {
                 	//审批任务开始,结束,转交
                 	case AddressListRegister.SEALAPPLY_TASK_CHANGE :
                 		String processInstanceId =decodeEncryptJson.getString("processInstanceId");//审批实例id
                 		//根据你审批实例获取审批单内容
                 		String corpId =decodeEncryptJson.getString("corpId");//审批实例id
                 		String type  = decodeEncryptJson.getString("type");//类型,判断是开始还是结束
                 		String staffId  = decodeEncryptJson.getString("staffId");//审批人的id
                 		String createTime = decodeEncryptJson.getString("createTime");//审批开始时间
                 		long time = Long.parseLong(createTime);
                        Date date = new Date(time);
                        createTime= StringUtil.DateToString(date, DateUtil.DATE_FORMAT_YMDHM);//开始时间
                        Date createTimeDate =StringUtil.StringToDate(createTime, DateUtil.DATE_FORMAT_LX_YMDHMS);
                 		String title = decodeEncryptJson.getString("title");//实例的标题
                 		if(decodeEncryptJson.getString("type").equals("strat")){
                 			
                 		}else if(decodeEncryptJson.getString("type").equals("finish")){
                 			String finishTime = decodeEncryptJson.getString("finishTime");//审批结束时间
                 			long timeEnd = Long.parseLong(finishTime);
                            Date dateEnd = new Date(timeEnd);
                            createTime= StringUtil.DateToString(dateEnd, DateUtil.DATE_FORMAT_YMDHM);//审批结束时间
                            Date finishTimeDate =StringUtil.StringToDate(createTime, DateUtil.DATE_FORMAT_LX_YMDHMS);
                 			
                 			String result_type  =  decodeEncryptJson.getString("result");//同意时result为agree,拒绝时result为refuse
                 			if("agree".equals(result_type)||"refuse".equals(result_type)){//任务结束(同意或者拒绝)
                 				String  remark  = decodeEncryptJson.getString("remark");//审批意见
                 				
                 			}else if("redirect".equals(result_type)){//任务转交
                 				
                 			}
                 		}
                 	break;
                 	//审批实例开始,结束
                 	case AddressListRegister.SEALAPPLY_INSTANCE_CHANGE :
                 		String start_instance_Person  = decodeEncryptJson.getString("staffId");//发起实例的员工
                 		
                 	break;
                 	
                 	default: // do something
                     break;
                 }
                 result = codeEncrypt(res, timeStamp, nonce).toString();
                 //response.getWriter().append(codeEncrypt(res, timeStamp, nonce).toString()); //返回加密后的数据
            }
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}
	 /**
     * 创建加密/解密 类
     * @return
     */
    public DingTalkEncryptor createDingTalkEncryptor(){
        DingTalkEncryptor dingTalkEncryptor = null;  //加密方法类
        try {
            dingTalkEncryptor = new DingTalkEncryptor(AddressListRegister.TOKEN, AddressListRegister.AES_KEY,AddressListRegister.CORPID);  //创建加解密类
        } catch (DingTalkEncryptException e) {
            e.printStackTrace();
        }
        return dingTalkEncryptor;
    }
    
    /**
     * encrypt解密
     * @param msgSignature
     * @param timeStamp
     * @param nonce
     * @param encrypt  密文
     * @return decodeEncrypt 解密后的明文
     */
    public String decodeEncrypt(String msgSignature,String timeStamp,String nonce,String encrypt){
            String decodeEncrypt = null;
            try {
                decodeEncrypt = createDingTalkEncryptor().getDecryptMsg(msgSignature, timeStamp, nonce, encrypt); //encrypt解密
            } catch (DingTalkEncryptException e) {
                e.printStackTrace();
            }
        return decodeEncrypt;
    }
    
    
    /**
     *  对返回信息进行加密
     * @param res
     * @param timeStamp
     * @param nonce
     * @return
     */
    public JSONObject codeEncrypt(String res,String timeStamp,String nonce){
        long timeStampLong = Long.parseLong(timeStamp);
        Map<String, String> jsonMap = null;
        try {
            jsonMap = createDingTalkEncryptor().getEncryptedMap(res, timeStampLong, nonce); //jsonMap是需要返回给钉钉服务器的加密数据包
        } catch (DingTalkEncryptException e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        JSONObject json = new JSONObject();
        json.putAll(jsonMap);
        return json;
    }
    
  //测试方法
    public static void main(String[] args) throws ApiException {
    	String accesstoken = DingTalkUtils.getAccessToken_new("ding9doc7pnuxjwpvpw7","XwEoy0NQSCZWRmR8GfwsBoqg0_1nVnRsZy7GWgROsQhaFnnvixaZMj_5bzosLVQa");
        String token = AddressListRegister.TOKEN;
        String aesKey = AddressListRegister.AES_KEY;
        String callBackUrl = "http://21664l066q.imwork.net:50125/join/dingtalk/callbackreceive.htm";
        
        List<String> listStr = new ArrayList<String>();
        listStr.add("bpms_task_change");
        listStr.add("bpms_instance_change");
        JSONObject registerCallBack = DingTalkUtils.registerCallBack(accesstoken, listStr, token, aesKey, callBackUrl);
        System.out.println("注册事件返回:"+registerCallBack);
        
        JSONObject callBack = DingTalkUtils.getCallBack(accesstoken);
        System.out.println("查询注册事件:"+callBack);
        
        
        
    }
 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    5.  以下是公共类
    5.1
  package com.shjysoft.base.util.dingtalk;
/**
 * <p>几个参数和通讯录和审批注册 需要监听的事件类型<p>
 * @version 1.0
 * @author li_hao
 * @date 2017年12月15日
 */
public class AddressListRegister{
    
    /**企业的corpid */
    public static final String CORPID = "ding7ee8e144c63d6a48";
    /**钉钉开放平台上,开发者设置的token */
    public static final String TOKEN = "token";
    /**数据加密密钥。用于回调数据的加密,长度固定为43个字符,从a-z, A-Z, 0-9共62个字符中选取,您可以随机生成,ISV(服务提供商)推荐使用注册套件时填写的EncodingAESKey */
    public static final String AES_KEY = "abcxx7p5qnb6zs3xxxxxlkfmxqfkv23d40yd0xxxxxx";
    
    /**通讯录用户增加 */
    public static final String USER_ADD_ORG = "user_add_org";
    /**通讯录用户更改*/
    public static final String USER_MODIFY_ORG = "user_modify_org";
    /** 通讯录用户离职 */
    public static final String USER_LEAVE_ORG = "user_leave_org";
    /** 通讯录用户被设为管理员 */
    public static final String ORG_ADMIN_ADD = "org_admin_add";
    /** 通讯录用户被取消设置管理员 */
    public static final String ORG_ADMIN_REMOVE = "org_admin_remove";
    /**通讯录企业部门创建*/
    public static final String ORG_DEPT_CREATE = "org_dept_create";
    /** 通讯录企业部门修改 */
    public static final String ORG_DEPT_MODIFY = "org_dept_modify";
    /**通讯录企业部门删除*/
    public static final String ORG_DEPT_REMOVE = "org_dept_remove";
    /**企业被解散*/
    public static final String ORG_REMOVE = "org_remove";
    /**企业信息发生变更*/
    public static final String ORG_CHANGE = "org_change";
    /**员工角色信息发生变更*/
    public static final String LABEL_USER_CHANGE = "label_user_change";
    /**增加角色或者角色组*/
    public static final String LABEL_CONF_ADD = "label_conf_add";
    /**删除角色或者角色组*/
    public static final String LABEL_CONF_DEL = "label_conf_del";
    /**修改角色或者角色组*/
    public static final String LABEL_CONF_MODIFY = "label_conf_modify";
    /**测试回调接口事件类型*/
    public static final String CHECK_URL = "check_url";
    public static final String SEALAPPLY_TASK_CHANGE = "bpms_task_change";//审批任务开始,结束,转交
    public static final String SEALAPPLY_INSTANCE_CHANGE = "bpms_instance_change";//审批实例开始,结束
}
 5.2
 package com.shjysoft.base.util.dingtalk;
import java.util.HashMap;
import java.util.Map;
/**
 * 加解密异常类
 */
public class DingTalkEncryptException extends Exception {
    /**成功**/
    public static final int SUCCESS = 0;
    /**加密明文文本非法**/
    public final static int  ENCRYPTION_PLAINTEXT_ILLEGAL = 900001;
    /**加密时间戳参数非法**/
    public final static int  ENCRYPTION_TIMESTAMP_ILLEGAL = 900002;
    /**加密随机字符串参数非法**/
    public final static int  ENCRYPTION_NONCE_ILLEGAL = 900003;
    /**不合法的aeskey**/
    public final static int AES_KEY_ILLEGAL = 900004;
    /**签名不匹配**/
    public final static int SIGNATURE_NOT_MATCH = 900005;
    /**计算签名错误**/
    public final static int COMPUTE_SIGNATURE_ERROR = 900006;
    /**计算加密文字错误**/
    public final static int COMPUTE_ENCRYPT_TEXT_ERROR  = 900007;
    /**计算解密文字错误**/
    public final static int COMPUTE_DECRYPT_TEXT_ERROR  = 900008;
    /**计算解密文字长度不匹配**/
    public final static int COMPUTE_DECRYPT_TEXT_LENGTH_ERROR  = 900009;
    /**计算解密文字suiteKey(ISV)或者corpid(普通企业)不匹配**/
    public final static int COMPUTE_DECRYPT_TEXT_CORPID_ERROR  = 900010;
    private static Map<Integer,String> msgMap = new HashMap<Integer,String>();
    static{
        msgMap.put(SUCCESS,"成功");
        msgMap.put(ENCRYPTION_PLAINTEXT_ILLEGAL,"加密明文文本非法");
        msgMap.put(ENCRYPTION_TIMESTAMP_ILLEGAL,"加密时间戳参数非法");
        msgMap.put(ENCRYPTION_NONCE_ILLEGAL,"加密随机字符串参数非法");
        msgMap.put(SIGNATURE_NOT_MATCH,"签名不匹配");
        msgMap.put(COMPUTE_SIGNATURE_ERROR,"签名计算失败");
        msgMap.put(AES_KEY_ILLEGAL,"不合法的aes key");
        msgMap.put(COMPUTE_ENCRYPT_TEXT_ERROR,"计算加密文字错误");
        msgMap.put(COMPUTE_DECRYPT_TEXT_ERROR,"计算解密文字错误");
        msgMap.put(COMPUTE_DECRYPT_TEXT_LENGTH_ERROR,"计算解密文字长度不匹配");
        msgMap.put(COMPUTE_DECRYPT_TEXT_CORPID_ERROR,"计算解密文字suiteKey(ISV)或者corpid(普通企业)不匹配");
    }
    public Integer  code;
    public DingTalkEncryptException(Integer exceptionCode){
        super(msgMap.get(exceptionCode));
        this.code = exceptionCode;
    }
}
5.3
package com.shjysoft.base.util.dingtalk;
import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.util.*;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import com.shjysoft.base.util.ip.Utils;
/**
 * 加解密方法
 * 在ORACLE官方网站下载JCE无限制权限策略文件
 *     JDK6的下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html
 *     JDK7的下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
 */
public class DingTalkEncryptor {
    private static final Charset CHARSET = Charset.forName("utf-8");
    private static final Base64         base64  = new Base64();
    private byte[]         aesKey;
    private String         token;
    private String         corpId;
    /**ask getPaddingBytes key固定长度**/
    private static final Integer AES_ENCODE_KEY_LENGTH = 43;
    /**加密随机字符串字节长度**/
    private static final Integer RANDOM_LENGTH = 16;
    /**
     * 构造函数
     * @param token             钉钉开放平台上,开发者设置的token
     * @param encodingAesKey  钉钉开放台上,开发者设置的EncodingAESKey
     * @param corpId           ISV进行配置的时候应该传对应套件的SUITE_KEY(第一次创建时传的是默认的CREATE_SUITE_KEY),普通企业是Corpid
     * @throws DingTalkEncryptException 执行失败,请查看该异常的错误码和具体的错误信息
     */
    public DingTalkEncryptor(String token, String encodingAesKey, String corpId) throws DingTalkEncryptException{
        if (null==encodingAesKey ||  encodingAesKey.length() != AES_ENCODE_KEY_LENGTH) {
            throw new DingTalkEncryptException(DingTalkEncryptException.AES_KEY_ILLEGAL);
        }
        this.token = token;
        this.corpId = corpId;
        aesKey = Base64.decodeBase64(encodingAesKey + "=");
    }
    /**
     * 将和钉钉开放平台同步的消息体加密,返回加密Map
     * @param plaintext     传递的消息体明文
     * @param timeStamp      时间戳
     * @param nonce           随机字符串
     * @return
     * @throws DingTalkEncryptException
     */
    public Map<String,String> getEncryptedMap(String plaintext, Long timeStamp, String nonce) throws DingTalkEncryptException {
        if(null==plaintext){
            throw new DingTalkEncryptException(DingTalkEncryptException.ENCRYPTION_PLAINTEXT_ILLEGAL);
        }
        if(null==timeStamp){
            throw new DingTalkEncryptException(DingTalkEncryptException.ENCRYPTION_TIMESTAMP_ILLEGAL);
        }
        if(null==nonce){
            throw new DingTalkEncryptException(DingTalkEncryptException.ENCRYPTION_NONCE_ILLEGAL);
        }
        // 加密
        String encrypt = encrypt(Utils.getRandomStr(RANDOM_LENGTH), plaintext);
        String signature = getSignature(token, String.valueOf(timeStamp), nonce, encrypt);
        Map<String,String> resultMap = new HashMap<String, String>();
        resultMap.put("msg_signature", signature);
        resultMap.put("encrypt", encrypt);
        resultMap.put("timeStamp", String.valueOf(timeStamp));
        resultMap.put("nonce", nonce);
        return  resultMap;
    }
    /**
     * 密文解密
     * @param msgSignature     签名串
     * @param timeStamp        时间戳
     * @param nonce             随机串
     * @param encryptMsg       密文
     * @return                  解密后的原文
     * @throws DingTalkEncryptException
     */
    public String getDecryptMsg(String msgSignature, String timeStamp, String nonce, String encryptMsg)throws DingTalkEncryptException {
        //校验签名
        String signature = getSignature(token, timeStamp, nonce, encryptMsg);
        if (!signature.equals(msgSignature)) {
            throw new DingTalkEncryptException(DingTalkEncryptException.COMPUTE_SIGNATURE_ERROR);
        }
        // 解密
        String result = decrypt(encryptMsg);
        return result;
    }
    /*
     * 对明文加密.
     * @param text 需要加密的明文
     * @return 加密后base64编码的字符串
     */
    private String encrypt(String random, String plaintext) throws DingTalkEncryptException {
        try {
            byte[] randomBytes = random.getBytes(CHARSET);
            byte[] plainTextBytes = plaintext.getBytes(CHARSET);
            byte[] lengthByte = Utils.int2Bytes(plainTextBytes.length);
            byte[] corpidBytes = corpId.getBytes(CHARSET);
            ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
            byteStream.write(randomBytes);
            byteStream.write(lengthByte);
            byteStream.write(plainTextBytes);
            byteStream.write(corpidBytes);
            byte[] padBytes = PKCS7Padding.getPaddingBytes(byteStream.size());
            byteStream.write(padBytes);
            byte[] unencrypted = byteStream.toByteArray();
            byteStream.close();
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
            IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
            byte[] encrypted = cipher.doFinal(unencrypted);
            String result = base64.encodeToString(encrypted);
            return result;
        } catch (Exception e) {
            throw new DingTalkEncryptException(DingTalkEncryptException.COMPUTE_ENCRYPT_TEXT_ERROR);
        }
    }
    /*
     * 对密文进行解密.
     * @param text 需要解密的密文
     * @return 解密得到的明文
     */
    private String decrypt(String text) throws DingTalkEncryptException {
        byte[] originalArr;
        try {
            // 设置解密模式为AES的CBC模式
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
            IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
            cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
            // 使用BASE64对密文进行解码
            byte[] encrypted = Base64.decodeBase64(text);
            // 解密
            originalArr = cipher.doFinal(encrypted);
        } catch (Exception e) {
            throw new DingTalkEncryptException(DingTalkEncryptException.COMPUTE_DECRYPT_TEXT_ERROR);
        }
        String plainText;
        String fromCorpid;
        try {
            // 去除补位字符
            byte[] bytes = PKCS7Padding.removePaddingBytes(originalArr);
            // 分离16位随机字符串,网络字节序和corpId
            byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);
            int plainTextLegth = Utils.bytes2int(networkOrder);
            plainText = new String(Arrays.copyOfRange(bytes, 20, 20 + plainTextLegth), CHARSET);
            fromCorpid = new String(Arrays.copyOfRange(bytes, 20 + plainTextLegth, bytes.length), CHARSET);
        } catch (Exception e) {
            throw new DingTalkEncryptException(DingTalkEncryptException.COMPUTE_DECRYPT_TEXT_LENGTH_ERROR);
        }
        // corpid不相同的情况
        if (!fromCorpid.equals(corpId)) {
            throw new DingTalkEncryptException(DingTalkEncryptException.COMPUTE_DECRYPT_TEXT_CORPID_ERROR);
        }
        return plainText;
    }
    /**
     * 数字签名
     * @param token         isv token
     * @param timestamp     时间戳
     * @param nonce          随机串
     * @param encrypt       加密文本
     * @return
     * @throws DingTalkEncryptException
     */
    public String getSignature(String token, String timestamp, String nonce, String encrypt) throws DingTalkEncryptException {
        try {
            String[] array = new String[] { token, timestamp, nonce, encrypt };
            Arrays.sort(array);
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < 4; i++) {
                sb.append(array[i]);
            }
            String str = sb.toString();
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            md.update(str.getBytes());
            byte[] digest = md.digest();
            StringBuffer hexstr = new StringBuffer();
            String shaHex = "";
            for (int i = 0; i < digest.length; i++) {
                shaHex = Integer.toHexString(digest[i] & 0xFF);
                if (shaHex.length() < 2) {
                    hexstr.append(0);
                }
                hexstr.append(shaHex);
            }
            return hexstr.toString();
        } catch (Exception e) {
            throw new DingTalkEncryptException(DingTalkEncryptException.COMPUTE_SIGNATURE_ERROR);
        }
    }
}
5.4
package com.shjysoft.base.util.dingtalk;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.io.IOUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiProcessinstanceCreateRequest;
import com.dingtalk.api.request.OapiProcessinstanceCreateRequest.FormComponentValueVo;
import com.dingtalk.api.request.OapiProcessinstanceGetRequest;
import com.dingtalk.api.response.OapiProcessinstanceCreateResponse;
import com.dingtalk.api.response.OapiProcessinstanceGetResponse;
import com.dingtalk.api.response.OapiProcessinstanceGetResponse.ProcessInstanceTopVo;
import com.shjysoft.base.util.common.HttpRequest;
import com.shjysoft.base.util.common.StringUtil;
import com.shjysoft.base.util.constants.Constants;
import com.taobao.api.ApiException;
/**
 * 钉钉微应用接口工具类
 * @author zhouqi
 *
 */
public class DingTalkUtils {
	/**
	 * 获取accestoken
	 * @return
	 */
	public static String getAccessToken(String corpid,String corpSecret){
		String accesstoken = null;
		try {
			HttpClient httpClient = new HttpClient();
			GetMethod getMethod = new GetMethod("https://oapi.dingtalk.com/gettoken?corpid="+corpid+"&corpsecret="+corpSecret);
			int stats=httpClient.executeMethod(getMethod);
			if(stats == HttpStatus.SC_OK){
				String result = IOUtils.toString(getMethod.getResponseBodyAsStream(),"UTF-8");
				JSONObject json = JSONObject.parseObject(result);
				if(Integer.parseInt(json.get("errcode").toString()) == 0){
					accesstoken = json.getString("access_token");
				}
			}
		} catch (HttpException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return accesstoken;
	}
	
	/**
	 * 获取accestoken--新版本
	 * @return
	 */
	public static String getAccessToken_new(String appkey,String appsecret){
		String accesstoken = null;
		try {
			HttpClient httpClient = new HttpClient();
			GetMethod getMethod = new GetMethod("https://oapi.dingtalk.com/gettoken?appkey="+appkey+"&appsecret="+appsecret);
			int stats=httpClient.executeMethod(getMethod);
			if(stats == HttpStatus.SC_OK){
				String result = IOUtils.toString(getMethod.getResponseBodyAsStream(),"UTF-8");
				JSONObject json = JSONObject.parseObject(result);
				if(Integer.parseInt(json.get("errcode").toString()) == 0){
					accesstoken = json.getString("access_token");
				}
			}
		} catch (HttpException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return accesstoken;
	}
	
	/**
	 * 获取jsapi_ticket
	 * @param accesstoken
	 * @return
	 */
	public static String getJsapi_ticket(String accesstoken){
		String jsapi_ticket = null;
		try {
			HttpClient httpClient = new HttpClient();
			GetMethod getMethod = new GetMethod("https://oapi.dingtalk.com/get_jsapi_ticket?access_token="+accesstoken);
			int stats=httpClient.executeMethod(getMethod);
			if(stats == HttpStatus.SC_OK){
				String result = IOUtils.toString(getMethod.getResponseBodyAsStream(),"UTF-8");
				JSONObject json = JSONObject.parseObject(result);
				if(Integer.parseInt(json.get("errcode").toString()) == 0){
					jsapi_ticket = json.getString("ticket");
				}
			}
		} catch (HttpException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return jsapi_ticket;
	}
	
	
	
	/**
	 * 根据code获取userid
	 * @param accesstoken
	 * @param code
	 * @return
	 */
	public static String getUserId(String accesstoken,String code){
		String userId = null;
		try {
			HttpClient httpClient = new HttpClient();
			GetMethod getMethod = new GetMethod("https://oapi.dingtalk.com/user/getuserinfo?access_token="+accesstoken+"&code="+code);
			int stats = httpClient.executeMethod(getMethod);
			if(stats == HttpStatus.SC_OK){
				String result = IOUtils.toString(getMethod.getResponseBodyAsStream(),"UTF-8");
				JSONObject json = JSONObject.parseObject(result);
				if(Integer.parseInt(json.get("errcode").toString()) == 0){
					userId = json.getString("userid");
				}
			}
		} catch (HttpException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return userId;
	}
	
	/**
	 * 根据userid获取用户信息
	 * @param accesstoken
	 * @param userId
	 * @return
	 */
	public static String getUserInfo(String accesstoken,String userId){
		String userInfo = null;
		try {
			HttpClient httpClient = new HttpClient();
			GetMethod getMethod = new GetMethod("https://oapi.dingtalk.com/user/get?access_token="+accesstoken+"&userid="+userId);
			int stats = httpClient.executeMethod(getMethod);
			if(stats == HttpStatus.SC_OK){
				userInfo = IOUtils.toString(getMethod.getResponseBodyAsStream(),"UTF-8");
			}
		} catch (HttpException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return userInfo;
	}
	
	/**
	 * 获取部门列表
	 * @param accesstoken
	 * @return
	 */
	public static String getDepartmentList(String accesstoken,String parent_id){
		try {
			HttpClient httpClient = new HttpClient();
			GetMethod getMethod = new GetMethod("https://oapi.dingtalk.com/department/list?access_token="+accesstoken+"&id="+parent_id);
			int stats = httpClient.executeMethod(getMethod);
			if(stats == HttpStatus.SC_OK){
				String result = IOUtils.toString(getMethod.getResponseBodyAsStream(),"UTF-8");
				JSONObject json = JSONObject.parseObject(result);
				if(Integer.parseInt(json.get("errcode").toString()) == 0){
					return json.getString("department");
				}
			}
		} catch (HttpException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 获取部门列表
	 * @param accesstoken
	 * @return
	 */
	public static String getDepartmentList(String accesstoken){
		try {
			HttpClient httpClient = new HttpClient();
			GetMethod getMethod = new GetMethod("https://oapi.dingtalk.com/department/list?access_token="+accesstoken+"");
			int stats = httpClient.executeMethod(getMethod);
			if(stats == HttpStatus.SC_OK){
				String result = IOUtils.toString(getMethod.getResponseBodyAsStream(),"UTF-8");
				JSONObject json = JSONObject.parseObject(result);
				if(Integer.parseInt(json.get("errcode").toString()) == 0){
					return json.getString("department");
				}
			}
		} catch (HttpException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 获取部门下的员工
	 * @param accesstoken
	 * @return
	 */
	public static String getUserByDepartment(String accesstoken,String dept_id){
		try {
			HttpClient httpClient = new HttpClient();
			GetMethod getMethod = new GetMethod("https://oapi.dingtalk.com/user/list?access_token="+accesstoken+"&department_id="+dept_id);
			int stats = httpClient.executeMethod(getMethod);
			if(stats == HttpStatus.SC_OK){
				String result = IOUtils.toString(getMethod.getResponseBodyAsStream(),"UTF-8");
				JSONObject json = JSONObject.parseObject(result);
				if(Integer.parseInt(json.get("errcode").toString()) == 0){
					return json.getString("userlist");
				}
			}
		} catch (HttpException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
		
	/**
	 * 获取CorpSecret授权范围
	 * @param accesstoken
	 * @return
	 */
	public static String getCorpSecretScope(String accesstoken){
		String result = null;
		try {
			HttpClient httpClient = new HttpClient();
			GetMethod getMethod = new GetMethod("https://oapi.dingtalk.com/auth/scopes?access_token="+accesstoken);
			int stats = httpClient.executeMethod(getMethod);
			if(stats == HttpStatus.SC_OK){
				result = IOUtils.toString(getMethod.getResponseBodyAsStream(),"UTF-8");
			}
		} catch (HttpException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return result;
	}
	/**
	 * 发起审批
	 * @param map
	 * @param seal_names
	 * @param seal_counts
	 * @param agent_id
	 * @param processCode
	 * @param originatorUserId
	 * @param dept_id
	 * @param approvers
	 * @param ccList
	 * @param accesstoken
	 * @return
	 */
	public static String getProcess_instance_id(Map<String,String> map,String seal_names,String seal_counts,String agent_id,String processCode,
			String originatorUserId,String dept_id,String approvers,String ccList,String accesstoken){
		String process_instance_id = null;
		try {
			DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/processinstance/create");
			OapiProcessinstanceCreateRequest request = new OapiProcessinstanceCreateRequest();
			if(StringUtil.isNotNullOrBlank(agent_id)){
				request.setAgentId(Long.parseLong(agent_id));//企业微应用标识
			}
			if(StringUtil.isNotNullOrBlank(processCode)){
				request.setProcessCode(processCode);//审批流的唯一码
			}
			if(StringUtil.isNotNullOrBlank(originatorUserId)){
				request.setOriginatorUserId(originatorUserId);//审批实例发起人的userid
			}
			if(StringUtil.isNotNullOrBlank(dept_id)){
				request.setDeptId(Long.parseLong(dept_id));//发起人所在的部门
			}
			if(StringUtil.isNotNullOrBlank(approvers)){
				request.setApprovers(approvers);//送给谁审批
			}
			if(StringUtil.isNotNullOrBlank(ccList)){
				request.setCcList(ccList);//抄送给谁的id
				request.setCcPosition("START");//抄送时间
			}
			List<FormComponentValueVo> formComponentValues = new ArrayList<FormComponentValueVo>();
			
			//循环单项的表单内容
			for (Map.Entry<String, String> entry : map.entrySet()) { 
				  //System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
				FormComponentValueVo vo = new FormComponentValueVo();
				vo.setName(entry.getKey());
				if(StringUtil.isNotNullOrBlank(entry.getValue())){
					vo.setValue(entry.getValue());
				}else{
					vo.setValue("");
				}
				
				formComponentValues.add(vo);
			}
			//明细:
			String[] seal_names_ = seal_names.split(",");
			String[] seal_counts_ = seal_counts.split(",");
			if(seal_names_.length==1){
				FormComponentValueVo detail1 = new FormComponentValueVo();
				detail1.setName("印章名称");
				detail1.setValue(seal_names_[0]);
				FormComponentValueVo detail2 = new FormComponentValueVo();
				detail2.setName("盖章次数");
				detail2.setValue(seal_counts_[0]);
				FormComponentValueVo obj = new FormComponentValueVo();
				obj.setName("印章明细");
				obj.setValue(JSON.toJSONString(Arrays.asList(Arrays.asList(detail1, detail2))));
				formComponentValues.add(obj);
			}else if(seal_names_.length==2){
				FormComponentValueVo detail11 = new FormComponentValueVo();
				detail11.setName("印章名称");
				detail11.setValue(seal_names_[0]);
				FormComponentValueVo detail12 = new FormComponentValueVo();
				detail12.setName("盖章次数");
				detail12.setValue(seal_counts_[0]);
				
				FormComponentValueVo detail21 = new FormComponentValueVo();
				detail21.setName("印章名称");
				detail21.setValue(seal_names_[1]);
				FormComponentValueVo detail22 = new FormComponentValueVo();
				detail22.setName("盖章次数");
				detail22.setValue(seal_counts_[1]);
				FormComponentValueVo obj = new FormComponentValueVo();
				obj.setName("印章明细");
				obj.setValue(JSON.toJSONString(Arrays.asList(Arrays.asList(detail11, detail12),Arrays.asList(detail11, detail12))));
				formComponentValues.add(obj);
			}else if(seal_names_.length==3){
				FormComponentValueVo detail11 = new FormComponentValueVo();
				detail11.setName("印章名称");
				detail11.setValue(seal_names_[0]);
				FormComponentValueVo detail12 = new FormComponentValueVo();
				detail12.setName("盖章次数");
				detail12.setValue(seal_counts_[0]);
				
				FormComponentValueVo detail21 = new FormComponentValueVo();
				detail21.setName("印章名称");
				detail21.setValue(seal_names_[1]);
				FormComponentValueVo detail22 = new FormComponentValueVo();
				detail22.setName("盖章次数");
				detail22.setValue(seal_counts_[1]);
				
				FormComponentValueVo detail31 = new FormComponentValueVo();
				detail31.setName("印章名称");
				detail31.setValue(seal_names_[2]);
				FormComponentValueVo detail32 = new FormComponentValueVo();
				detail32.setName("盖章次数");
				detail32.setValue(seal_counts_[2]);
				FormComponentValueVo obj = new FormComponentValueVo();
				obj.setName("印章明细");
				obj.setValue(JSON.toJSONString(Arrays.asList(Arrays.asList(detail11, detail12),Arrays.asList(detail21, detail22),Arrays.asList(detail31, detail32))));
				formComponentValues.add(obj);
			}
			request.setFormComponentValues(formComponentValues);
			OapiProcessinstanceCreateResponse response = client.execute(request,accesstoken);
			String body = response.getBody();
			process_instance_id  =  response.getProcessInstanceId();
		} catch (ApiException e) {
			e.printStackTrace();
		}
		return process_instance_id;
	}
	/**
	 * 根据审批实例id 获取审批实例(此处采用钉钉的sdk方式获取)
	 * @param accesstoken
	 * @param process_instance_id
	 * @return
	 */
	public static ProcessInstanceTopVo getProcess_instance(String accesstoken,String process_instance_id){
		ProcessInstanceTopVo  processInstanceTopVo = null;
		DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/processinstance/get");
		OapiProcessinstanceGetRequest request = new OapiProcessinstanceGetRequest();
		request.setProcessInstanceId(process_instance_id);
		try {
			OapiProcessinstanceGetResponse response = client.execute(request,accesstoken);
			if(response.getErrcode()==0){//请求成功
				 processInstanceTopVo = response.getProcessInstance();
			}
		} catch (ApiException e) {
			e.printStackTrace();
		}
		return processInstanceTopVo;
	}
	//根据实例id 获取实例
	public static void main(String[] args) {
		String accesstoken = DingTalkUtils.getAccessToken_new("ding9doc7pnuxjwpvpw7","XwEoy0NQSCZWRmR8GfwsBoqg0_1nVnRsZy7GWgROsQhaFnnvixaZMj_5bzosLVQa");
		getProcess_instance(accesstoken, "770d9292-4d75-442e-841c-6760d630557b");
	}
	
	//发起审批
//	public static void main(String[] args) {
//		Map<String,String> map =  new  HashMap<String,String>();
//		map.put("文件名称", "使用财务章");
//		map.put("文件编码", StringUtil.getBillNumberByTime());
//		map.put("文件类型", "合同类");
//		map.put("文件份数", "5");
//		map.put("合同金额", "5000");
//		map.put("往来单位", "上海建业信息科技股份有限公司");
//		map.put("是否外带","否" );
//		map.put("预计归还时间", "234");
//		map.put("申请事由", "申请使用");
//		map.put("是否远程盖章", "否");
//		map.put("盖章确认人", "234");
//		map.put("所属部门", "测试部");
//		map.put("申请人","张三");
//		map.put("申请时间", "2019-03-18");
//		map.put("单据状态", "审批中");
//		String seal_names ="财务章,法人章,合同章";
//		String seal_counts ="10,20,30";
//		String agent_id = "";
//		String processCode = "PROC-5FYJXW8W-6IU3LLYP3XMZ18HW3OYA3-0DJULDTJ-L";
//		String originatorUserId = "07320147141201617";//发起人
//		String dept_id = "56176621";//发起人部门
//		String approvers = "1715464811691399";//审批人
//		String ccList = "48291940761009";
//		String accesstoken = DingTalkUtils.getAccessToken_new("ding9doc7pnuxjwpvpw7","XwEoy0NQSCZWRmR8GfwsBoqg0_1nVnRsZy7GWgROsQhaFnnvixaZMj_5bzosLVQa");
//		String  processInstanceId = getProcess_instance_id(map, seal_names, seal_counts, agent_id, processCode, originatorUserId, dept_id, approvers, ccList, accesstoken);
//		DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/processinstance/get");
//		OapiProcessinstanceGetRequest request = new OapiProcessinstanceGetRequest();
//		request.setProcessInstanceId(processInstanceId);
//		try {
//			OapiProcessinstanceGetResponse response = client.execute(request,accesstoken);
//			ProcessInstanceTopVo ss =response.getProcessInstance();
//			ss.getFormComponentValues();
//		} catch (ApiException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
//	}
	/**
     * 注册事件回调接口
     * @param accesstoken 企业的accesstoken
     * @param callBackTag  需要监听的事件类型,共有20种(Array[String])
     * @param token      加解密需要用到的token,ISV(服务提供商)推荐使用注册套件时填写的token,普通企业可以随机填写
     * @param aesKey      数据加密密钥。用于回调数据的加密,长度固定为43个字符,从a-z, A-Z, 0-9共62个字符中选取,您可以随机生成,ISV(服务提供商)推荐使用注册套件时填写的EncodingAESKey
     * @param callBackUrl      接收事件回调的url
     * @return
     * @throws ApiException
     */
    public static JSONObject registerCallBack(String accesstoken,List<String> callBackTag,String token,String aesKey,String callBackUrl) throws ApiException{
        String url = Constants.REGISTER_CALL_BACK.replace("ACCESS_TOKEN", accesstoken);
        JSONObject jsonReq = new JSONObject();
        jsonReq.put("call_back_tag", callBackTag);
        jsonReq.put("token", token);
        jsonReq.put("aes_key", aesKey);
        jsonReq.put("url", callBackUrl);
        System.out.println(jsonReq.toString());
        JSONObject jsonObject = HttpRequest.doPostStr(url, jsonReq.toString());
        return jsonObject;
    }
    
    /**
     * 查询事件回调接口
     * @param accesstoken  企业的accesstoken
     * @return
     */
    public static JSONObject getCallBack(String accesstoken){
        String url = Constants.GET_CALL_BACK.replace("ACCESS_TOKEN", accesstoken);
        JSONObject jsonObject = HttpRequest.doGetStr(url);
        return jsonObject;
    }
    
    /**
     * 更新事件回调接口
     * @param accesstoken 企业的accesstoken
     * @param callBackTag  需要监听的事件类型,共有20种(Array[String])
     * @param token      加解密需要用到的token,ISV(服务提供商)推荐使用注册套件时填写的token,普通企业可以随机填写
     * @param aesKey      数据加密密钥。用于回调数据的加密,长度固定为43个字符,从a-z, A-Z, 0-9共62个字符中选取,您可以随机生成,ISV(服务提供商)推荐使用注册套件时填写的EncodingAESKey
     * @param callBackUrl      接收事件回调的url
     * @return
     * @throws ApiException
     */
    public static JSONObject updateCallBack(String accesstoken,List<String> callBackTag,String token,String aesKey,String callBackUrl) throws ApiException{
        String url = Constants.UPDATE_CALL_BACK.replace("ACCESS_TOKEN", accesstoken);
        JSONObject jsonReq = new JSONObject();
        jsonReq.put("call_back_tag", callBackTag);
        jsonReq.put("token", token);
        jsonReq.put("aes_key", aesKey);
        jsonReq.put("url", callBackUrl);
        
        JSONObject jsonObject = HttpRequest.doPostStr(url, jsonReq.toString());
        return jsonObject;
    }
    
    /**
     * 删除事件回调接口
     * @param accesstoken  企业的accesstoken
     * @return
     */
    public static JSONObject deleteCallBack(String accesstoken){
        String url = Constants.DELETE_CALL_BACK.replace("ACCESS_TOKEN", accesstoken);
        JSONObject jsonObject = HttpRequest.doGetStr(url);
        return jsonObject;
    }
    /**
     * 获取回调失败的结果
     * @param accesstoken  企业的accesstoken
     * @return
     */
    public static JSONObject getCallBackFailedResult(String accesstoken){
        String url = Constants.GET_CALL_BACK_FAILED_RESULT.replace("ACCESS_TOKEN", accesstoken);
        JSONObject jsonObject = HttpRequest.doGetStr(url);
        return jsonObject;
    }
	
}
5.5
package com.shjysoft.base.util.dingtalk;
import java.nio.charset.Charset;
import java.util.Arrays;
/*
 * PKCS7算法的加密填充
 */
public class PKCS7Padding {
    private final static Charset CHARSET    = Charset.forName("utf-8");
    private final static int     BLOCK_SIZE = 32;
    /**
     * 填充mode字节
     * @param count
     * @return
     */
    public static byte[] getPaddingBytes(int count) {
        int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
        if (amountToPad == 0) {
            amountToPad = BLOCK_SIZE;
        }
        char padChr = chr(amountToPad);
        String tmp = new String();
        for (int index = 0; index < amountToPad; index++) {
            tmp += padChr;
        }
        return tmp.getBytes(CHARSET);
    }
    /**
     * 移除mode填充字节
     * @param decrypted
     * @return
     */
    public static byte[] removePaddingBytes(byte[] decrypted) {
        int pad = (int) decrypted[decrypted.length - 1];
        if (pad < 1 || pad > BLOCK_SIZE) {
            pad = 0;
        }
        return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
    }
    private static char chr(int a) {
        byte target = (byte) (a & 0xFF);
        return (char) target;
    }
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
标签:auth erro 加密 cal mapping you eof input 远程
原文地址:https://www.cnblogs.com/ZhouQi-0921/p/10615145.html