当前位置: 首页 > article >正文

钉钉内集成第三方免密登录(Vue+.Net)

需要实现的效果就是在钉钉内点击应用能跳转到第三方网站并且免密登录

1.登录钉钉PC端管理后台

2.通过管理后台进去开发者后台 

3.应用开发 创建H5微应用

4.应用创建成功后直接点权限管理全部授权

5.设置H5登录地址 

6. 应用管理发布

 至此需要配置的步骤全部已完成,需要记住已下三个参数后续开发时候会用到

Client ID、Client Secret、CorpId

上代码

前端用的VUE

// 1.需要下载钉钉包
npm install dingtalk-jsapi --save

// 2.引入包
import * as dd from 'dingtalk-jsapi';

// 3.编写相关登录逻辑
async function initDD() {
  //判断是不是通过钉钉内打开的应用
  if (dd.env.platform !== "notInDingTalk") {
    //进行钉钉登录操作
    dd.ready(() => {
      //获取登录一次性凭证
      dd.runtime.permission.requestAuthCode({
        corpId: '换成自己对应的参数以上有说明', // 企业id
      }).then(ddRes => {
        //凭证获取成功后调用后端登录接口完成相关自动登录逻辑
        loginDingTalk(ddRes.code).then(res => {
          //记录应用登录凭证到本地
          userStore.updateToken(res.data.data.token);
          nextTick(() => {
            //跳转到主页
            router.push(PageEnum.BASE_HOME);
          });
        });
      }).catch(err => {
        alert(JSON.stringify(err));
      });
    });
  }
}

 后端.NET

WebApi 接口

    /// <summary>
    /// 用户登录.
    /// </summary>
    /// <returns></returns>
    [HttpPost("Login/DingTalk/{code}")]
    [AllowAnonymous]
    [IgnoreLog]
    public async Task<dynamic> LoginDingTalk(string code)
    {
        DingUtil ding = new DingUtil();
        //得到企业访问token
        string accessToken = ding.GetDingToken("Client ID对应自己应用", "Client Secret对应自己应用");
        //得到当前钉钉登录的用户信息
        string strObj = ding.GetUserInfoInApp(code, accessToken);
        
        JObject objData = strObj.ToObject();

        //通过钉钉移动电话获取第三方本地用户信息
        UserEntity userEntity = await _userRepository.GetFirstAsync(x => x.MobilePhone.Equals(objData["Mobile"]));

        if (userEntity == null) throw Oops.Bah("当前应用无账号,请联系管理员");
        
        //获取到用户信息后完成自动登录相关逻辑 并返回第三方应用登录凭证给登录界面进行缓存
        var loginInput = await GetUserInfoByUserAccount(userEntity.Account);
        var result = await Login(loginInput);
        return new { code = 200, data = result };
    }
using DingTalk.Api;
using DingTalk.Api.Request;
using DingTalk.Api.Response;
using Mapster;
using Minio.DataModel.Tracing;
using NetTaste;
using Org.BouncyCastle.Ocsp;
using System.Text.RegularExpressions;
using Tea;
using static DingTalk.Api.Request.OapiRobotSendRequest;
using static DingTalk.Api.Response.OapiV2DepartmentListsubResponse;
using static DingTalk.Api.Response.OapiV2UserListResponse;

namespace DingDing;

/// <summary>
/// 钉钉.
/// </summary>
public class DingUtil
{
    /// <summary>
    /// 访问令牌.
    /// </summary>
    public string token { get; private set; }

    /// <summary>
    /// token有效时间.
    /// </summary>
    public TimeSpan expiresTime { get; private set; }

    /// <summary>
    /// 构造函数.
    /// </summary>
    /// <param name="appKey">企业号ID.</param>
    /// <param name="appSecret">凭证密钥.</param>
    public DingUtil(string appKey, string appSecret)
    {
        token = GetDingToken(appKey, appSecret);
    }

    /// <summary>
    /// 构造函数.
    /// </summary>
    /// <param name="appKey">企业号ID.</param>
    /// <param name="appSecret">凭证密钥.</param>
    public DingUtil()
    {
    }

    /// <summary>
    /// 钉钉token.
    /// </summary>
    /// <param name="appKey">企业号ID.</param>
    /// <param name="appSecret">凭证密钥.</param>
    /// <returns></returns>
    public string GetDingToken(string appKey, string appSecret)
    {
        try
        {
            var tokenurl = "https://oapi.dingtalk.com/gettoken";
            DefaultDingTalkClient client = new DefaultDingTalkClient(tokenurl);
            OapiGettokenRequest req = new OapiGettokenRequest();
            req.SetHttpMethod("GET");
            req.Appkey = appKey;
            req.Appsecret = appSecret;
            OapiGettokenResponse response = client.Execute(req);
            if (response.Errcode == 0)
            {
                // 过期时间
                expiresTime = DateTime.Now.Subtract(DateTime.Now.AddSeconds(response.ExpiresIn));
                return response.AccessToken;
            }
            else
            {
                throw new Exception("获取钉钉Token失败,失败原因:" + response.Errmsg);
            }

        }
        catch (Exception ex)
        {

            return string.Empty;
        }
    }


    public string GetUserInfoInApp(string code, string accessToken)
    {
        var client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/getuserinfo");
        OapiV2UserGetuserinfoRequest req = new OapiV2UserGetuserinfoRequest();
        req.Code = code;
        OapiV2UserGetuserinfoResponse rsp = client.Execute(req, accessToken);
        if (rsp.Errcode == 0)
        {
            // 根据unionid获取userid
            string unionid = rsp.Result.Unionid;
            DefaultDingTalkClient clientDingTalkClient = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/user/getbyunionid");
            OapiUserGetbyunionidRequest reqGetbyunionidRequest = new OapiUserGetbyunionidRequest();
            reqGetbyunionidRequest.Unionid = unionid;
            OapiUserGetbyunionidResponse oapiUserGetbyunionidResponse = clientDingTalkClient.Execute(reqGetbyunionidRequest, accessToken);
            if (oapiUserGetbyunionidResponse.Errcode == 0)
            {
                // 根据userId获取用户信息
                string userid = oapiUserGetbyunionidResponse.Result.Userid;
                var user = GetUserInfoByUserId(userid, accessToken);
                return user;
            }
        }

        return string.Empty;
    }

    /// <summary>
    /// 根据用户UserId取得用户信息.
    /// </summary>
    /// <param name="userId"></param>
    /// <returns></returns>
    private string GetUserInfoByUserId(string userId, string accessToken)
    {
        var client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/get");
        var req = new OapiV2UserGetRequest();
        req.Userid = userId;
        req.Language = "zh_CN";
        var res = client.Execute(req, accessToken);

        if (res.Errcode == 0) return res.Result.ToJsonString(); else throw new Exception(res.ErrMsg);
    }
    #region 用户
}


http://www.kler.cn/a/376620.html

相关文章:

  • 求最大公约数,最小公倍数
  • Android @JvmOverloads
  • js、vue、angular中的函数声明方式及特点
  • ctfshow文件包含web78~81
  • 模拟栈的实现
  • JAVA题目笔记(十一)多态+带有抽象类/接口的JavaBean类
  • 定制化视频生成新模范!零样本主体驱动,精确运动控制!复旦阿里等发布DreamVideo-2
  • 算法笔记day10
  • CentOS下Redis简洁安装(无坑版)
  • LocalDate 类常用方法详解(日期时间类)
  • 图文深入介绍Oracle DB link(三)
  • Python世界:自动化办公Word之批量替换文本生成副本
  • C++ 实现俄罗斯方块游戏
  • 贪心算法习题其二【力扣】【算法学习day.19】
  • Selenium自动化测试框架(附教程+文档)
  • Rust 力扣 - 2134. 最少交换次数来组合所有的 1 II
  • 游戏光照的专业知识解析
  • 网络学习/复习3序列化与反序列化/HTTP/HTTPS
  • 了解SQLExpress数据库
  • 文件系统(IO-进程-线程)
  • shodan-4
  • Milvus - GPU 索引类型及其应用场景
  • Soft TeacherEnd-to-End Semi-Supervised Object Detection with Soft Teacher
  • wireshark抓包查看langchain的ChatOpenAI接口发送和接收的数据
  • P3-2.【结构化程序设计】第二节——知识要点:多分支选择语句
  • 详解ARM64可执行程序的生成过程