网页 H5 微应用接入钉钉自动登录

ℹ️关于云审批
云审批(cloud approve) ,一款专为小微企业打造,支持多租户的在线审批神器。它简化了申请和审批流程,让您随时随地通过手机或电脑完成请款操作。员工一键提交申请,审批者即时响应,方便快捷。同时,云审批提供全面的数据记录与分析,助力企业实现财务管理透明化、智能化,安全高效,让企业的信息数字化管理变得简单轻松!最后,重要的事情说三遍📢:开源、开源、所有代码开源。
👉GITHUB开源地址 👈
👉飞书在线文档👈

概述

钉钉免登(此处专指自建H5微应用,官方文档)是一种便捷的登录机制,当用户已在钉钉客户端(包括PC端和移动端)完成登录后,通过工作台访问我们的网站时,系统能够自动识别并完成用户身份验证,无需重复输入登录信息。该功能广泛应用于微信、飞书、抖音等主流平台,为用户提供无缝的跨平台使用体验。

流程详解

数据表

登录模块设计到两个表:账号表/Account、员工表/Staff。

账号/Account

此表为登录到平台的账户信息,支持传统的账密方式、钉钉免登等方式,并记录与之关联的员工ID

字段名中文名类型必填默认值说明
id编号Int唯一标识
cid企业IDInt关联企业
name账号名称String
pwd密码String加密
type类型String登录类型
sid员工IDInt关联员工
active是否生效Booleanfalse
addOn录入日期Int

登录类型:

  • dingding=钉钉
  • wechat=微信
  • phone=手机号(未来支持手机验证码登录)
  • other=其它(传统密码登录)

员工/Staff

字段名中文名类型必填默认值说明
id编号Int唯一标识
cid企业IDInt关联企业
name员工名称String
phone电话号码String
summary描述String

免登流程

  • 准备阶段
    • 企业管理员登录钉钉开发者后台,创建应用并配置网页功能
    • 获取应用的AppKeyAppSecrect
  • 逻辑实现
    • 新建钉钉登录专用页面(dingding.html)
    • 在页面中获取两个参数cid(企业ID)corpId(钉钉内企业ID)
    • 前端调用钉钉接口获取授权码/CODE
    • 后端拿到上述 CODE 后通过AppKeyAppSecrect获取到用户信息(包含唯一编号 unionid、姓名 name 等)
    • 构建唯一账户名:D_{unionid}_{name}
    • 检查强求账户名是否存在于 Account 表
    • 如存在则判断是否生效,若生效返回token,否则报错
    • 若不存在
      • 自动创建账户信息
      • 检索企业下同名员工,若不存在则自动创建并关联到账户对象
      • 若配置了账户自动生效,返回 token,否则前端提示账户未激活请联系管理员
  • 部署上线
    • 部署平台获取到登录页 URL(https://{域名}/dingding.html)
    • 在钉钉后台填入上述地址后发布应用版本
    • 用户在钉钉客户端工作台添加应用后即可访问

新建 dingding.html

我们在前端项目代码下新建对应页面:

并在 rsbuild.config.mjs中配置多页面:

export default defineConfig({source:{entry:{index: './src/index.js',dingding: './src/pages/dingding/index.js'}}
})

至此,我们可以通过 http://{IP}/dingding.html访问到该页面,作为钉钉免登的入口😄。

编写登录页面逻辑

登录页主要组件 App.vue 代码如下:

<template><div style="width: 80%; margin: 40px auto;"><div class="text-center" v-if="!errMsg"><n-spin :show="working"><template #description>钉钉客户端登录中,请稍候...</template></n-spin></div><n-alert v-else :type show-icon title="钉钉自动登录失败" :bordered="false">{{ errMsg }}</n-alert></div>
</template><script setup>import { NSpin, NAlert, useMessage, NMessageProvider } from 'naive-ui'import { requestAuth } from "./dingding"import { checkLocalToken, saveLocalToken } from "../login"const msg = useMessage()let cid = undefinedlet corpId = undefinedconst debug = import.meta.env.DEV;let working = ref(true)let errMsg = ref("")let type = ref("info")const onMsg = (msg, isError=true)=>{errMsg.value = msgtype.value = isError?"error":"info"}const tryToAutoLogin = ()=>{requestAuth(corpId).then(code=>{msg.info(`CODE=${code}`)fetch("/common/login-with-dingding",{method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify({ cid, code })}).then(response => response.json()).then(({ success, data, message }) => {if(success==true){msg.success(`登陆成功`)saveLocalToken(data)gotoIndex()}else{const messages = {E01 : "您的钉钉账户为首次登录,请先联系管理员完成激活",E02 : "您的钉钉账户关联未激活,请联系企业管理员",E03 : "找不到当前钉钉账户关联的员工"}onMsg(messages[message]||message, !messages[message])}})}).catch(e=>onMsg(typeof(e)=='string'?e:e.message))}const gotoIndex = ()=> location.href = "/"onMounted(() => {let u = new URL(location.href)cid = u.searchParams.get('cid')corpId = u.searchParams.get('corpId')if(checkLocalToken())return gotoIndex()tryToAutoLogin()})
</script>
// dingding.js
import { runtime } from 'dingtalk-jsapi'export const requestAuth = async (corpId)=> {let { code } = await runtime.permission.requestAuthCode({corpId})return code
}//login.js
const NAME = import.meta.env.PUBLIC_HEADER_TOKEN
const CREATED = `${NAME}_CREATED`/*** 检查本地 token 是否在有效期内* @param {Number} expired - token 有效期,默认12小时,单位毫秒* @returns {Boolean} true 时为 token 有效*/
export const checkLocalToken = (expired=12*60*60*1000)=>{let token = localStorage.getItem(NAME)if(!token)  return falselet expire = localStorage.getItem(CREATED)||0if(Date.now() - expire>=expired)return falsereturn true
}export const saveLocalToken = token=>{localStorage.setItem(NAME, token)localStorage.setItem(CREATED, Date.now())
}

这里不得不吐槽下钉钉开发平台的官网文档,新旧版 API 文档特别容易让人混乱,引入dingtalk-jsapi的话需要查看旧版文档😔。

编写后端与钉钉服务器的交互

const { get, post } = require('axios')
const { loadWithCidAndName } = require("./ConstantService")
const logger = require('../common/logger')/*** @typedef {Object} DDTokenResponse - 钉钉获取token效应值* @property {String} access_token - token值* @property {Number} expires_in - 有效期(单位秒)* @property {Number} errcode - 错误代码* @property {String} errmsg - 错误信息** @typedef {Object} DDUser - 钉钉用户信息* @property {String} userid* @property {String} unionid - 唯一编号* @property {String} name - 用户名称** @typedef {Object} DDUserResponse - 钉钉用户信息响应值* @property {DDUser} result* @property {String} request_id* @property {Number} errcode - 错误代码* @property {String} errmsg - 错误信息*/const DING_HOST = "https://oapi.dingtalk.com"let localToken = {value: "",expire: 0
}const isTokenExpired = ()=> !localToken.value || localToken.expire<=Date.now()
const log = (msg, level='info')=> logger[level](`[钉钉] ${msg}`)exports.loginWithCode = async (cid, code)=>{if(isTokenExpired()){/**@type {CompanyConfig} */let cfg = await loadWithCidAndName(cid)if(!cfg || !(cfg.ddAppKey && cfg.ddAppSecret))throw `企业未配置钉钉登录`let url = `${DING_HOST}/gettoken?appkey=${cfg.ddAppKey}&appsecret=${cfg.ddAppSecret}`/**@type {{data:DDTokenResponse}} */let { data } = await get(url)if(data.errcode != 0){log(`获取企业 token 失败:${data.errcode}|${data.errmsg}`, 'error')throw data.errmsg}localToken.value = data.access_tokenlocalToken.expire = Date.now() + data.expires_in*1000log(`更新 TOKEN 为 ${localToken.value}(EXPIRED=${data.expires_in}`)}let url = `${DING_HOST}/topapi/v2/user/getuserinfo?access_token=${localToken.value}`/**@type {{data:DDUserResponse}} */let { data } = await post(url, { code })if(data.errcode != 0){log(`[钉钉] 获取用户信息失败:${data.errcode}|${data.errmsg}`, 'error')throw data.errmsg}global.isDebug && log(`获取用户信息 ${data.result.userid}/${data.result.name}`, 'debug')return data.result
}

部署及上线

创建钉钉H5微应用

  1. 登录钉钉开发者后台。
  2. 单击应用开发 > 企业内部应用 > 钉钉应用 > 创建应用
  3. 填写应用信息。
配置项是否必填配置说明
应用名称输入应用名称,应用名称最小长度为 2 个字符。
应用描述简要描述应用提供的产品或服务,应用描述最小长度为 4 个字符。
应用图标上传应用图标,图标要求 JPG/PNG 格式、240 px * 240 px 以上、1:1 、2 MB 以内的无圆角图标。
  1. 单击保存,进入应用详情页。
  2. 如果你需要开发 AI 应用、小程序、网页应用、酷应用和机器人功能,你需要添加应用能力。

发布应用

创建应用后,需要发布才能看到噢


接着在钉钉客户端就能看到此应用啦🎉

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/81987.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

idea无法识别Maven项目

把.mvn相关都删除了 导致Idea无法识别maven项目 或者 添加导入各个模块 最后把父模块也要导入

飞桨paddle import fluid报错【已解决】

跟着飞桨的安装指南安装了paddle之后 pip install paddlepaddle有一个验证&#xff1a; import paddle.fluid as fluid fluid.install check.run check()报错情况如下&#xff0c;但是我在pip list中&#xff0c;确实看到了paddle安装上了 我import paddle别的包&#xff0c…

现代化SQLite的构建之旅——解析开源项目Limbo

现代化SQLite的构建之旅——解析开源项目Limbo 在当今飞速发展的技术世界中,轻量级且功能强大的数据库已成为开发者的得力助手。当我们谈论轻量级数据库时,SQLite无疑是一个举足轻重的名字。然而,随着技术的进步,我们对数据库的需求也变得更加多样化。这正是Limbo项目诞生…

MinIO:从入门到精通,解锁云原生存储的奥秘

一、引言&#xff1a;为什么 MinIO 正在重塑存储世界&#xff1f; 在云计算和大数据时代&#xff0c;传统存储系统面临扩展性差、成本高、兼容性不足等挑战。MinIO 凭借其 S3 兼容性、分布式架构、高性能存储 等特性&#xff0c;成为企业构建现代化存储基础设施的首选。 本文…

vscode怎么关闭自动定位文件

关闭自动定位文件功能 方式1 在设置中搜索: explorer.autoReveal 方式2 直接在settings.json中增加"explorer.autoReveal": false 添加类似jetbrains IDE的文件定位功能 可以直接安装插件市场搜索niushuaibing.vs-location, 安装后会有文件定位按钮, 点击后即可…

学习路之uniapp--unipush2.0推送功能--给自己发通知

学习路之uniapp--unipush2.0推送功能--给自己发通知 一、绑定云空间及创建云函数二、编写发送界面三、效果后期展望&#xff1a; 一、绑定云空间及创建云函数 package.json {"name": "server-push","dependencies": {},"main": "…

什么是VR展示?VR展示的用途

随着科技的迅猛发展&#xff0c;我们步入一个全新的数字时代。在这个时代&#xff0c;虚拟现实&#xff08;VR&#xff09;技术崭露头角&#xff0c;逐步改变我们对世界的认知。全景展示厅作为VR技术与传统展览艺术的完美结合&#xff0c;以独特的全景视角&#xff0c;引领我们…

抖音IP属地跟无线网有关吗?如何更改

IP属地显示功能让许多用户感到好奇——为什么自己的位置信息有时准确&#xff0c;有时却显示在其他城市&#xff1f;这时&#xff0c;用户会疑惑&#xff1a;抖音IP属地跟无线网有关系吗&#xff1f;抖音的IP属地显示与其所使用的网络类型&#xff08;包括无线网&#xff09;密…

JESD204 ip核使用与例程分析(二)

JESD204 ip核使用与例程分析(二) JESD204时钟方案专用差分时钟对例程分析jesd204_0_transport_layer_demapperjesd204_0_sig_chkjesd204_0_clockingjesd204_0 ip核port寄存器AXI-LITE寄存器配置jesd204_phy ip核JESD204时钟方案 图3-1所示为最通用、灵活的时钟解决方案。在图…

微软全新开源的Agentic Web网络项目:NLWeb,到底是什么 ?

目录 1、背景 2、NLWeb是什么&#xff1f; 3、NLWeb是如何工作的&#xff1f; 3.1 技术原理 3.2 对发布者的价值 3.3 核心团队与合作伙伴 4、快速入门指南 5、延伸阅读 Agentic&#xff1a;Agent的形容词&#xff0c;Agentic指系统由大型语言模型&#xff08;LLM&#…

前端性能优化的秘密武器:Preload 与 Prefetch 的深度解析

前端性能优化的秘密武器&#xff1a;Preload 与 Prefetch 的深度解析 在前端开发中&#xff0c;页面加载速度直接影响用户体验和业务转化率。而“资源预加载”技术&#xff0c;正是优化加载性能的核心手段之一。本文将深入浅出地讲解 Preload 与 Prefetch 这两项技术&#xff…

App Builder技术选型指南:从AI编程到小程序容器,外卖App开发实战

在2025年快速迭代的技术生态中&#xff0c;开发者构建App的路径愈发多样化。本文以开发一个同城外卖App为例&#xff0c;对比当前主流的AI编程工具&#xff08;如Cursor、GitHub Copilot、Trae&#xff09;与小程序容器技术&#xff08;如FinClip&#xff09;的优劣势、难易度及…

深度学习入门到实战:用PyTorch打通数学、张量与模型训练全链路​

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 一. 人工智能、机器学习与深度学习的关系 1.1 概念层次解析 人工智能&#xff08;AI&#xff09;&#xff1a;使机器模拟人类智能的广义领域 机器学…

windows服务器部署jenkins工具(一)

jenkins作为一款常用的构建发布工具&#xff0c;极大的简化了项目部署发布流程。jenkins通常是部署在linux服务上&#xff0c;今天给大家分享的是windows服务器上如何搭建jenkins发布工具。 1.首先第一步还是看windows安装docker 这篇文章哈&#xff0c;当然也可以不采用docke…

前端开发规范性利器系列之:ESLint

前言 我是一名从事低代码平台研发的前端CV程序猿&#xff0c;有几十名像我一样的小伙伴协同研发。在长期的多人协作和滚动迭代中&#xff0c;不出意外&#xff0c;代码中会充斥各种“坏味道”&#xff0c;如代码风格不统一、扩展性和灵活性降低等问题。我们是如何解决这些问题的…

数据结构知识点汇总

1、在数据结构中&#xff0c;随机访问是指能够直接访问任一元素&#xff0c;而不需要从特定的起始位置开始&#xff0c;也不需要按顺序访问其他元素。这种访问方式通常不涉及遍历。例如&#xff0c;数组&#xff08;array&#xff09;支持随机访问&#xff0c;你可以直接通过索…

ubuntu中上传项目至GitHub仓库教程

一、到github官网注册用户 1.注册用户 地址&#xff1a;https://github.com/ 2.安装Git 打开终端&#xff0c;输入指令git,检查是否已安装Git 如果没有安装就输入指令 sudo apt-get install git 二、上传项目到github 1.创建项目仓库 进入github主页&#xff0c;点击号…

C#在 .NET 9.0 中启用二进制序列化:配置、风险与替代方案

在 .NET 9.0 中启用二进制序列化&#xff1a;配置、风险与替代方案 引言一、启用二进制序列化的步骤二、实现序列化与反序列化三、安全风险与缓解措施四、推荐替代方案五、总结 引言 在 .NET 生态中&#xff0c;二进制序列化&#xff08;Binary Serialization&#xff09;曾是…

如何解决鸿蒙应用闪退问题

如何解决鸿蒙应用闪退问题 本文是一份面向 ArkTS&#xff0f;JavaScript&#xff0f;C 多语言开发者的综合性排查与优化手册&#xff0c;覆盖 HarmonyOS/OpenHarmony 5.x 时代 常见闪退根因、诊断流程、调试技巧、CI 监控及线上防护方案&#xff0c;力争帮你把 Crash 数量降到 …

【Java高阶面经:微服务篇】4.大促生存法则:微服务降级实战与高可用架构设计

一、降级决策的核心逻辑:资源博弈下的生存选择 1.1 大促场景的资源极限挑战 在电商大促等极端流量场景下,系统面临的资源瓶颈呈现指数级增长: 流量特征: 峰值QPS可达日常的50倍以上(如某电商大促下单QPS从1万突增至50万)流量毛刺持续时间短(通常2-4小时),但对系统稳…