OA集成釘釘開發——第四篇——微應用開發

前一篇咱們說到從釘釘中登陸微應用,由於咱們是從微應用的中的入口進入的,那麼咱們項目中就不須要設置登陸,註冊,咱們經過釘釘就能夠拿到你的惟一標識,這個標識在咱們的組織機構中,也就是數據庫中提早就會從阿里雲中down下來,這樣就是 釘釘的免登錄了!javascript

相關代碼實現: 前端

個人web項目使用java,springmvc_mybatis實現。java

我在釘釘的微應用中設置的入口的URL:項目名+/order/change_order_apply_page.doweb

controller中代碼:spring

/**
	 * 項目變動申請界面
	 * @return
	 */
	@RequestMapping("/change_order_apply_page.do")
	public ModelAndView change_order_apply_page(HttpServletRequest request){		
		ModelAndView mav = new ModelAndView();		
	 	String config= AuthHelper.getConfig(request);
	 	System.out.println("config:"+config);
	 	request.setAttribute("config", config);
		mav.setViewName("order/change_order_apply");		
		return mav;
	}

其中 String config= AuthHelper.getConfig(request);數據庫

AuthHelper是手動封裝的工具類:json

import com.alibaba.fastjson.JSONObject;
import com.ddSdk.base.Env;
import com.ddSdk.base.OApiException;
import com.ddSdk.base.OApiResultException;
import com.ddSdk.utils.FileUtils;
import com.ddSdk.utils.HttpHelper;
import com.dingtalk.open.client.ServiceFactory;
import com.dingtalk.open.client.api.model.corp.JsapiTicket;
import com.dingtalk.open.client.api.service.corp.CorpConnectionService;
import com.dingtalk.open.client.api.service.corp.JsapiService;
import com.dingtalk.open.client.common.SdkInitException;
import com.dingtalk.open.client.common.ServiceException;
import com.dingtalk.open.client.common.ServiceNotExistException;


import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Formatter;
import java.util.Timer;

public class AuthHelper {

	// public static String jsapiTicket = null;
	// public static String accessToken = null;
	public static Timer timer = null;
	// 調整到1小時50分鐘
	public static final long cacheTime = 7200;
	public static long currentTime = 0 + cacheTime + 1;
	public static long lastTime = 0;
	public static SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	/*
	 * 在此方法中,爲了不頻繁獲取access_token,
	 * 在距離上一次獲取access_token時間在兩個小時以內的狀況,
	 * 將直接從持久化存儲中讀取access_token
	 * 
	 * 由於access_token和jsapi_ticket的過時時間都是7200秒
	 * 因此在獲取access_token的同時也去獲取了jsapi_ticket
	 * 注:jsapi_ticket是在前端頁面JSAPI作權限驗證配置的時候須要使用的
	 * 具體信息請查看開發者文檔--權限驗證配置
	 */
	public static String getAccessToken() throws OApiException {
		long curTime = System.currentTimeMillis();
		JSONObject accessTokenValue = (JSONObject) FileUtils.getValue("accesstoken", Env.CORP_ID);
		String accToken = "";
		String jsTicket = "";
		JSONObject jsontemp = new JSONObject();
		if (accessTokenValue == null || curTime - accessTokenValue.getLong("begin_time") >= cacheTime) {
			try
			{
			ServiceFactory serviceFactory = ServiceFactory.getInstance();
	        CorpConnectionService corpConnectionService = serviceFactory.getOpenService(CorpConnectionService.class);
	        accToken = corpConnectionService.getCorpToken(Env.CORP_ID, Env.CORP_SECRET);
			// save accessToken
			JSONObject jsonAccess = new JSONObject();
			jsontemp.clear();
			jsontemp.put("access_token", accToken);
			jsontemp.put("begin_time", curTime);
			jsonAccess.put(Env.CORP_ID, jsontemp);
			FileUtils.write2File(jsonAccess, "accesstoken");
			
			if(accToken.length() > 0){
				
				JsapiService jsapiService = serviceFactory.getOpenService(JsapiService.class);

				JsapiTicket JsapiTicket = jsapiService.getJsapiTicket(accToken, "jsapi");
				jsTicket = JsapiTicket.getTicket();
				JSONObject jsonTicket = new JSONObject();
				jsontemp.clear();
				jsontemp.put("ticket", jsTicket);
				jsontemp.put("begin_time", curTime);
				jsonTicket.put(Env.CORP_ID, jsontemp);
				FileUtils.write2File(jsonTicket, "jsticket");
			}
		} catch (SdkInitException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ServiceException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ServiceNotExistException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		} else {
			return accessTokenValue.getString("access_token");
		}

		return accToken;
	}

	// 正常的狀況下,jsapi_ticket的有效期爲7200秒,因此開發者須要在某個地方設計一個定時器,按期去更新jsapi_ticket
	public static String getJsapiTicket(String accessToken) throws OApiException {
		JSONObject jsTicketValue = (JSONObject) FileUtils.getValue("jsticket", Env.CORP_ID);
		long curTime = System.currentTimeMillis();
		String jsTicket = "";

		 if (jsTicketValue == null || curTime -
		 jsTicketValue.getLong("begin_time") >= cacheTime) {
			ServiceFactory serviceFactory;
			try {
				serviceFactory = ServiceFactory.getInstance();
				JsapiService jsapiService = serviceFactory.getOpenService(JsapiService.class);

				JsapiTicket JsapiTicket = jsapiService.getJsapiTicket(accessToken, "jsapi");
				jsTicket = JsapiTicket.getTicket();

				JSONObject jsonTicket = new JSONObject();
				JSONObject jsontemp = new JSONObject();
				jsontemp.clear();
				jsontemp.put("ticket", jsTicket);
				jsontemp.put("begin_time", curTime);
				jsonTicket.put(Env.CORP_ID, jsontemp);
				FileUtils.write2File(jsonTicket, "jsticket");
			} catch (SdkInitException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ServiceException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ServiceNotExistException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return jsTicket;
		 } else {
			 return jsTicketValue.getString("ticket");
		 }
	}

	public static String sign(String ticket, String nonceStr, long timeStamp, String url) throws OApiException {
		String plain = "jsapi_ticket=" + ticket + "&noncestr=" + nonceStr + "&timestamp=" + String.valueOf(timeStamp)
				+ "&url=" + url;
		try {
			MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
			sha1.reset();
			sha1.update(plain.getBytes("UTF-8"));
			return bytesToHex(sha1.digest());
		} catch (NoSuchAlgorithmException e) {
			throw new OApiResultException(e.getMessage());
		} catch (UnsupportedEncodingException e) {
			throw new OApiResultException(e.getMessage());
		}
	}

	private static String bytesToHex(byte[] hash) {
		Formatter formatter = new Formatter();
		for (byte b : hash) {
			formatter.format("%02x", b);
		}
		String result = formatter.toString();
		formatter.close();
		return result;
	}

	public static String getConfig(HttpServletRequest request) {
		String urlString = request.getRequestURL().toString();
		String queryString = request.getQueryString();

		String queryStringEncode = null;
		String url;
		if (queryString != null) {
			queryStringEncode = URLDecoder.decode(queryString);
			url = urlString + "?" + queryStringEncode;
		} else {
			url = urlString;
		}
		
		String nonceStr = "abcdefg";
		long timeStamp = System.currentTimeMillis() / 1000;
		String signedUrl = url;
		String accessToken = null;
		String ticket = null;
		String signature = null;
		String agentid = null;

		try {
			accessToken = AuthHelper.getAccessToken();
	       
			ticket = AuthHelper.getJsapiTicket(accessToken);
			signature = AuthHelper.sign(ticket, nonceStr, timeStamp, signedUrl);
			agentid = "";
			
		} catch (OApiException  e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		String configValue = "{jsticket:'" + ticket + "',signature:'" + signature + "',nonceStr:'" + nonceStr + "',timeStamp:'"
		+ timeStamp + "',corpId:'" + Env.CORP_ID + "',agentid:'" + agentid+  "'}";
		System.out.println(configValue);
		return configValue;
	}

	public static String getSsoToken() throws OApiException {
		String url = "https://oapi.dingtalk.com/sso/gettoken?corpid=" + Env.CORP_ID + "&corpsecret=" + Env.SSO_Secret;
		JSONObject response = HttpHelper.httpGet(url);
		String ssoToken;
		if (response.containsKey("access_token")) {
			ssoToken = response.getString("access_token");
		} else {
			throw new OApiResultException("Sso_token");
		}
		return ssoToken;

	}

}

相關釘釘數據在java 後臺中進行http請求拿到api

返回到個人jsp界面中,在咱們JSP界面中我引入了釘釘的JS服務器

<script type="text/javascript" src="http://g.alicdn.com/ilw/ding/0.7.3/scripts/dingtalk.js"></script>

界面初始化時 我會加載一段JS:其中angentID 是釘釘分給你微應用的ID ,重複貌似也沒事。session

/*權限驗證配置所需的信息 */
    var config =<%=request.getAttribute("config")%>;
    //當前用戶
    var nowUser=null;
    //用戶受權碼
    var code=null;
    /* $(document).ready(function(){
   	 $.alert(config);
    }); */
     //配置釘釘jsapi
    dd.config({
        agentId : "38433641", 
        corpId : config.corpId,
        timeStamp : config.timeStamp,
        nonceStr : config.nonceStr,
        signature : config.signature,
        jsApiList : [ 'runtime.info', 'biz.contact.choose',
            'device.notification.confirm', 'device.notification.alert',
            'device.notification.prompt', 'biz.ding.post',
            'biz.util.openLink' ]
    });

   
    dd.ready(function() {
 
        dd.runtime.permission.requestAuthCode({
            corpId : config.corpId, //請求 code
            onSuccess : function(info) {
               //存儲用戶信息
               
               $.post("<%=path%>/order/login.do",{"code":info.code}); //向後臺傳入code
               
            },
            onFail : function(err) {
                alert('fail: ' + JSON.stringify(err));
            }
        });
    });

 dd.ready中我會向後臺傳入code碼:

/**
	 * 項目變動申請界面
	 * @return
	 */
	@RequestMapping("/login.do")
	public void login(HttpServletRequest request,String code){		
		String staffUserId=DDUtil.getUserID(code);
		System.out.println("staffUserId:"+staffUserId);
		//從數據庫中得到該員工的全部信息
		StaffInfo staffInfo= iStaffInfoService.selectStaffByID(staffUserId);
		//在當前回話session中存儲相關信息
		request.getSession().setAttribute(GlobalConstant.user_staffId, staffInfo.getStaffId());
		request.getSession().setAttribute(GlobalConstant.user_department, staffInfo.getDepartment());
		request.getSession().setAttribute(GlobalConstant.user_staff_user_id,staffInfo.getStaffUserId());
		request.getSession().setAttribute(GlobalConstant.user_name,staffInfo.getName());		
		
	}

其中DDUtil,GlobalConstant是手動封裝的類;

DDUtil.getUserID(code);這句代碼是經過code向釘釘服務器請求該用戶的staffuserid 也就咱們所說的用戶的惟一標識;再從咱們數據庫獲取用戶的相關信息,存入session中。

這是就是個人免登錄流程!

相關文章
相關標籤/搜索