嘉兴做网站优化多少钱,卖机票的网站怎么做,wordpress不用帐号,wordpress插件对话Tenant Access Token 获取机制聊天群组管理成员批量管理自动推送消息错误处理和重试策略为什么需要服务端集成飞书#xff1f;典型的业务场景在企业日常业务开展过程中#xff0c;经常会遇到以下场景#xff1a;应用场景 核心功能 关键技术点 业务价值项目群组自动化创建 - …Tenant Access Token 获取机制聊天群组管理成员批量管理自动推送消息错误处理和重试策略为什么需要服务端集成飞书典型的业务场景在企业日常业务开展过程中经常会遇到以下场景应用场景 核心功能 关键技术点 业务价值项目群组自动化创建 - 新项目启动时自动创建项目群组- 根据项目类型和人员角色批量拉入相关成员- 设置群组名称、描述、权限等规范配置 - 群组创建API- 批量成员添加- 权限模板配置 提高项目启动效率确保团队沟通规范性系统告警/通知自动推送 - 监控系统告警信息自动发送到指定飞书群- 业务流程状态变更通知- 定期报告和数据统计自动推送 - 富文本消息发送- 定时任务调度- 消息模板管理 及时通知相关人员提升响应速度和决策效率组织架构同步与批量管理 - HR系统组织架构变更同步到飞书- 批量创建部门群组并同步成员- 员工入职/离职时自动处理群组权限 - 组织架构API集成- 批量群组管理- 权限自动分配 保持组织架构一致性减少人工维护成本核心价值服务端集成带来的优势价值维度 核心特性 具体表现 技术优势 自动化 减少人工操作提高工作效率 - 群组创建、成员管理、消息推送全流程自动化- 7x24 小时无人值守运行- 业务规则驱动的智能处理 程序化执行减少人为错误提升处理速度和一致性 业务解耦 独立于飞书客户端可集成到现有系统 - 不依赖人工操作飞书客户端- 与 ERP、HR、OA 等业务系统无缝集成- API 接口标准化易于扩展和维护 系统集成灵活可嵌入现有工作流降低耦合度️ 安全可靠 服务端级别的高可用性保障 - 企业级应用的认证和授权机制- 操作日志完整记录便于审计追踪- 异常处理和重试机制确保消息送达 企业级安全标准操作可追溯系统稳定性高本文目标实际解决企业中的几个问题✅ Token 管理获取、缓存、自动刷新机制✅ 群组操作创建、查询、更新、解散✅ 成员管理批量添加、移除、权限控制✅ 消息推送文本、富文本、卡片等格式✅ 异常处理错误码解析、重试策略、日志记录准备工作进入飞书开放平台1. 创建应用首先访问 飞书开放平台 并创建企业自建应用登录飞书开放平台使用企业管理员账号登录进入开发者后台 - 创建应用选择应用类型选择企业自建应用填写应用名称如企业群管系统选择应用图标和描述获取关键信息App ID应用唯一标识符App Secret应用密钥用于获取访问令牌⚠️ 注意App Secret 泄露会导致安全风险生产环境中必须使用密钥管理服务。2. 配置权限在应用详情页中找到权限管理并添加以下必要权限核心群组权限contact:group:readonly # 获取群组信息contact:group:update # 更新群组信息contact:group:delete # 解散群组群组成员权限contact:group.member:readonly # 获取群组成员信息contact:group.member:add # 添加群组成员contact:group.member:delete # 移除群组成员消息发送权限im:message # 发送消息用于消息推送示例im:chat:announcement # 群公告操作可选高级权限根据需要添加contact:user.base:readonly # 读取用户基本信息contact:department:readonly # 读取部门信息3. 发布与启用应用发布确保应用状态为已发布配置应用图标、名称等基本信息授权范围将应用授权给测试范围如自己所在部门生产环境需要管理员审批后才能全公司使用获取服务器地址记录应用的服务器地址国内版 https://open.feishu.cn核心概念与流程解析1. 飞书服务端 API 认证机制Tenant Access Token什么是 Tenant Access TokenTenant Access Token租户访问令牌是飞书开放平台的 API 调用凭证具有以下特点租户级别代表整个企业应用的访问权限服务端调用适用于服务器端的自动化场景高权限可获得企业内所有受权数据自动刷新支持通过 App ID 和 App Secret 重新获取获取流程详解内存缓存飞书API.NET应用内存缓存飞书API.NET应用携带App ID和App Secretalt[Token存在且未过期][Token不存在或已过期]Authorization: Bearer {tenant_access_token}检查缓存中的Token返回缓存的TokenPOST /open-apis/auth/v3/tenant_access_token/internal返回tenant_access_token缓存新Token调用业务API (携带Token)返回业务数据技术实现要点使用 App ID App Secret 调用认证接口获取 tenant_access_token 和过期时间实现内存缓存避免频繁请求认证接口Token 过期前自动刷新机制2. 使用 Mud.Feishu 调用通用步骤步骤概览获取 Token调用认证接口获取有效的访问令牌构造请求设置 HTTP 方法、URL、请求头等携带认证在请求头中添加 Bearer Token处理请求体构造 JSON 格式的请求参数解析响应处理 API 返回的 JSON 响应数据简化的调用流程// 传统方式 - 需要大量样板代码var httpClient new HttpClient();var token await GetTokenAsync();httpClient.DefaultRequestHeaders.Authorization new AuthenticationHeaderValue(Bearer, token);var json JsonSerializer.Serialize(request);var response await httpClient.PostAsync(url,new StringContent(json, Encoding.UTF8, application/json));var result JsonSerializer.DeserializeResponseModel(await response.Content.ReadAsStringAsync());// Mud.Feishu 方式 - 简洁直观var result await _chatGroupApi.CreateChatGroupAsync(request);// 所有认证、序列化、异常处理都已内置处理使用 Mud.Feishu 进行 .NET 自动化群组管理与消息推送实战1. 环境与项目搭建创建新项目# 创建 .NET 8 Web API 项目dotnet new webapi -n FeishuGroupManager# 切换到项目目录cd FeishuGroupManager# 安装必要 NuGet 包dotnet add package Mud.Feishu --version 1.0.3dotnet add package Microsoft.Extensions.Httpdotnet add package System.Text.Json所有组件都使用微软官方库中的标准组件不添加多余的第三方库。配置文件设置创建 appsettings.json{Logging: {LogLevel: {Default: Information,Microsoft.AspNetCore: Warning}},Feishu: {AppId: cli_xxxxxxxxxxxxxxxx,AppSecret: your_secret_key_here,BaseUrl: https://open.feishu.cn}}服务注册配置在 Program.cs 中注册飞书服务using Mud.Feishu;var builder WebApplication.CreateBuilder(args);// 注册飞书 API 服务builder.Services.AddFeishuApiService(builder.Configuration);var app builder.Build();app.UseHttpsRedirection();app.UseAuthorization();app.MapControllers();app.Run();2. 核心服务类设计FeishuChatGroupService创建核心服务类来封装飞书 API 调用using Mud.Feishu;using Mud.Feishu.Exceptions;using Mud.Feishu.ChatGroup;using Microsoft.Extensions.Logging;/// summary/// 飞书群组管理服务/// /summarypublic class FeishuChatGroupService{private readonly IFeishuTenantV1ChatGroup _chatGroupApi;private readonly IFeishuTenantV1ChatGroupMember _memberApi;private readonly IFeishuTenantV1Message _messageApi;private readonly ILoggerFeishuChatGroupService _logger;public FeishuChatGroupService(IFeishuTenantV1ChatGroup chatGroupApi,IFeishuTenantV1ChatGroupMember memberApi,IFeishuTenantV1Message messageApi,ILoggerFeishuChatGroupService logger){_chatGroupApi chatGroupApi;_memberApi memberApi;_messageApi messageApi;_logger logger;}}3. 第一步获取 Tenant Access TokenMudFeishu 内置了自动令牌管理但我们可以展示手动获取的过程/// summary/// 获取飞书租户访问令牌手动实现示例/// /summarypublic async Taskstring GetTenantAccessTokenAsync(){try{// Mud.Feishu 会自动处理 Token 获取和刷新// 这里仅展示原理实际使用时直接调用 API 即可_logger.LogInformation(正在获取飞书访问令牌...);// 实际使用中Token 会自动管理无需手动获取return Mud.Feishu自动管理的Token;}catch (Exception ex){_logger.LogError(ex, 获取飞书访问令牌失败);throw new FeishuException(Token获取失败, -1, ex.Message);}} 技术要点Mud.Feishu 内置 Token 管理包括获取、缓存、刷新逻辑。4. 第二步实现群组操作a. 创建群聊此方法实现了飞书群组的完整创建流程主要操作包括构造群组创建请求设置群组基本信息名称、描述配置群组类型和权限私有群组、免审批加入添加初始成员列表支持批量邀请调用飞书API执行群组创建处理创建结果包含错误检查和异常处理返回创建成功的群组ID供后续操作使用/// summary/// 创建新的飞书群组/// /summary/// param namegroupName群组名称/param/// param namedescription群组描述/param/// param namememberIds初始成员ID列表/param/// returns创建结果包含群组ID/returnspublic async Taskstring CreateChatAsync(string groupName, string description, string[] memberIds){try{_logger.LogInformation(开始创建群组: {GroupName}, groupName);var request new CreateChatRequest{Name groupName,Description description,UserIdList memberIds,GroupMessageType chat, // 对话消息ChatMode group, // 群组模式ChatType private, // 私有群组JoinMessageVisibility all_members, // 入群消息所有人可见LeaveMessageVisibility all_members, // 退群消息所有人可见MembershipApproval no_approval_required, // 无需审批加入EditPermission all_members, // 所有人可编辑AddMemberPermission all_members, // 所有人可添加成员ShareCardPermission all_members // 所有人可分享名片};var result await _chatGroupApi.CreateChatGroupAsync(request);if (result null || result.Code ! 0){_logger.LogError(创建群组失败: {Error}, result?.Msg ?? 未知错误);throw new FeishuException(创建群组失败, result?.Code ?? -1, result?.Msg ?? 未知错误);}var chatId result.Data!.ChatId;_logger.LogInformation(群组创建成功: {ChatId}, chatId);return chatId;}catch (FeishuException){throw; // 重新抛出飞书异常}catch (Exception ex){_logger.LogError(ex, 创建群组时发生系统异常);throw new FeishuException(系统异常, -999, ex.Message);}}b. 获取群组列表此方法实现了飞书群组列表的分页获取功能主要操作包括构造分页查询请求支持自定义页大小和分页令牌调用飞书API获取指定页面的群组列表数据处理API响应包含错误检查和异常处理记录获取到的群组数量便于监控和调试返回包含群组列表和分页信息的完整结果支持继续分页查询可用于群组数据的批量处理/// summary/// 获取群组列表/// /summary/// param namepageSize页大小/param/// param namepageToken分页令牌/param/// returns群组分页列表结果/returnspublic async TaskFeishuApiPageListResultChatItemInfo GetChatListAsync(int pageSize 50, string? pageToken null){try{_logger.LogInformation(获取群组列表页大小: {PageSize}, pageSize);var result await _chatGroupApi.GetChatGroupPageListAsync(page_size: pageSize,page_token: pageToken);if (result null || result.Code ! 0){_logger.LogError(获取群组列表失败: {Error}, result?.Msg ?? 未知错误);throw new FeishuException(获取群组列表失败, result?.Code ?? -1, result?.Msg ?? 未知错误);}_logger.LogInformation(获取到 {Count} 个群组,result.Data?.Items?.Count ?? 0);return result.Data!;}catch (FeishuException){throw;}catch (Exception ex){_logger.LogError(ex, 获取群组列表时发生系统异常);throw new FeishuException(系统异常, -999, ex.Message);}}c. 获取群组详情此方法实现了获取指定群组的详细信息功能主要操作包括根据群组ID调用飞书API获取群组完整信息获取群组的所有配置属性名称、描述、权限设置等处理API响应包含错误检查和异常处理记录操作成功日志便于追踪群组访问情况返回完整的群组详情对象包含所有群组属性支持异常传播确保调用方能正确处理错误情况/// summary/// 获取群组详细信息/// /summary/// param namechatId群组ID/param/// returns群组详细信息/returnspublic async TaskGetChatGroupInfoResult GetChatDetailAsync(string chatId){try{_logger.LogInformation(获取群组详情: {ChatId}, chatId);var result await _chatGroupApi.GetChatGroupInoByIdAsync(chatId);if (result null || result.Code ! 0){_logger.LogError(获取群组详情失败: {Error}, result?.Msg ?? 未知错误);throw new FeishuException(获取群组详情失败, result?.Code ?? -1, result?.Msg ?? 未知错误);}_logger.LogInformation(获取群组详情成功: {GroupName}, result.Data?.Name);return result.Data!;}catch (FeishuException){throw;}catch (Exception ex){_logger.LogError(ex, 获取群组详情时发生系统异常);throw new FeishuException(系统异常, -999, ex.Message);}}d. 更新群组信息此方法实现了群组信息的动态更新功能主要操作包括构造群组更新请求支持修改群组名称和描述设置群组模式和相关权限保持群组类型一致性调用飞书API执行群组信息更新操作处理更新结果包含错误检查和异常处理记录更新操作日志便于审计和追踪返回布尔值指示更新操作是否成功完成/// summary/// 更新群组信息/// /summary/// param namechatId群组ID/param/// param namenewName新的群组名称/param/// param namenewDescription新的群组描述/param/// returns更新结果/returnspublic async Taskbool UpdateChatAsync(string chatId, string newName, string newDescription){try{_logger.LogInformation(更新群组信息: {ChatId} - {NewName}, chatId, newName);var request new UpdateChatRequest{Name newName,Description newDescription,// 保持其他设置不变ChatMode group,EditPermission all_members};var result await _chatGroupApi.UpdateChatGroupByIdAsync(chatId, request);if (result null || result.Code ! 0){_logger.LogError(更新群组失败: {Error}, result?.Msg ?? 未知错误);throw new FeishuException(更新群组失败, result?.Code ?? -1, result?.Msg ?? 未知错误);}_logger.LogInformation(群组更新成功: {ChatId}, chatId);return true;}catch (FeishuException){throw;}catch (Exception ex){_logger.LogError(ex, 更新群组时发生系统异常);throw new FeishuException(系统异常, -999, ex.Message);}}e. 添加群组成员此方法实现了批量添加成员到群组的功能主要操作包括构造批量添加成员请求支持一次添加多个用户验证成员ID列表的有效性和数量统计调用飞书API执行批量成员添加操作处理添加结果区分成功添加和失败的成员记录详细的操作日志包含成功和失败的统计信息返回包含无效ID列表的详细结果便于后续处理/// summary/// 添加成员到群组/// /summary/// param namechatId群组ID/param/// param namememberIds要添加的成员ID列表/param/// returns添加结果/returnspublic async TaskAddMemberResult AddChatMembersAsync(string chatId, string[] memberIds){try{_logger.LogInformation(向群组添加成员: {ChatId}, 成员数: {Count},chatId, memberIds.Length);var request new MembersRequest{MemberIdList memberIds};var result await _memberApi.AddMemberAsync(request);if (result null || result.Code ! 0){_logger.LogError(添加群成员失败: {Error}, result?.Msg ?? 未知错误);throw new FeishuException(添加群成员失败, result?.Code ?? -1, result?.Msg ?? 未知错误);}_logger.LogInformation(成功添加 {SuccessCount} 个成员失败 {FailedCount} 个,memberIds.Length - (result.Data?.InvalidIdList?.Count ?? 0),result.Data?.InvalidIdList?.Count ?? 0);return result.Data!;}catch (FeishuException){throw;}catch (Exception ex){_logger.LogError(ex, 添加群成员时发生系统异常);throw new FeishuException(系统异常, -999, ex.Message);}}f. 解散群组此方法实现了永久解散群组的功能主要操作包括根据群组ID调用飞书API执行群组解散操作注意此操作不可逆解散后群组将永久删除处理解散结果包含错误检查和异常处理记录关键操作日志便于审计和追踪解散行为返回布尔值指示解散操作是否成功完成确保只有有权限的用户才能执行此敏感操作/// summary/// 解散群组/// /summary/// param namechatId要解散的群组ID/param/// returns操作结果/returnspublic async Taskbool DeleteChatAsync(string chatId){try{_logger.LogInformation(解散群组: {ChatId}, chatId);var result await _chatGroupApi.DeleteChatGroupAsync(chatId);if (result null || result.Code ! 0){_logger.LogError(解散群组失败: {Error}, result?.Msg ?? 未知错误);throw new FeishuException(解散群组失败, result?.Code ?? -1, result?.Msg ?? 未知错误);}_logger.LogInformation(群组解散成功: {ChatId}, chatId);return true;}catch (FeishuException){throw;}catch (Exception ex){_logger.LogError(ex, 解散群组时发生系统异常);throw new FeishuException(系统异常, -999, ex.Message);}}5. 第三步在群内发送消息本部分实现了群组内消息发送的核心功能包括文本消息发送支持纯文本内容的群组消息推送富文本消息发送支持格式化的富文本内容展示消息构造与发送统一的消息请求构造和API调用流程发送结果处理完整的错误检查和异常处理机制消息ID追踪返回消息唯一标识符便于后续操作日志记录详细的发送操作日志便于监控和调试/// summary/// 在群组中发送文本消息/// /summary/// param namechatId群组ID/param/// param namecontent消息内容/param/// returns消息发送结果/returnspublic async Taskstring SendTextMessageAsync(string chatId, string content){try{_logger.LogInformation(发送消息到群组: {ChatId}, 内容长度: {Length},chatId, content.Length);var request new SendMessageRequest{ReceiveId chatId,MsgType text,Content new{text content}};var result await _messageApi.SendMessageAsync(request);if (result null || result.Code ! 0){_logger.LogError(发送消息失败: {Error}, result?.Msg ?? 未知错误);throw new FeishuException(发送消息失败, result?.Code ?? -1, result?.Msg ?? 未知错误);}var messageId result.Data!.MessageId;_logger.LogInformation(消息发送成功: {MessageId}, messageId);return messageId;}catch (FeishuException){throw;}catch (Exception ex){_logger.LogError(ex, 发送消息时发生系统异常);throw new FeishuException(系统异常, -999, ex.Message);}}/// summary/// 在群组中发送富文本消息////// 富文本消息特点支持格式化内容展示包含标题、段落、换行等排版元素/// 适用于通知公告、报告总结等需要结构化展示的场景/// /summary/// param namechatId群组ID/param/// param nametitle消息标题/param/// param namecontent富文本内容/param/// returns消息发送结果/returnspublic async Taskstring SendRichMessageAsync(string chatId, string title, string content){try{_logger.LogInformation(发送富文本消息到群组: {ChatId}, chatId);var richTextContent new ListRichTextElement{new RichTextElement{Tag text,Text $ {title}\n\n{content}}};var request new SendMessageRequest{ReceiveId chatId,MsgType post,Content new{post richTextContent}};var result await _messageApi.SendMessageAsync(request);if (result null || result.Code ! 0){_logger.LogError(发送富文本消息失败: {Error}, result?.Msg ?? 未知错误);throw new FeishuException(发送富文本消息失败, result?.Code ?? -1, result?.Msg ?? 未知错误);}var messageId result.Data!.MessageId;_logger.LogInformation(富文本消息发送成功: {MessageId}, messageId);return messageId;}catch (FeishuException){throw;}catch (Exception ex){_logger.LogError(ex, 发送富文本消息时发生系统异常);throw new FeishuException(系统异常, -999, ex.Message);}}完整代码示例与演示控制器实现创建 FeishuGroupController.cs 来演示完整业务流程using Microsoft.AspNetCore.Mvc;using Mud.Feishu;/// summary/// 飞书群组管理控制器/// /summary[ApiController][Route(api/[controller])]public class FeishuGroupController : ControllerBase{private readonly FeishuChatGroupService _chatGroupService;private readonly ILoggerFeishuGroupController _logger;public FeishuGroupController(FeishuChatGroupService chatGroupService,ILoggerFeishuGroupController logger){_chatGroupService chatGroupService;_logger logger;}/// summary/// 创建项目群组并添加成员然后发送欢迎消息/// /summary[HttpPost(create-project-group)]public async TaskIActionResult CreateProjectGroup([FromBody] CreateProjectGroupRequest request){try{_logger.LogInformation(开始创建项目群组: {ProjectName}, request.ProjectName);// 第一步创建群组var chatId await _chatGroupService.CreateChatAsync(${request.ProjectName}项目群,$这是 {request.ProjectName} 项目的专用沟通群组用于项目进展同步和团队协作。,request.MemberIds);// 第二步等待片刻确保群组创建完成await Task.Delay(2000);// 第三步发送欢迎消息var welcomeMessage $✅ 项目群组创建完成 项目信息• 项目名称{request.ProjectName}• 项目负责人{request.ProjectManager}• 创建时间{DateTime.Now:yyyy-MM-dd HH:mm:ss} 群组成员• 初始成员{request.MemberIds.Length} 人• 群组ID{chatId} 群组用途技术团队在此群组处理• 项目进度同步• 技术问题讨论• 资源协调• 资料分享祝项目顺利推进;var messageId await _chatGroupService.SendRichMessageAsync(chatId,项目群组创建成功,welcomeMessage);return Ok(new{success true,data new{chatId chatId,messageId messageId,projectName request.ProjectName,memberCount request.MemberIds.Length}});}catch (FeishuException ex){_logger.LogError(ex, 创建项目群组失败: {ErrorCode} - {Message},ex.ErrorCode, ex.Message);return BadRequest(new{success false,error ex.Message,errorCode ex.ErrorCode});}catch (Exception ex){_logger.LogError(ex, 创建项目群组时发生系统异常);return StatusCode(500, new{success false,error 系统内部错误});}}/// summary/// 获取群组列表/// /summary[HttpGet(groups)]public async TaskIActionResult GetGroups([FromQuery] int pageSize 20, [FromQuery] string? pageToken null){try{var result await _chatGroupService.GetChatListAsync(pageSize, pageToken);return Ok(new{success true,data new{items result.Items,pageToken result.PageToken,hasMore !string.IsNullOrEmpty(result.PageToken)}});}catch (Exception ex){_logger.LogError(ex, 获取群组列表失败);return StatusCode(500, new{success false,error 获取群组列表失败});}}/// summary/// 向指定群组发送系统通知/// /summary[HttpPost(send-notification)]public async TaskIActionResult SendNotification([FromBody] SendNotificationRequest request){try{var message $ 系统通知{request.Title}{request.Content}---发送时间{DateTime.Now:yyyy-MM-dd HH:mm:ss}发送者系统管理员;var messageId await _chatGroupService.SendRichMessageAsync(request.ChatId,系统通知,message);return Ok(new{success true,messageId messageId,timestamp DateTime.Now});}catch (Exception ex){_logger.LogError(ex, 发送系统通知失败);return StatusCode(500, new{success false,error 发送通知失败});}}}/// summary/// 创建项目群组请求模型/// /summarypublic class CreateProjectGroupRequest{public string ProjectName { get; set; } string.Empty;public string ProjectManager { get; set; } string.Empty;public string[] MemberIds { get; set; } Array.Emptystring();}/// summary/// 发送通知请求模型/// /summarypublic class SendNotificationRequest{public string ChatId { get; set; } string.Empty;public string Title { get; set; } string.Empty;public string Content { get; set; } string.Empty;}完整业务流程演示/// summary/// 程序入口 - 演示完整的群组管理流程/// /summarypublic class Program{public static async Task Main(string[] args){// 创建服务容器var services new ServiceCollection();// 配置日志services.AddLogging(builder {builder.AddConsole();builder.SetMinimumLevel(LogLevel.Information);});// 配置内存中的配置var configuration new ConfigurationBuilder().AddInMemoryCollection(new[]{new KeyValuePairstring, string(Feishu:AppId, your_app_id),new KeyValuePairstring, string(Feishu:AppSecret, your_app_secret),new KeyValuePairstring, string(Feishu:BaseUrl, https://open.feishu.cn)}).Build();// 注册飞书服务services.AddFeishuApiService(configuration);// 添加我们的群组管理服务services.AddSingletonFeishuChatGroupService();var serviceProvider services.BuildServiceProvider();var chatGroupService serviceProvider.GetRequiredServiceFeishuChatGroupService();try{