钉钉企业内部应用授权免登+鉴权

本文详细介绍了在钉钉中创建企业内部应用的步骤,包括获取应用凭证、授权免登流程(前端获取授权码、后端换取access_token、获取用户信息及详情)以及鉴权流程(获取签名并进行JSAPI鉴权)。通过这些步骤,可以实现用户免登授权和鉴权调用受保护的API。

一、创建应用

在钉钉管理后台-应用开发-企业内部开发-创建应用(我们这边创建的是H5微应用)
创建好了之后,会拿到应用凭证:AgentId,AppKey,AppSecret
这三个值在开发中会用到

二、授权免登流程

1、前端–获取微应用免登授权码
具体参考API:获取授权码API

2、后端–授权免登
(1)获取access_token
AppKeyAppSecret换取access_token

 public static String getAccessToken(String appKey, String appSecret) {
        DefaultDingTalkClient client = new        
        DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
        OapiGettokenRequest request = new OapiGettokenRequest();
       request.setAppkey(appKey);
       request.setAppsecret(appSecret);
       request.setHttpMethod("GET");
       OapiGettokenResponse response = null;
       try {
            response = client.execute(request);
        } catch (ApiException e) {
            log.error("dingUtil getAppToken error", e);
            throw new BizException("获取token失败");
        }
       if (!response.isSuccess()) {
           log.error("dingUtil getAccessTokenAfresh failed, errorCode={}, errorMsg={}", response.getErrcode(), response.getErrmsg());
            return null;
        }
        return response.getAccessToken();
    }

说明:正常情况下access_token有效期为7200秒,有效期内重复获取返回相同结果,并自动续期。所以不需要每次有用户授权登录,都要去获取一次。

@Component
public class AccessTokenCache {
    private static Logger logger = LoggerFactory.getLogger(AccessTokenCache.class);

    private static AccessTokenCache cache = new AccessTokenCache();
    private String appToken = null;

    private AccessTokenCache() {
    }

    public static AccessTokenCache getInstance() {
        return cache;
    }

    public void init() {
        while (true) {
            try {
                appToken = DingDingUtil.getAccessToken("appKey", "appSecret");
                if (null != appToken) {
                    logger.info("获取token成功, appToken:{}", appToken);
                    // 休眠 1 小时
                    Thread.sleep(3600 * 1000);
                } else {
                    // 如果access_token为null,60秒后再获取
                    Thread.sleep(60 * 1000);
                }
            } catch (InterruptedException e) {
                try {
                    Thread.sleep(60 * 1000);
                } catch (InterruptedException e1) {
                    logger.error("{}", e1);
                }
                logger.error("{}", e);
            }
        }
    }

    public String getAppToken() {
        return appToken;
    }
}

在启动类加上:
AccessTokenCache accessTokenCache = new AccessTokenCache();
AccessTokenCache.getInstance().init();

每个小时获取一次access_token 需要的时候通过这个方法来获取就好了,
在授权,鉴权,消息通知等流程中都是要用到的。

参考API:获取access_tokenAPI
(2)获取用户userid
通过免登授权码access_token获取用户的userid。

 DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/user/getuserinfo");
        OapiUserGetuserinfoRequest request = new OapiUserGetuserinfoRequest();
        request.setCode(code);
        request.setHttpMethod("GET");
        OapiUserGetuserinfoResponse response = client.execute(request, accessToken);
        if (!response.isSuccess()) {
            log.error("dingUtil getUserInfo failed, errorCode={}, errorMsg={}", response.getErrcode(), response.getErrmsg());
            return null;
        }
       return response;

返回值:

{
    "userid": "****",//	员工在当前企业内的唯一标识,也称staffId
    "is_sys": true,//是否是管理员,true:是,false:不是
    "sys_level": 1,//级别。1是主管理员,2是子管理员,100是老板,0是其他(如普通员工)
    "errcode": 0//错误码
    "errmsg": "ok",//错误描述
}

获取用户信息参考API:获取用户信息
(3)获取用户详情
如果要获取当前用户更多的详情,可以使用这个api去获取更多用户信息
用上一步获得的useridaccess_token获取用户详情信息

  DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/user/get");
        OapiUserGetRequest request = new OapiUserGetRequest();
        request.setUserid(userId);
        request.setHttpMethod("GET");
        OapiUserGetResponse response = client.execute(request, accessToken);
        if (!response.isSuccess()) {
            log.error("dingUtil getUser failed, errorCode={}, errorMsg={}", response.getErrcode(), response.getErrmsg());
            return null;
        }

获取用户详情参考API:获取用户详情述
(4)将当前用户信息写进缓存,并生成token给前端以便验证登录用户,这样就拿到了当前用户信息完成了授权免登。

三、鉴权流程

在开发过程,前端调用某些api是需要鉴权才可以调用的。所以要走鉴权流程把需要鉴权的api走鉴权流程。

1、后端–获取签名
(1)获取access_token(同上)
(2)获取jsapi_ticket
用access_token换取ticket
注意:
a、当jsapi_ticket未过期时,再次调用get_jsapi_ticket会获取到一个全新的jsapi_ticket(和旧的jsapi_ticket值不同),这个全新的jsapi_ticket的过期时间是2小时。
b、jsapi_ticket是一个appKey对应一个,所以在使用的时候需要将jsapi_ticket以appKey为维度进行缓存下来(设置缓存过期时间2小时),并不需要每次都通过接口拉取。

 DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/get_jsapi_ticket");
        OapiGetJsapiTicketRequest req = new OapiGetJsapiTicketRequest();
        req.setTopHttpMethod("GET");
        OapiGetJsapiTicketResponse response = client.execute(req, accessToken);

        if (!response.isSuccess()) {
            log.error("dingUtil getTicket failed, errorCode={}, errorMsg={}", response.getErrcode(), response.getErrmsg());
            return null;
        }
        return response.getTicket();

(3)生成签名,并将签名参数返回给前端
生成签名的参数:
String ticket 上一步获取的票据
String nonceStr 随机字符串
long timeStamp 当前时间戳
String url 当前网页的URL,不包含#及其后面部分

  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 byteToHex(sha1.digest());
        } catch (NoSuchAlgorithmException e) {
            log.error("dingUtil sign error", e);
            throw new BizException("签名错误");
        } catch (UnsupportedEncodingException e) {
            log.error("dingUtil sign error", e);
            throw new BizException("签名错误");
        }
        
  /**
     * 字节数组转化成十六进制字符串
     *
     * @param hash
     * @return
     */
    private static String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

返回前端的参数:nonceStr,timeStamp,signature(签名结果),corpId(企业ID),agentId(创建应用时获得的)

2、前端–JSAPI鉴权
拿着后端返回的签名参数进行dd.config鉴权
注意:这里鉴权,钉钉那边是做了灰度的,如果出现偶发错误情况,那一定是代码有问题。
参考博文:钉钉鉴权报错
至此,完成鉴权。整个鉴权流程API:鉴权流程API

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值