前一篇咱們說到從釘釘中登陸微應用,由於咱們是從微應用的中的入口進入的,那麼咱們項目中就不須要設置登陸,註冊,咱們經過釘釘就能夠拿到你的惟一標識,這個標識在咱們的組織機構中,也就是數據庫中提早就會從阿里雲中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 + "×tamp=" + 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中。
這是就是個人免登錄流程!