当前位置: 首页 > 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…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)

2025年能源电力系统与流体力学国际会议&#xff08;EPSFD 2025&#xff09;将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会&#xff0c;EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题&#xff08;可多选&#xff09; 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘&#xff1a;专注于发现数据中…...

vscode(仍待补充)

写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh&#xff1f; debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

SpringTask-03.入门案例

一.入门案例 启动类&#xff1a; package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

Docker 本地安装 mysql 数据库

Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker &#xff1b;并安装。 基础操作不再赘述。 打开 macOS 终端&#xff0c;开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...