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

java后端对接飞书登陆

java后端对接飞书登陆
在这里插入图片描述

项目要求对接第三方登陆,飞书登陆,次笔记仅针对java后端,在看本笔记前,默认已在飞书开发方已建立了应用,并获取到了appid和appsecret。后端要做的其实很简单,基本都是前端做的,后端要做的就是接收前端请求飞书获取到一个code后传到后端,后端拿到code后请求登陆人在飞书的token信息,同时根据token请求飞书接口获取登陆人信息返回给前端就好了,官网开发指导有很详细的教程,可以看下官方文档。
飞书官方文档
废话不多书,直接上代码:
首先controller:

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;/*** @author xx*/
@RestController
@Api(tags = "飞书登陆认证")
public class FeiShuController {@Resourceprivate FeiShuService feiShuService;@GetMapping("/getUserByCode/{code}")@ApiOperation(value = "根据code获取飞书用户信息")public Response<FeishuUserResp> login(@PathVariable String code) {//获取飞书用户tokenFeiShuTokenResp feiShuTokenVo = feiShuService.getTokenByCode(code);//根据token获取用户信息FeishuUserResp userInfo = feiShuService.getUserInfoByToken(feiShuTokenVo);// 刷新tokenreturn Response.ok(userInfo);}@GetMapping("/refreshToken/{refreshToken}")@ApiModelProperty(value = "刷新token")public Response<FeishuUserResp> refreshToken(@PathVariable String refreshToken){return Response.ok(feiShuService.refreshToken(refreshToken));}@PostMapping("/login-out/{userId}")@ApiOperation(value = "飞书退出登陆")public Response loginOut(HttpServletRequest request, @PathVariable String userId){return feiShuService.loginOut(request,userId);}
}

service层:

import cn.hutool.http.Header;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;@Slf4j
@Service
public class FeiShuServiceImpl implements FeiShuService {// 应用appid@Value("${feishu.app.id}")private String appid;// 应用appsecret@Value("${feishu.app.secret}")private String appsecret;// 飞书获取token地址@Value("${feishu.userAccessTokenUrl}")private String userAccessTokenUrl;// 回调地址(需前端提供)@Value("${feishu.redirectUrl}")private String redirectUrl;// 获取用户详情@Value("${feishu.userInfoUrl}")private String userInfoUrl;// 登出飞书地址@Value("${feishu.logOutUrl}")private String loginOutUrl;//刷新飞书token地址@Value("${feishu.refreshTokenUrl}")private String refreshTokenUrl;@Resourceprivate RedisService redisService;/*** 根据code获取token** @param code code* @return token*/@Overridepublic FeiShuTokenResp getTokenByCode(String code) {Map<String, Object> params = new HashMap<>(4);params.put("grant_type", "authorization_code");params.put("client_id", appid);params.put("client_secret", appsecret);params.put("code", code);params.put("redirect_uri", redirectUrl);String result = HttpUtil.createPost(userAccessTokenUrl).header(Header.CONTENT_TYPE, "application/json").charset("utf-8").body(JSON.toJSONString(params)).execute().body();if (StringUtils.isEmpty(result)) {throw new RuntimeException("获取飞书token失败!");}JSONObject parseObj = JSONUtil.parseObj(result);if ((int) parseObj.get("code") != 0) {throw new RuntimeException("请求飞书token失败:" + parseObj.get("error_description"));}//tokenString userAccessToken = (String) parseObj.get("access_token");//token过期时间long expiresIn = (int) parseObj.get("expires_in");// refresh_tokenString refreshToken = (String) parseObj.get("refresh_token");// 刷新token的过期时间long refreshTokenExpiresIn = (int) parseObj.get("refresh_token_expires_in");// token_typeString tokenType = (String) parseObj.get("token_type");return FeiShuTokenResp.builder().tokenType(tokenType).accessToken(userAccessToken).expiresIn(expiresIn).refreshToken(refreshToken).refreshTokenExpiresIn(refreshTokenExpiresIn).build();}/*** 获取用户详情** @return 用户信息*/@Overridepublic FeishuUserResp getUserInfoByToken(FeiShuTokenResp feiShuTokenVo) {String token = feiShuTokenVo.getTokenType() + " " + feiShuTokenVo.getAccessToken();String result = HttpUtil.createGet(userInfoUrl).header("Authorization", token).header(Header.CONTENT_TYPE, "application/json").charset("utf-8").execute().body();if (StringUtils.isEmpty(result)) {throw new RuntimeException("请求飞书用户详情接口失败!");}JSONObject parseObj = JSONUtil.parseObj(result);if ((int) parseObj.get("code") != 0) {throw new RuntimeException("获取飞书用户信息失败:" + parseObj.get("msg"));}Object data = parseObj.get("data");FeishuUserResp userResp = JSONUtil.toBean(JSONUtil.toJsonStr(data), FeishuUserResp.class);userResp.setAccessToken(feiShuTokenVo.getAccessToken());userResp.setRefreshToken(feiShuTokenVo.getRefreshToken());// 缓存tokenString tokenKey = GlobalConstant.TOKEN + ":" + feiShuTokenVo.getAccessToken();redisService.setCacheObject(tokenKey, feiShuTokenVo.getAccessToken(), feiShuTokenVo.getExpiresIn(), TimeUnit.SECONDS);//缓存用户信息redisService.setCacheObject(feiShuTokenVo.getAccessToken(), userResp, feiShuTokenVo.getExpiresIn(), TimeUnit.SECONDS);//缓存刷新tokenif (Objects.nonNull(feiShuTokenVo.getRefreshToken())) {String refreshTokenKey = GlobalConstant.REFRESH_TOKEN + ":" + feiShuTokenVo.getRefreshToken();redisService.setCacheObject(refreshTokenKey, feiShuTokenVo.getRefreshToken(), feiShuTokenVo.getRefreshTokenExpiresIn(), TimeUnit.SECONDS);//缓存redisService.setCacheObject(feiShuTokenVo.getRefreshToken(), userResp, feiShuTokenVo.getRefreshTokenExpiresIn(), TimeUnit.SECONDS);}return userResp;}/*** 飞书退出登陆** @param userId user_id* @return 返回*/@Overridepublic Response loginOut(HttpServletRequest request, String userId) {String token = request.getHeader(GlobalConstant.TOKEN);Map<String, Object> params = new HashMap<>(2);params.put("logout_type", 1);params.put("user_id", userId);String result = HttpUtil.createPost(loginOutUrl).header("Authorization", "").header(Header.CONTENT_TYPE, "application/json").charset("utf-8").body(JSONUtil.toJsonStr(params)).execute().body();if (result == null) {throw new RuntimeException("飞书退出登陆失败!");}JSONObject parseObj = JSONUtil.parseObj(result);//删除缓存tokenFeishuUserResp object = redisService.getCacheObject(token);redisService.deleteObject(object.getAccessToken());redisService.deleteObject(object.getRefreshToken());redisService.deleteObject(GlobalConstant.TOKEN + ":" + token);redisService.deleteObject(GlobalConstant.REFRESH_TOKEN + ":" + object.getRefreshToken());if ((int) parseObj.get("code") == 0) {return Response.ok();}return Response.failed(parseObj.get("msg").toString());}/*** 刷新token** @param refreshToken 刷新token* @return 返回*/@Overridepublic FeishuUserResp refreshToken(String refreshToken) {Map<String, String> params = new HashMap<>(4);params.put("grant_type", "refresh_token");params.put("client_id", appid);params.put("client_secret", appsecret);params.put("refresh_token", refreshToken);String result = HttpUtil.createPost(refreshTokenUrl).header(Header.CONTENT_TYPE, "application/json").charset("utf-8").body(JSONUtil.toJsonStr(params)).execute().body();if (Objects.isNull(result)) {throw new RuntimeException("刷新token失败!");}JSONObject parseObj = JSONUtil.parseObj(result);if (20037 == (int) parseObj.get("code")) {throw new RuntimeException("refresh_token已过期");}if (0 != (int) parseObj.get("code")) {throw new RuntimeException("请求飞书刷新token接口失败:" + parseObj.get("error_description"));};//tokenString token = (String) parseObj.get("access_token");//token过期时间long expiresIn = (long) parseObj.get("expires_in");//刷新tokenString refreshToken1 = (String) parseObj.get("refresh_token");//刷新token 过期时间long refreshTokenExpiresIn = (long) parseObj.get("refresh_token_expires_in");FeishuUserResp resp = redisService.getCacheObject(refreshToken);resp.setAccessToken(token);resp.setRefreshToken(refreshToken1);//缓存tokenredisService.setCacheObject(GlobalConstant.TOKEN + ":" + token, token, expiresIn, TimeUnit.MINUTES);redisService.setCacheObject(token, resp, expiresIn, TimeUnit.MINUTES);Object object = redisService.getCacheObject(GlobalConstant.REFRESH_TOKEN + ":" + refreshToken1);if (Objects.isNull(object)) {redisService.setCacheObject(GlobalConstant.REFRESH_TOKEN + ":" + refreshToken1, refreshToken1, refreshTokenExpiresIn, TimeUnit.MINUTES);redisService.setCacheObject(refreshToken1, resp, refreshTokenExpiresIn, TimeUnit.MINUTES);}return resp;}
}

yml文件飞书相关配置

#  飞书相关配置
feishu:app:id: "xxxxxx"secret: "xxxxxx"# 获取token地址userAccessTokenUrl: "https://open.feishu.cn/open-apis/authen/v2/oauth/token"# 回调地址(可更改)redirectUrl: "http://xxxxxx/upgrade/login"# 获取用户信息地址userInfoUrl: "https://open.feishu.cn/open-apis/authen/v1/user_info"# 登出logOutUrl: "https://open.feishu.cn/open-apis/passport/v1/sessions/logout"# 刷新token地址refreshTokenUrl: "https://open.feishu.cn/open-apis/authen/v2/oauth/token"

学习笔记仅供学习使用,更详细步骤请移步官方文档。

相关文章:

java后端对接飞书登陆

java后端对接飞书登陆 项目要求对接第三方登陆&#xff0c;飞书登陆&#xff0c;次笔记仅针对java后端&#xff0c;在看本笔记前&#xff0c;默认已在飞书开发方已建立了应用&#xff0c;并获取到了appid和appsecret。后端要做的其实很简单&#xff0c;基本都是前端做的&…...

记录一次Android Studio的下载、安装、配置

目录 一、下载和安装 Android Studio 1、搜索下载Android studio ​2、下载成功后点击安装包进行安装&#xff1a; 3、这里不用打勾&#xff0c;直接点击安装 &#xff1a; 4、完成安装&#xff1a; 5、这里点击Cancel就可以了 6、接下来 7、点击自定义安装&#xff1a…...

直流无刷电机控制(FOC):电流模式

目录 概述 1 系统框架结构 1.1 硬件模块介绍 1.2 硬件实物图 1.3 引脚接口定义 2 代码实现 2.1 软件架构 2.2 电流检测函数 3 电流环功能实现 3.1 代码实现 3.2 测试代码实现 4 测试 概述 本文主要介绍基于DengFOC的库函数&#xff0c;实现直流无刷电机控制&#x…...

73.矩阵置零 python

矩阵置零 题目题目描述示例 1&#xff1a;示例 2&#xff1a;提示&#xff1a; 题解思路分析Python 实现代码代码解释提交结果 题目 题目描述 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例…...

垃圾收集算法

分代收集理论 分代收集理论&#xff0c;建立在两个分代假说之上。 弱分代假说&#xff1a;绝大多数对象都是朝圣夕灭的。 强分代假说&#xff1a;熬过越多次垃圾收集的过程的对象就越难以消亡。 这两个分代假说奠定了垃圾收集器的一致设计原则&#xff1a;收集器应该将Java…...

SQL-leetcode-262. 行程和用户

262. 行程和用户 表&#xff1a;Trips --------------------- | Column Name | Type | --------------------- | id | int | | client_id | int | | driver_id | int | | city_id | int | | status | enum | | request_at | varchar | --------------------- id 是这张表的主键…...

太原理工大学软件设计与体系结构 --javaEE

这个是简答题的内容 选择题的一些老师会给你们题库&#xff0c;一些注意的点我会做出文档在这个网址 项目目录预览 - TYUT复习资料:复习资料 - GitCode 希望大家可以给我一些打赏 什么是Spring的IOC和DI IOC 是一种设计思想&#xff0c;它将对象的创建和对象之间的依赖关系…...

Leetcode 139. 单词拆分 动态规划

原题链接&#xff1a;Leetcode 139. 单词拆分 递归&#xff0c;超时 class Solution { public:bool isfind(string s,map<string,int>& mp){for(auto x:mp){string wordx.first;if(sword) return true;int nword.size();if(n>s.size()) continue;string s1s.subs…...

python异常机制

异常是什么&#xff1f; 软件程序在运行过程中&#xff0c;非常可能遇到刚刚提到的这些问题&#xff0c;我们称之为异常&#xff0c;英文是Exception&#xff0c;意思是例外。遇到这些例外情况&#xff0c;或者交异常&#xff0c;我们怎么让写的程序做出合理的处理&#xff0c…...

运行爬虫时可能遇到哪些常见问题?

在运行Python爬虫时&#xff0c;可能会遇到以下一些常见问题及相应的解决方法&#xff1a; 1. 请求频繁被封 IP 问题描述&#xff1a;爬虫请求频繁时&#xff0c;网站可能会识别到异常行为并封禁 IP&#xff0c;从而导致后续请求失败。解决方法&#xff1a; 使用代理&#xf…...

BGP与CN2的区别 详解两者在网络传输中的应用与优势

在现代互联网环境中&#xff0c;选择合适的网络传输协议和解决方案对于企业的业务运行至关重要。BGP&#xff08;Border Gateway Protocol&#xff09;和CN2&#xff08;China Telecom Next Carrier Network&#xff09;是两种广泛应用的网络技术&#xff0c;但它们的设计理念、…...

Spring 项目 基于 Tomcat容器进行部署

文章目录 一、前置知识二、项目部署1. 将写好的 Spring 项目先打包成 war 包2. 查看项目工件&#xff08;Artifact&#xff09;是否存在3. 配置 Tomcat3.1 添加一个本地 Tomcat 容器3.2 将项目部署到 Tomcat 4. 运行项目 尽管市场上许多新项目都已经转向 Spring Boot&#xff0…...

“负载均衡”出站的功能、原理与场景案例

在企业日常网络中&#xff0c;外网访问速度不稳定是一个常见问题。特别是多条外网线路并行时&#xff0c;不合理的流量分配会导致资源浪费甚至网络拥堵。而出站负载均衡&#xff0c;正是解决这一问题的关键技术。 作为一种先进的网络流量管理技术&#xff0c;其核心是优化企业内…...

02-51单片机数码管与矩阵键盘

一、数码管模块 1.数码管介绍 如图所示为一个数码管的结构图&#xff1a; 说明&#xff1a; 数码管上下各有五个引脚&#xff0c;其中上下中间的两个引脚是联通的&#xff0c;一般为数码管的公共端&#xff0c;分为共阴极或共阳极&#xff1b;其它八个引脚分别对应八个二极管…...

不同方式获取音频时长 - python 实现

DataBall 助力快速掌握数据集的信息和使用方式&#xff0c;会员享有 百种数据集&#xff0c;持续增加中。 需要更多数据资源和技术解决方案&#xff0c;知识星球&#xff1a; “DataBall - X 数据球(free)” -------------------------------------------------------------…...

【python A* pygame 格式化 自定义起点、终点、障碍】

- pip install pygame test.py(chatgpt版本) 空格键&#xff1a;运行 A* 算法。CtrlC 键&#xff1a;清空路径。CtrlS 键&#xff1a;保存当前地图到 map.json 文件。CtrlL 键&#xff1a;从 map.json 文件加载地图。 import pygame import json from queue import PriorityQ…...

12_Redis发布订阅

1.Redis发布订阅介绍 1.1 基本概念 Redis的发布订阅(Pub/Sub)是一种消息通信模式,允许消息的发布者(Publisher)将消息发布到一个或多个频道(Channel),订阅者(Subscriber)通过订阅这些频道来接收消息。 发布者(Publisher):发送消息的一方,使用PUBLISH命令将消息…...

归并排序:数据排序的高效之道

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…...

【redis初阶】浅谈分布式系统

目录 一、常见概念 1.1 基本概念 2.2 评价指标&#xff08;Metric&#xff09; 二、架构演进 2.1 单机架构 2.2 应用数据分离架构 2.3 应用服务集群架构 2.4 读写分离/主从分离架构 2.5 引入缓存 ⸺ 冷热分离架构 2.6 数据库分库分表 2.7 业务拆分 ⸺ 引入微服务 redis学习&…...

CatLog的使用

一 CatLog的简介 1.1 作用 CAT&#xff08;Central Application Tracking&#xff09; 是基于 Java 开发的实时应用监控平台&#xff0c;为美团点评提供了全面的实时监控告警服务。 1.2 组成部分 1.2.1 Transaction 1.Transaction 适合记录跨越系统边界的程序访问行为&a…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

【决胜公务员考试】求职OMG——见面课测验1

2025最新版&#xff01;&#xff01;&#xff01;6.8截至答题&#xff0c;大家注意呀&#xff01; 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:&#xff08; B &#xff09; A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学&#xff08;silicon photonics&#xff09;的光波导&#xff08;optical waveguide&#xff09;芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中&#xff0c;光既是波又是粒子。光子本…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...