如何实现H5端对接钉钉登录并优雅扩展其他平台

news2025/7/18 9:14:25

如何实现H5端对接钉钉登录并优雅扩展其他平台

    • 钉钉H5登录逻辑
    • 后端代码如何实现?
    • 本次采用策略模式+工厂方式进行
      • 定义接口确定会使用的基本鉴权步骤
      • 具体逻辑类进行实现
      • 采用注册表模式(Registry Pattern)
      • 抽象工厂进行基本逻辑定义
      • 具体工厂进行对接口中的逻辑步骤具体----实例化----逻辑进行重写
    • 总结

钉钉H5登录逻辑

下图中需要说明的一点是,准确来说步骤3来说是钉钉API返回给前端,前端携带一次性校验码token给后端进行后续的鉴权。
还有一点需要注意获得权限之后,如果前端需要回调接口获取用户信息,则需要增加上下文中的用户信息存储

image-20250407212849539

后端代码如何实现?

具体的伪代码如下所述,下面细聊一下如何进行实现获取用户信息这一步。其中本次采用了设计模式进行实现。

    public Result<LoginResp> h5Login(LoginH5UserReq loginH5UserReq) throws ApiException {
        // 获取租户信息
        xxxxx
        // 查询三方鉴权配置信息
        xxxxx
        // 获取用户信息 这一步很关键后面细说如何实现
        H5AuthHandler H5AuthHandler = H5AuthHandlerRegistry.createHandler(loginH5UserReq.getTypePlatForm());
        String userUniqueIdentifier = H5AuthHandler.getUserDetail(loginH5UserReq);
        // 系统校验根据手机号查询用户信息
        SysUser sysUser = sysUserMapper.selectOne(Wrappers.lambdaQuery(SysUser.class).eq(SysUser::getTel, userUniqueIdentifier), false);
        // 使用断言进行优雅校验
        Assert.notNull(sysUser, () -> new BizException(ErrorCodeEnum.NOT_AVAILABLE));
        // 校验通过下发token
        String accessToken = StpUtil.getTokenInfo().getTokenValue();
       	xxxx
        return Result.success(loginResult);
    }

本次我的思路是实现针对不同平台,例如对接钉钉、企业微信、飞书、三方,具体的逻辑是不一样的,使用设计模式中的工厂模式进行构建,实现不同的逻辑进行创建不同类进行完成。

简单罗列一下可以采用的设计模式的具体之间的区别

image-20250407214413483

本次采用策略模式+工厂方式进行

定义接口确定会使用的基本鉴权步骤

public interface AuthHandler {
    // 获取访问令牌(需处理OAuth2 code校验)
    String getAccessToken(String code) throws AuthException;
    
    // 使用令牌换取用户唯一标识(需处理令牌失效场景)
    String getUserId(String token) throws AuthException;
    
    // 获取用户详细信息(需处理多层级JSON解析)
    UserDetail getUserDetail(String userId) throws AuthException;
}

具体逻辑类进行实现

下面代码是大致思路展示,直接run是会出现问题。涉及公司保密协议不可以直接上我的源码望读者朋友见谅~

public class DingTalkAuthHandler implements AuthHandler {
    private static final String API_HOST = "https://oapi.dingtalk.com";
    private final String appKey;
    private final String appSecret;

    // 依赖配置注入(参考网页6的钉钉配置)
    public DingTalkAuthHandler(String appKey, String appSecret) {
        this.appKey = appKey;
        this.appSecret = appSecret;
    }

    @Override
    public String getAccessToken(String code) {
        // 构建认证请求参数(参考网页7的code交换逻辑)
        Map<String, String> params = new HashMap<>();
        params.put("appkey", appKey);
        params.put("appsecret", appSecret);
        
        // 调用钉钉API(网页6的接口文档)
        String url = API_HOST + "/gettoken?" + buildQueryString(params);
        JsonNode response = HttpUtil.get(url);
        
        // 错误码校验(参考网页6的errcode处理)
        if(response.get("errcode").asInt() != 0) {
            throw new DingTalkAuthException(response.get("errmsg").asText());
        }
        return response.get("access_token").asText();
    }

    @Override
    public String getUserId(String token) {
        // 安全域名验证(参考网页7的domain校验)
        String url = API_HOST + "/user/getuserinfo?access_token=" + token;
        JsonNode userInfo = HttpUtil.get(url);
        return userInfo.get("userid").asText();
    }

    @Override
    public UserDetail getUserDetail(String userId) {
        // 多层级数据解析(参考网页6的JSON结构)
        String url = API_HOST + "/user/get?userid=" + userId;
        JsonNode data = HttpUtil.get(url).get("result");
        
        return UserDetail.builder()
            .mobile(data.at("/mobile").asText()) // JSONPath定位
            .name(data.get("name").asText())
            .avatar(data.get("avatar").asText())
            .build();
    }
    
    // 私有方法封装请求构建
    private String buildQueryString(Map<String, String> params) {
        return params.entrySet().stream()
            .map(e -> e.getKey() + "=" + URLEncoder.encode(e.getValue(), StandardCharsets.UTF_8))
            .collect(Collectors.joining("&"));
    }
}

上述代码通过接口 + 实现类的方式进行大致逻辑的定义,具体逻辑的展开,不是本次的重点,主要想记录一下如何实现下述的调用:

// 需要实现根据loginH5UserReq.getTypePlatForm() 传入不同的类型,实现实例化对应的实体类进行处理对应逻辑
H5AuthHandler H5AuthHandler = H5AuthHandlerRegistry.createHandler(loginH5UserReq.getTypePlatForm());
// 得到具体逻辑类之后根据请求信息返回用户唯一的id进行后续鉴权
String userUniqueIdentifier = H5AuthHandler.getUserDetail(loginH5UserReq);

采用注册表模式(Registry Pattern)

集中管理平台与工厂映射关系,提供统一访问入口

@Component
// 为什么要采用ApplicationContextAware?文末解释
public class H5AuthHandlerRegistry implements ApplicationContextAware {
    
    private static final Map<String, H5AuthHandlerFactory<?>> REGISTRY = new ConcurrentHashMap<>();
    private static ApplicationContext applicationContext;
    
    @Override
    public void setApplicationContext(ApplicationContext context) {
        applicationContext = context;
        // Spring容器初始化完成后动态注册平台
        registerPlatforms();
    }
    
    // 具体平台注册
    private void registerPlatforms() {
        // 钉钉平台注册(依赖注入已生效)
        H5DingTalkAuthFactory dingTalkFactory = new H5DingTalkAuthFactory(applicationContext);
        REGISTRY.put(Platforms.DING_TALK.name(), dingTalkFactory);
        // 其他平台注册
        xxxxxxx
    }
    
    // 获取处理器工厂
    public static H5AuthHandlerFactory<?> getFactory(String platform) {
        return Optional.ofNullable(REGISTRY.get(platform))
                .orElseThrow(() -> new IllegalArgumentException("未注册的平台: " + platform));
    }
    
    // 全局同意访问入口
    public static H5AuthHandler createHandler(String platform) {
        return getFactory(platform).createHandler();
    }
}

抽象工厂进行基本逻辑定义

为什么这里要使用抽象类?

首先我想定义基本的创建逻辑,其次抽象类不能被实例化。还有抽象类一般用于设计模式中一种通用写法规范,为子类提供公共的代码实现(如非抽象方法)和强制约束(如抽象方法),子类继承并实现所有抽象方法后才能实例化。

public abstract class H5AuthHandlerFactory<T extends H5AuthHandler> {
    
    private final Class<T> handlerClass;
    
    protected H5AuthHandlerFactory(Class<T> handlerClass) {
        this.handlerClass = handlerClass;
    }
    
    // 定义基本创建逻辑,采用反射方式进行。支持反射创建(需无参构造)
    // PS:如果具体进行逻辑类不涉及采用spring容器管理类,可以使用直接newInstance。不然会出现创建失败,spring容器ioc和Java创建对象是割裂的两派
    public T createHandler() {
        try {
            return handlerClass.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException("H5端登录逻辑抽象工厂---H5AuthHandlerFactory---处理器实例化失败", e);
        }
    }
    
}

具体工厂进行对接口中的逻辑步骤具体----实例化----逻辑进行重写

public class H5DingTalkAuthFactory extends H5AuthHandlerFactory<H5DingTalkAuthHandler> {
    
    private final ApplicationContext context;
    
    // 这里是因为具体实例化处理钉钉H5登录逻辑类会使用到spring容器中的类,所以需要采用上下文的方式
    public H5DingTalkAuthFactory(ApplicationContext context) {
        super(H5DingTalkAuthHandler.class);
        this.context = context;
    }
    
    @Override
    public H5DingTalkAuthHandler createHandler() {
        // 从Spring容器获取依赖项
        ThreePartyLoginRuleConfig ruleConfig = context.getBean(ThreePartyLoginRuleConfig.class);
        ObjectMapper objectMapper = context.getBean(ObjectMapper.class);
        // 通过构造器注入依赖
        return new H5DingTalkAuthHandler(ruleConfig, objectMapper);
    }
}

总结

总体来说,要实现其他平台的扩展。本次的使用中,由于对接不同平台,具体逻辑中涉及了配置文件配置不同平台JSON数据的解析,所以会使用sping中IOC功能,所以在工厂类中存在上下文部分。

扩展其他平台部分就需要创建两个类,一个类是集成抽象工厂实现其中的createHandler()方法,还有一个是实现接口中定义的三部曲。

H5xxxxxxxAuthFactory extends H5AuthHandlerFactory
H5xxxxxxxxAuthHandler implements H5AuthHandler

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

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

相关文章

LabVIEW真空度监测与控制系统

开发了一种基于LabVIEW的真空度信号采集与管理系统&#xff0c;该系统通过图形化编程语言实现了真空度的高精度测量和控制。利用LabVIEW的强大功能&#xff0c;研制了相应的硬件并设计了完整的软件解决方案&#xff0c;以满足工业应用中对真空度监测的精确要求。 项目背景 随着…

虚拟dom工作原理以及渲染过程

浏览器渲染引擎工作流程都差不多&#xff0c;大致分为5步&#xff0c;创建DOM树——创建StyleRules——创建Render树——布局Layout——绘制Painting 第一步&#xff0c;用HTML分析器&#xff0c;分析HTML元素&#xff0c;构建一颗DOM树(标记化和树构建)。 第二步&#xff0c;用…

数据采集爬虫三要素:User-Agent、随机延迟、代理ip

做爬虫的朋友都懂&#xff1a;你刚打开一个页面&#xff0c;还没来得及发第二个请求&#xff0c;服务器已经把你当成了“可疑流量”。403、429、验证码、JS挑战……这些“欢迎仪式”你是不是也经常收到&#xff1f;防爬策略越来越猛&#xff0c;采集工程师越来越秃。 但别慌&am…

汽车的四大工艺

文章目录 冲压工艺核心流程关键技术 焊接工艺核心流程 涂装工艺核心流程 总装工艺核心流程终检与测试静态检查动态检查四轮定位制动转鼓测试淋雨测试总结 简单总结下汽车的四大工艺&#xff08;从网上找了一张图&#xff0c;感觉挺全面的&#xff09;。 冲压工艺 将金属板材通过…

【JVM是什么?JVM解决什么问题?JVM在JDK体系中是什么?虚拟机和JVM、操作系统是什么关系?】

1. JVM 是什么&#xff1f; JVM&#xff08;Java Virtual Machine&#xff0c;Java 虚拟机&#xff09; 是一个虚拟的计算机程序&#xff0c;它是 Java 程序运行的核心环境。JVM 的主要职责是加载、验证、解释或编译 Java 字节码&#xff08;.class 文件&#xff09;&#xff…

10-MySQL-性能优化思路

1、优化思路 当我们发现了一个慢SQL的问题的时候,需要做性能优化,一般我们是为了提高SQL查询更快,一个查询的流程由下图的各环节组成,每个环节都会消耗时间,要减少消耗时候需要从各个环节都分析一遍。 2 连接配置优化 第一个环节是客户端连接到服务端,这块可能会出现服务…

MySQL学习笔记十

第十二章汇总数据 12.1聚集函数 聚集函数运行在行组上&#xff0c;计算和返回单个值。 12.1.1AVG()函数 输入&#xff1a; SELECT AVG(prod_price) AS avg_price FROM products; 输出&#xff1a; 说明&#xff1a;AVG()函数通过对表中行数计数并计算特定列值之和&#…

Redis快的原因

1、基于内存实现 Redis将所有数据存储在内存中&#xff0c;因此它可以非常快速地读取和写入数据&#xff0c;而无需像传统数据库那样将数据从磁盘读取和写入磁盘&#xff0c;这样也就不受I/O限制。 2、I/O多路复用 多路指的是多个socket连接&#xff1b;复用指的是复用一个线…

如何在React中集成 PDF.js?构建支持打印下载的PDF阅读器详解

本文深入解析基于 React 和 PDF.js 构建 PDF 查看器的实现方案&#xff0c;该组件支持 PDF 渲染、图片打印和下载功能&#xff0c;并包含完整的加载状态与错误处理机制。 完整代码在最后 一个PDF 文件&#xff1a; https://mozilla.github.io/pdf.js/web/compressed.tracemo…

【完美解决】VSCode连接HPC节点,已配置密钥却还是提示需要输入密码

目录 问题描述软件版本原因分析错误逻辑链 解决方案总结 问题描述 本人在使用 ​​VSCode Remote-SSH 插件​​连接超算集群节点时&#xff0c;遇到以下问题&#xff1a;已正确配置 SSH 密钥&#xff0c;且 VSCode 能识别密钥文件&#xff08;如图1&#xff09;&#xff0c;但在…

【JSON2WEB】16 login.html 登录密码加密传输

【JSON2WEB】系列目录 【JSON2WEB】01 WEB管理信息系统架构设计 【JSON2WEB】02 JSON2WEB初步UI设计 【JSON2WEB】03 go的模板包html/template的使用 【JSON2WEB】04 amis低代码前端框架介绍 【JSON2WEB】05 前端开发三件套 HTML CSS JavaScript 速成 【JSON2WEB】06 JSO…

从递归入手一维动态规划

从递归入手一维动态规划 1. 509. 斐波那契数 1.1 思路 递归 F(i) F(i-1) F(i-2) 每个点都往下展开两个分支&#xff0c;时间复杂度为 O(2n) 。 在上图中我们可以看到 F(6) F(5) F(4)。 计算 F(6) 的时候已经展开计算过 F(5)了。而在计算 F(7)的时候&#xff0c;还需要…

轻量级爬虫框架Feapder入门:快速搭建企业级数据管道

一、目标与前置知识 1. 目标概述 本教程的主要目标是&#xff1a; 介绍轻量级爬虫框架 Feapder 的基本使用方式。快速搭建一个采集豆瓣电影数据的爬虫&#xff0c;通过电影名称查找对应的电影详情页并提取相关信息&#xff08;电影名称、导演、演员、剧情简介、评分&#xf…

golang gmp模型分析

思维导图&#xff1a; 1. 发展过程 思维导图&#xff1a; 在单机时代是没有多线程、多进程、协程这些概念的。早期的操作系统都是顺序执行 单进程的缺点有&#xff1a; 单一执行流程、计算机只能一个任务一个任务进行处理进程阻塞所带来的CPU时间的浪费 处于对CPU资源的利用&…

【算法竞赛】树上最长公共路径前缀(蓝桥杯2024真题·团建·超详细解析)

目录 一、题目 二、思路 1. 问题转化&#xff1a;同步DFS走树 2. 优化&#xff1a;同步DFS匹配 3. 状态设计&#xff1a;dfs参数含义 4. 匹配过程&#xff1a;用 map 建立权值索引 5. 终止条件&#xff1a;无法匹配则更新答案 6. 总结 三、完整代码 四、知识点总…

【windows10】基于SSH反向隧道公网ip端口实现远程桌面

【windows10】基于SSH反向隧道公网ip端口实现远程桌面 1.背景2.SSH反向隧道3.远程连接电脑 1.背景 ‌Windows 10远程桌面协议的简称是RDP&#xff08;Remote Desktop Protocol&#xff09;‌。 RDP是一种网络协议&#xff0c;允许用户远程访问和操作另一台计算机。 远程桌面功…

Python----概率论与统计(贝叶斯,朴素贝叶斯 )

一、贝叶斯 1.1、贝叶斯定理 贝叶斯定理&#xff08;Bayes Theorem&#xff09;也称贝叶斯公式&#xff0c;是关于随机事件的条件概率的定理 贝叶斯的的作用&#xff1a;根据已知的概率来更新事件的概率。 1.2、定理内容 提示&#xff1a; 贝叶斯定理是“由果溯因”的推断&…

爬虫抓包工具和PyExeJs模块

我们在处理一些网站的时候, 会遇到一些屏蔽F12, 以及只要按出浏览器的开发者工具就会关闭甚至死机的现象. 在遇到这类网站的时候. 我们可以使用抓包工具把页面上屏蔽开发者工具的代码给干掉. Fiddler和Charles 这两款工具是非常优秀的抓包工具. 他们可以监听到我们计算机上所…

无人机击落技术难点与要点分析!

一、技术难点 1. 目标探测与识别 小型化和低空飞行&#xff1a;现代无人机体积小、飞行高度低&#xff08;尤其在城市或复杂地形中&#xff09;&#xff0c;雷达和光学传感器难以有效探测。 隐身技术&#xff1a;部分高端无人机采用吸波材料或低可探测设计&#xff0c;进…

8.第二阶段x64游戏实战-string类

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 上一个内容&#xff1a;7.第二阶段x64游戏实战-分析人物属性 string类是字符串类&#xff0c;在计算机中…