🎯 权限管理组件执行流程详解

🏗️ 组件架构图

┌─────────────────────────────────────────────────────────────┐
│                    HTTP请求                                  │
└─────────────────────┬───────────────────────────────────────┘│
┌─────────────────────▼───────────────────────────────────────┐
│              SecureController                               │
│  - 获取当前用户ID                                            │
│  - 统一错误处理                                              │
└─────────────────────┬───────────────────────────────────────┘│
┌─────────────────────▼───────────────────────────────────────┐
│              SecurityService (接口)                         │
│  - 业务语义化的权限检查方法                                   │
│  - canAccessUser(), canCreateProcurement()等                │
└─────────────────────┬───────────────────────────────────────┘│
┌─────────────────────▼───────────────────────────────────────┐
│              SecurityServiceImpl (实现)                     │
│  - 构建SecurityContext                                      │
│  - 调用PermissionEngine                                     │
│  - 异常处理                                                  │
└─────────────────────┬───────────────────────────────────────┘│
┌─────────────────────▼───────────────────────────────────────┐
│              PermissionEngine (接口)                        │
│  - 权限计算的抽象接口                                        │
│  - checkPermission()方法                                   │
└─────────────────────┬───────────────────────────────────────┘│
┌─────────────────────▼───────────────────────────────────────┐
│              RoleBasedPermissionEngine (实现)               │
│  - 具体的权限计算逻辑                                        │
│  - 基于角色的权限规则                                        │
└─────────────────────────────────────────────────────────────┘

🔄 完整执行流程

场景:BUYER用户想查看自己的信息

让我们跟踪一个完整的请求:GET /api/v1/users/123

第1步:SecureController - 安全控制器基类

// 任何继承SecureController的Controller
@RestController
class UserController(currentUserService: CurrentUserService,private val securityService: SecurityService  // 👈 注入SecurityService接口
) : SecureController(currentUserService) {@GetMapping("/api/v1/users/{userId}")fun getUserInfo(@PathVariable userId: String): ResponseEntity<UserInfo> {// 1.1 获取当前用户ID(来自SecureController基类)val currentUserId = getCurrentUserId()  // 返回 "123"// 1.2 调用SecurityService进行权限检查if (!securityService.canAccessUser(userId)) {  // 👈 调用接口方法return createForbiddenResponse()}// 1.3 执行业务逻辑val userInfo = userService.getUserInfo(userId)return ResponseEntity.ok(userInfo)}
}

SecureController说:“我获取到当前用户ID是123,现在要检查是否可以访问用户123的信息,让我问问SecurityService!”

第2步:SecurityService - 权限服务接口

// SecurityService.kt - 接口定义
interface SecurityService {/*** 是否可以访问用户信息*/fun canAccessUser(userId: String?): Boolean  // 👈 业务语义化的方法/*** 是否可以创建采购需求*/fun canCreateProcurement(): Boolean// ... 其他业务权限方法
}

SecurityService接口说:“我定义了所有业务权限检查的方法,具体实现由SecurityServiceImpl来完成!”

第3步:SecurityServiceImpl - 权限服务实现

// SecurityServiceImpl.kt - 具体实现
@Service("securityService")
class SecurityServiceImpl(private val currentUserService: CurrentUserService,private val permissionEngine: PermissionEngine  // 👈 注入PermissionEngine接口
) : SecurityService {override fun canAccessUser(userId: String?): Boolean {// 3.1 调用通用权限检查方法return safeCheckPermission("user", "read", userId)  // 👈 转换为通用格式}private fun safeCheckPermission(resource: String,    // "user"action: String,      // "read"targetId: String?    // "123"): Boolean {return try {// 3.2 构建安全上下文val context = getCurrentSecurityContext() ?: return false// 3.3 调用权限引擎进行具体检查permissionEngine.checkPermission(context, resource, action, targetId)  // 👈 委托给引擎} catch (e: Exception) {false  // 异常时拒绝访问}}private fun getCurrentSecurityContext(): SecurityContext? {return try {val currentUserResult = currentUserService.getCurrentUser()if (!currentUserResult.isSuccess) return nullval currentUser = currentUserResult.data!!val role = Role.fromCode(currentUser.role.name) ?: return null// 3.4 创建SecurityContext对象SecurityContext(userId = currentUser.id.value.toString(),  // "123"userRole = role,                           // Role.BUYERuserStatus = currentUser.status.name       // "ACTIVE")} catch (e: Exception) {null}}
}

SecurityServiceImpl说:“我收到canAccessUser请求,让我构建安全上下文,然后调用权限引擎来做具体判断!”

第4步:PermissionEngine - 权限引擎接口

// PermissionEngine.kt - 权限计算引擎接口
interface PermissionEngine {/*** 检查权限*/fun checkPermission(context: SecurityContext,  // 安全上下文resource: String,          // 资源类型action: String,           // 操作类型targetId: String? = null  // 目标ID): Booleanfun getEngineVersion(): Stringfun getEngineDescription(): String
}

PermissionEngine接口说:“我定义了权限计算的标准接口,具体的计算逻辑由不同的实现来完成!”

第5步:RoleBasedPermissionEngine - 基于角色的权限引擎

// RoleBasedPermissionEngine.kt - 具体的权限计算实现
@Component
class RoleBasedPermissionEngine : PermissionEngine {override fun checkPermission(context: SecurityContext,  // userId="123", userRole=BUYER, userStatus="ACTIVE"resource: String,          // "user"action: String,           // "read"targetId: String?         // "123"): Boolean {// 5.1 基础检查:非活跃用户无权限if (!context.isActive()) {return false}// 5.2 管理员检查:管理员拥有所有权限if (context.isAdmin()) {return true}// 5.3 根据角色进行具体权限检查return when (context.userRole) {Role.BUYER -> checkBuyerPermission(context, resource, action, targetId)  // 👈 BUYER角色Role.SELLER -> checkSellerPermission(context, resource, action, targetId)Role.FORWARDER -> checkForwarderPermission(context, resource, action, targetId)Role.SALES -> checkSalesPermission(context, resource, action, targetId)Role.SUPPORT -> checkSupportPermission(context, resource, action, targetId)Role.ADMIN -> true  // 已在上面处理}}private fun checkBuyerPermission(context: SecurityContext,  // userId="123", userRole=BUYERresource: String,          // "user"action: String,           // "read"targetId: String?         // "123"): Boolean {return when (resource) {"user" -> when (action) {"read" -> context.canAccessUserData(targetId)  // 👈 检查是否可以访问用户数据"write" -> context.canAccessUserData(targetId)else -> false}"procurement" -> when (action) {"create" -> true  // BUYER可以创建采购需求"read" -> true    // BUYER可以查看采购需求"write" -> canAccessOwnResource(context, targetId)  // 只能修改自己的else -> false}// ... 其他资源else -> false}}
}

RoleBasedPermissionEngine说:“让我分析…用户123是BUYER角色,想读取用户123的信息,这是访问自己的数据,允许!”

🎭 各组件的具体职责

1. SecureController(安全控制器基类)

// 职责:提供安全基础设施
abstract class SecureController {protected fun getCurrentUserId(): String        // 获取当前用户IDprotected fun resolveUserId(String?): String    // 解析目标用户IDprotected fun createForbiddenResponse(): ResponseEntity  // 创建403响应
}

角色:安全基础设施提供者
工作:获取用户身份、统一错误处理

2. SecurityService(权限服务接口)

// 职责:定义业务权限检查接口
interface SecurityService {fun canAccessUser(userId: String?): Boolean      // 业务语义化fun canCreateProcurement(): Boolean              // 业务语义化fun canModifyOrder(orderId: String?): Boolean    // 业务语义化
}

角色:业务权限接口定义者
工作:提供清晰的业务语义化权限检查方法

3. SecurityServiceImpl(权限服务实现)

// 职责:协调和转换
@Service
class SecurityServiceImpl {private fun safeCheckPermission(resource, action, targetId): Boolean  // 转换格式private fun getCurrentSecurityContext(): SecurityContext             // 构建上下文
}

角色:协调者和转换器
工作

  • 将业务方法转换为通用权限检查
  • 构建SecurityContext
  • 异常处理
  • 委托给权限引擎

4. PermissionEngine(权限引擎接口)

// 职责:定义权限计算接口
interface PermissionEngine {fun checkPermission(context, resource, action, targetId): Boolean  // 通用权限检查
}

角色:权限计算接口定义者
工作:定义标准的权限计算接口,支持可插拔实现

5. RoleBasedPermissionEngine(基于角色的权限引擎)

// 职责:具体的权限计算逻辑
@Component
class RoleBasedPermissionEngine {private fun checkBuyerPermission(...): Boolean    // BUYER角色权限private fun checkSellerPermission(...): Boolean   // SELLER角色权限private fun checkAdminPermission(...): Boolean    // ADMIN角色权限
}

角色:权限计算执行者
工作

  • 执行具体的权限计算逻辑
  • 基于角色的权限规则
  • 资源和操作的细粒度控制

🔄 数据流转过程

// 数据在各组件间的流转
HTTP请求: GET /api/v1/users/123↓
SecureController: getCurrentUserId()"123"↓
SecurityService: canAccessUser("123")↓
SecurityServiceImpl: safeCheckPermission("user", "read", "123")↓
SecurityServiceImpl: getCurrentSecurityContext()SecurityContext(userId="123", role=BUYER)↓
PermissionEngine: checkPermission(context, "user", "read", "123")↓
RoleBasedPermissionEngine: checkBuyerPermission(context, "user", "read", "123")↓
SecurityContext: canAccessUserData("123")true (同一用户)↓
返回结果: true → 允许访问

🎯 为什么要这样设计?

1. 单一职责原则

  • SecureController:只负责安全基础设施
  • SecurityService:只负责业务权限接口
  • SecurityServiceImpl:只负责协调和转换
  • PermissionEngine:只负责权限计算接口
  • RoleBasedPermissionEngine:只负责具体权限逻辑

2. 开闭原则

// 可以轻松添加新的权限引擎实现
@Component
class RuleBasedPermissionEngine : PermissionEngine {// 基于规则的权限计算
}@Component  
class DatabasePermissionEngine : PermissionEngine {// 基于数据库配置的权限计算
}

3. 依赖倒置原则

// 高层模块依赖抽象,不依赖具体实现
class SecurityServiceImpl(private val permissionEngine: PermissionEngine  // 依赖接口,不是具体实现
)

4. 接口隔离原则

// 不同层次的接口,职责明确
interface SecurityService {        // 业务层接口fun canAccessUser(String?): Boolean
}interface PermissionEngine {       // 权限计算接口fun checkPermission(...): Boolean
}

🎊 总结

这5个组件形成了一个完整的权限管理体系

  1. SecureController = 安全门卫:检查身份,统一处理
  2. SecurityService = 业务顾问:提供业务语义化的权限检查
  3. SecurityServiceImpl = 协调员:转换格式,构建上下文,处理异常
  4. PermissionEngine = 权限计算标准:定义权限计算接口
  5. RoleBasedPermissionEngine = 权限计算器:执行具体的权限计算逻辑

就像一个完整的银行业务流程

  • 门卫(SecureController):检查身份证
  • 业务顾问(SecurityService):了解业务需求
  • 业务经理(SecurityServiceImpl):准备材料,协调各部门
  • 审批标准(PermissionEngine):定义审批流程
  • 审批员(RoleBasedPermissionEngine):根据规则做最终决定

这种设计让权限管理既灵活又可维护! 🎉


ps:
好问题!让我详细解释第4点和第5点的区别:

🤔 第4点和第5点的区别

📋 简单对比

步骤组件职责具体工作
第4点SecurityService权限服务调用权限引擎,但不做具体判断
第5点RoleBasedPermissionEngine权限引擎执行具体的权限计算逻辑

🔍 详细解析

第4点:SecurityService - 权限服务(中介者)
// SecurityServiceImpl.kt
@Service
class SecurityServiceImpl : SecurityService {override fun canAccessUser(userId: String?): Boolean {// 👈 这里只是调用权限引擎,自己不做判断return safeCheckPermission("user", "read", userId)}private fun safeCheckPermission(resource: String, action: String, targetId: String?): Boolean {return try {// 1. 获取当前用户的安全上下文val context = getCurrentSecurityContext() ?: return false// 2. 调用权限引擎进行检查(重点:这里只是调用,不判断)permissionEngine.checkPermission(context, resource, action, targetId)} catch (e: Exception) {false  // 出错就拒绝访问}}
}

SecurityService说:“我收到了权限检查请求,让我准备好用户信息,然后交给权限引擎去判断!”

SecurityService的工作

  • 🔄 转换参数:将业务参数转换为权限引擎需要的格式
  • 🛡️ 异常处理:捕获异常,确保系统安全
  • 📋 获取上下文:准备当前用户的安全信息
  • 📞 委托调用:把实际判断工作交给权限引擎
第5点:RoleBasedPermissionEngine - 权限引擎(实际判断者)
// RoleBasedPermissionEngine.kt
class RoleBasedPermissionEngine : PermissionEngine {override fun checkPermission(context: SecurityContext,  // 用户123,BUYER角色resource: String,          // "user"action: String,           // "read"targetId: String?         // "123"): Boolean {// 👈 这里才是真正的权限判断逻辑// 1. 非活跃用户无权限if (!context.isActive()) return false// 2. 管理员拥有所有权限if (context.isAdmin()) return true// 3. 根据角色检查权限return when (context.userRole) {Role.BUYER -> checkBuyerPermission(context, resource, action, targetId)// ... 其他角色}}private fun checkBuyerPermission(context: SecurityContext,resource: String,action: String,targetId: String?): Boolean {return when (resource) {"user" -> when (action) {"read" -> context.canAccessUserData(targetId)  // 👈 具体的判断逻辑else -> false}else -> false}}
}

RoleBasedPermissionEngine说:“让我仔细分析…用户123是BUYER角色,想读取用户123的信息,这是访问自己的数据,允许!”

权限引擎的工作

  • 🧠 具体判断:执行真正的权限计算逻辑
  • 📊 角色分析:根据用户角色决定权限范围
  • 🎯 资源检查:判断是否可以访问特定资源
  • ⚖️ 规则执行:应用具体的业务权限规则

🎭 用生活例子来理解

SecurityService = 银行前台接待员
  • 客户:“我想查看我的账户信息”
  • 接待员:“好的,让我帮您准备资料,然后请权限部门审核”
  • 接待员的工作
    • 收集客户信息
    • 准备审核材料
    • 联系权限部门
    • 处理异常情况
RoleBasedPermissionEngine = 银行权限审核部门
  • 审核部门:“让我看看…您是账户持有人,想查看自己的账户,符合规定,批准!”
  • 审核部门的工作
    • 分析客户身份
    • 检查权限规则
    • 做出最终决定
    • 返回审核结果

🔄 完整的调用链

// 完整的调用过程
Controller.getUserInfo(userId: "123")↓
SecurityService.canAccessUser("123")  // 👈 第4点:准备和调用↓
SecurityService.safeCheckPermission("user", "read", "123")↓
RoleBasedPermissionEngine.checkPermission(context, "user", "read", "123")  // 👈 第5点:具体判断↓
RoleBasedPermissionEngine.checkBuyerPermission(...)↓
SecurityContext.canAccessUserData("123")return true  // 允许访问

🎯 为什么要分成两层?

1. 职责分离
// SecurityService:业务接口层
fun canAccessUser(userId: String?): Boolean  // 业务语义清晰// PermissionEngine:权限计算层  
fun checkPermission(context, resource, action, targetId): Boolean  // 通用权限检查
2. 异常处理
// SecurityService负责异常处理
private fun safeCheckPermission(...): Boolean {return try {permissionEngine.checkPermission(...)  // 可能抛异常} catch (e: Exception) {false  // 统一处理异常}
}
3. 扩展性
// 可以轻松替换权限引擎
class SecurityServiceImpl(private val permissionEngine: PermissionEngine  // 可以是不同的实现
) {// RoleBasedPermissionEngine// RuleBasedPermissionEngine  // DatabasePermissionEngine
}
4. 测试友好
// 可以单独测试权限引擎
@Test
fun `BUYER角色应该可以访问自己的数据`() {val context = SecurityContext(userId = "123", userRole = Role.BUYER)val result = permissionEngine.checkPermission(context, "user", "read", "123")assertTrue(result)
}

🎊 总结

第4点和第5点的核心区别

方面SecurityService(第4点)RoleBasedPermissionEngine(第5点)
角色中介者、协调者执行者、判断者
职责准备数据、调用引擎、处理异常执行具体的权限计算逻辑
工作“我来帮你联系权限部门”“我来判断你有没有权限”
复杂度简单的转发和异常处理复杂的业务规则和权限计算
可替换性相对稳定可以有多种实现(基于角色、基于规则等)

就像餐厅点餐

  • SecurityService = 服务员:接收订单,转给厨房,处理问题
  • RoleBasedPermissionEngine = 厨师:根据菜谱制作具体的菜品

两者配合,形成了完整的权限检查流程! 🎉

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

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

相关文章

redis怎么保障双写一致性

redis做为缓存&#xff0c;mysql的数据如何与redis进行同步呢&#xff1f;&#xff08;双写一致性&#xff09;候选人&#xff1a;嗯&#xff01;就说我最近做的这个项目&#xff0c;里面有xxxx&#xff08;根据自己的简历上写&#xff09;的功能&#xff0c;需要让数据库与red…

异常值检测:孤立森林模型(IsolationForest)总结

目录一、前言二、孤立森林算法2.1 算法简介2.2 基本原理2.3 算法步骤2.4 异常分数计算方式2.5 python调用方式三、python代码示例四、小结五、参考学习一、前言 近期在研究构建寿命预测模型&#xff0c;相信很多数据人都懂建模的过程&#xff0c;其实有80%的时间都是在和数据处…

Docker容器化部署实战:Tomcat与Nginx服务配置指南

部署Tomcat搜索镜像 使用以下命令搜索可用的Tomcat镜像&#xff1a;docker search tomcat拉取镜像 拉取官方Tomcat镜像&#xff1a;docker pull tomcat创建专用目录 为Tomcat配置和数据创建专用目录&#xff1a;mkdir tomcat运行临时容器并复制配置文件 启动临时容器以复制配置…

Go语言实战案例-使用SQLite实现本地存储

在开发工具类软件、桌面应用或者移动端时&#xff0c;我们经常需要一个轻量级数据库来做 本地存储。相比 MySQL、Postgres 等服务型数据库&#xff0c;SQLite 体积小、零配置、单文件存储&#xff0c;非常适合这种场景。Go 语言通过 GORM SQLite 驱动 就能轻松实现。本文将带你…

云计算学习100天-第23天

主机192.168.88.5 安装nginx#安装编译工具&#xff0c;正则表达式依赖包&#xff0c;SSL加密依赖包 yum -y install gcc make pcre-devel openssl-devel tar -xf /root/lnmp_soft.tar.gz cd lnmp_soft/ tar -xf nginx-1.22.1.tar.gz cd nginx-1.22.1/ #指定安装路径&…

【生成树+环】题解:P3907 环的异或_图论_环_异或_搜索_算法竞赛_C++

推销洛谷博客&#xff1a;https://www.luogu.com.cn/article/znmr9iu9 Link&#xff1a;Luogu - P3907 这里默认题目中指的环都是“简单环”&#xff08;即没有“环套环”的情况&#xff09;。 众所周知&#xff0c;树是图的一种特殊情况&#xff0c;且一定无环。如果我们想…

数据库优化提速(二)排序优化之搜索大数据酒店,进销存AI—仙盟创梦IDE

在 MySQL 数据库管理中&#xff0c;排序操作对于数据的有效展示和分析至关重要。本文将以一个实际的 SQL 查询为例&#xff0c;深入探讨排序优化方案&#xff0c;并结合进销存、酒店、知识库等大数据场景&#xff0c;阐述这些优化策略的应用价值。原始SELECT 应用编号, 应用序列…

Linux之Ansible自动化运维(二)

一、ansible Playbook应用由于服务器数量很多&#xff0c;配置信息比较多&#xff0c;因此可以利用Ansible Playbook编写任务自动化与流程化脚本Playbook 由一个或多个play组成的列表&#xff0c;play的主要功能Ansible中Task定义好的角色&#xff0c;指定剧本对应的服务器组二…

ArrayList线程不安全问题及解决方案详解

问题背景在多线程编程中&#xff0c;我们经常会遇到集合类的线程安全问题。Java中的ArrayList是一个常用的集合类&#xff0c;但它不是线程安全的。当多个线程同时操作同一个ArrayList实例时&#xff0c;可能会出现各种不可预料的问题。问题演示List<String> list new A…

车辆方向数据集 - 物体检测

关于数据集 包含超过50,000 张图像中具有方向的车辆的 50,000 多万个注释。它通过同时提供车辆类别和方向来减少对方向进行分类的辅助神经网络的需求。 预训练权重 我们将继续添加在车辆方向数据集和合成车辆方向数据集上训练的各种对象检测模型。如果您需要一些特定的预训练权…

Nextcloud搭建教程:使用Docker在腾讯云服务器上自建私人云盘

更多云服务器知识&#xff0c;尽在hostol.com你那百兆光纤的宽带。你是否也曾看着自己最珍贵的家庭照片、最私密的个人文档&#xff0c;静静地躺在某个科技巨头的服务器上&#xff0c;感到过一丝丝的不安&#xff1f;你的数据&#xff0c;到底被如何“阅读”和“分析”&#xf…

【操作记录】MNN Chat Android App 构建笔记(二)

&#x1f4d2; MNN Chat Android App 构建笔记 一、背景知识MNN 简介 MNN 是阿里开源的轻量级深度学习框架&#xff0c;支持 Android / iOS / Linux / Windows。提供推理、LLM、Vision、Audio 等模块。Android App 里用到的是 Java JNI 调用 MNN 库。CMake NDK 的作用 CMake&…

如何在 Axios 中处理多个 baseURL 而不造成混乱

网罗开发&#xff08;小红书、快手、视频号同名&#xff09;大家好&#xff0c;我是 展菲&#xff0c;目前在上市企业从事人工智能项目研发管理工作&#xff0c;平时热衷于分享各种编程领域的软硬技能知识以及前沿技术&#xff0c;包括iOS、前端、Harmony OS、Java、Python等方…

AP服务发现PRS_SOMEIPSD_00255 的解析

[PRS_SOMEIPSD_00255 ] 「SOME/IP-SD头部的重启标志&#xff0c;对于重启后发出的所有报文&#xff0c;都应设置为 1&#xff0c;直至 SOME/IP头部中的会话 ID (Session-ID) 回绕并因此再次从 1 开始。在此回绕之后&#xff0c;重启标志应设置为 0。」(RS_SOMEIPSD_00006)核心含…

纯手撸一个RAG

纯手撸一个RAGRAG基本流程第一阶段&#xff1a;数据预处理&#xff08;索引&#xff09; - 构建知识库第二阶段&#xff1a;查询与生成&#xff08;推理&#xff09; - 回答问题总结Chunk介绍Chunk框架的介绍Chunk核心概念选择分块策略和框架如何选择分块框架Python代码实现第一…

视觉语言对比学习的发展史:从CLIP、BLIP、BLIP2、InstructBLIP(含MiniGPT4的详解)

前言 本文一开始是属于此文《图像生成(AI绘画)的发展史&#xff1a;从CLIP、BLIP、InstructBLIP到DALLE、DALLE 2、DALLE 3、Stable Diffusion(含ControlNet详解)》的&#xff0c;后独立成本文 第一部分 从CLIP、BLIP1、BLIP2到InstructBLIP 1.1 CLIP&#xff1a;基于对比文本…

HTTP代理与SOCKS代理的区别、应用场景与选择指南

在互联网日常使用与跨境业务中&#xff0c;HTTP代理 和 SOCKS代理 是两种常见的网络代理方式。无论是跨境电商、社交媒体账号运营、数据采集&#xff0c;还是科学访问海外资源&#xff0c;都需要选择合适的代理协议。什么是HTTP代理&#xff1f;定义HTTP代理 是基于 HTTP协议 的…

AI重塑职业教育:个性化学习计划提效率、VR实操模拟强技能,对接就业新路径

职业教育长期面临着一系列问题&#xff0c;包括“统一课程难以适配不同基础学员”、“实操反馈滞后”和“就业技能与企业需求脱节”等。随着人工智能技术的应用&#xff0c;这些传统教学模式正在发生变化。个性化技能培养得以实现&#xff0c;甚至可以提前识别学员的就业短板。…

主题配色下的背景透明度

用 CSS color-mix() 解决背景透明度的痛点 在设计卡片组件时&#xff0c;经常遇到这样的需求&#xff1a;卡片背景需要80%透明度&#xff0c;鼠标悬浮在内部某项时&#xff0c;修改背景色但保持同样的透明度。 问题场景 .card {background: rgba(59, 130, 246, 0.8); /* 蓝色80…

【Python代码】谷歌专利CSV处理函数

以下是一个重构后的高可用、可配置、低耦合的专利CSV处理函数&#xff0c;包含清晰的注释和结构&#xff1a; import csv import pandas as pd from datetime import datetime import os from typing import List, Dict, Any, Optional, Tuple import logging# 配置日志 loggin…