OA集成钉钉开发——第四篇——微应用开发

前一篇我们说到从钉钉中登录微应用,因为我们是从微应用的中的入口进入的,那么我们项目中就不需要设置登录,注册,我们通过钉钉就可以拿到你的唯一标识,这个标识在我们的组织机构中,也就是数据库中提前就会从阿里云中down下来,这样就是 钉钉的免登陆了!

相关代码实现: 

我的web项目使用java,springmvc_mybatis实现。

我在钉钉的微应用中设置的入口的URL:项目名+/order/change_order_apply_page.do

controller中代码:

/**
	 * 项目变更申请界面
	 * @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是手动封装的工具类:


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请求拿到

返回到我的jsp界面中,在我们JSP界面中我引入了钉钉的JS

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

界面初始化时 我会加载一段JS:其中angentID 是钉钉分给你微应用的ID ,重复貌似也没事。

 /*权限验证配置所需的信息 */
    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中。

这是就是我的免登陆流程!

转载于:https://my.oschina.net/xiaoshoubingliang/blog/809871

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值