免登流程 - 钉钉 API (apifox.cn)

免登”是指用户进入应用后,无需输入钉钉用户名和密码,应用程序可自动获取当前用户身份,进而登录系统的流程。

0cb36c1ee17cf421f1f74e1c176ecc8.png

实现步骤

1. 获取授权码

获取微应用免登授权码 - 钉钉开放平台 (dingtalk.com)获取微应用免登授权码 - 钉钉开放平台 (dingtalk.com)

dd.ready(function() {
    dd.runtime.permission.requestAuthCode({
        corpId: "ding12345xxx", // 企业id
        onSuccess: function (info) {
                  code = info.code // 通过该免登授权码可以获取用户身份
        }});
});

2. 通过免登授权码换取用户身份

这里根据获取access_token不同将分为企业内部应用和第三方应用

  • 企业内部应用获取access_token

首先到开发者平台获取appkey和appSecret。

// This file is auto-generated, don't edit it
import Util from '@alicloud/tea-util';
import dingtalkoauth2_1_0, * as $dingtalkoauth2_1_0 from '@alicloud/dingtalk/oauth2_1_0';
import OpenApi, * as $OpenApi from '@alicloud/openapi-client';
import * as $tea from '@alicloud/tea-typescript';


export default class Client {

  /**
   * 使用 Token 初始化账号Client
   * @return Client
   * @throws Exception
   */
  static createClient(): dingtalkoauth2_1_0 {
    let config = new $OpenApi.Config({ });
    config.protocol = "https";
    config.regionId = "central";
    return new dingtalkoauth2_1_0(config);
  }

  static async main(args: string[]): Promise<void> {
    let client = Client.createClient();
    let getAccessTokenRequest = new $dingtalkoauth2_1_0.GetAccessTokenRequest({
      appKey: "dingeqqpkv3xxxxxx",
      appSecret: "GT-lsu-taDAxxxsTsxxxx",
    });
    try {
      await client.getAccessToken(getAccessTokenRequest);
    } catch (err) {
      if (!Util.empty(err.code) && !Util.empty(err.message)) {
        // err 中含有 code 和 message 属性,可帮助开发定位问题
      }

    }    
  }

}

Client.main(process.argv.slice(2));

返回示例

HTTP/1.1 200 OK
Content-Type:application/json

{
  "accessToken" : "fw8ef8we8f76e6f7s8dxxxx",
  "expireIn" : 7200
}
  • 第三方应用获取access_token

第三方企业应用获取access_token需要以下参数,具体参考获取第三方应用授权企业的accessToken - 钉钉开放平台 (dingtalk.com)

POST /v1.0/oauth2/corpAccessToken HTTP/1.1
Host:api.dingtalk.com
Content-Type:application/json

{
  "suiteKey" : "String",
  "suiteSecret" : "String",
  "authCorpId" : "String",
  "suiteTicket" : "String"
}
/**
 * 
 *  第三方企业应用免登
 * @author openapi@dingtalk
 * 2020-11-3
 */
@RestController
public class LoginController {

 /**
   * 欢迎页面,通过 /welcome 访问,判断后端服务是否启动
     *
     * @return 字符串 welcome
     */
    @GetMapping("/welcome")
    public String welcome() {
        return "welcome";
    }
 
 /**
  * 
  * @param requestAuthCode
  * @return
  * ServiceResult
  * 2020-11-3
  */
 @RequestMapping(value = "/login", method = RequestMethod.GET)
 public ServiceResult<Map<String, Object>> login (@RequestParam("code") String requestAuthCode) {
  
  // 获取access_token,注意正式代码要有异常流处理
  String access_token= AccessTokenUtil.getToken();
  // 获取用户信息
  DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/user/getuserinfo");
  OapiUserGetuserinfoRequest request = new OapiUserGetuserinfoRequest();
  request.setCode(requestAuthCode);
  request.setHttpMethod("GET");
  OapiUserGetuserinfoResponse response;
  try {
   response = client.execute(request, access_token);
  } catch (ApiException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
   return null;
  }
  // 查询得到当前用户的userId    
  // 获得到userId之后应用应该处理应用自身的登录会话管理(session),避免后续的业务交互(前端到应用服务端)每次都要重新获取用户身份,提升用户体验
  String userId = response.getUserid();
  Map<String, Object> returnMap = new HashMap<String,Object>();
  returnMap.put("userId", userId);
  return ServiceResult.success(returnMap);
 }
}

3. 获取userId

通过免登码获取用户信息

请求地址https://oapi.dingtalk.com/topapi/v2/user/getuserinfo

请求方式:POST

Query参数:access_token

Body参数:code

返回示例

{
        "errcode": 0, 
        "result": {
                "associated_unionid": "N2o5U3axxxx", 
                "unionid": "gliiW0piiii02zBUjUxxxx", 
                "device_id": "12drtfxxxxx", 
                "sys_level": 1, 
                "name": "张xx", 
                "sys": true, 
                "userid": "userid123"
        }, 
        "errmsg": "ok"
}