阳光电源二面(已挂)
- 轮次
- 二面
- 结果
- 已挂
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
- 实习中的技术难点在哪里?
- Skills 中的鉴权安全方面是如何做的?
- JWT 的具体逻辑和验证流程是怎样的?
- 状态变更的一致性如何保障?
- Canal 如何保障顺序消费?
《参考解析》
JWT 的结构与验证流程要答成一个完整闭环。JWT 由三段 Base64URL 编码用点拼接:Header(alg 与 typ)、Payload(iss、sub、exp、iat 等标准声明加业务声明)、Signature。签发方用密钥对 base64url(header) + "." + base64url(payload) 做签名(HS256 是对称 HMAC,RS256/ES256 是非对称,公钥验签、私钥签发,更适合多服务共享验证)。验证方的流程是:解析三段 → 校验算法白名单(必须显式指定允许的算法,否则会中 alg: none 或 HMAC/RSA 混淆这类经典漏洞)→ 用密钥验签 → 校验 exp/nbf/iss/aud → 取出 sub 等信息做后续授权。要主动说出 JWT 的两个先天短板:① 无法主动失效——签出去的 token 在过期前一直有效,所以要么把有效期设短(分钟级)配 refresh token,要么维护吊销名单(Redis 黑名单或版本号),后者等于又引入了服务端状态;② payload 只是编码不是加密,谁都能解开,绝不能放手机号、身份证这类敏感信息。存放位置上,浏览器端用 HttpOnly + Secure + SameSite 的 Cookie 比 localStorage 更抗 XSS,但要额外防 CSRF(用 SameSite=Lax/Strict 或双提交 CSRF token)。这一题的加分项是能说出「JWT 适合无状态的服务间调用和短时凭证,不适合当会话的唯一载体」。
鉴权安全设计通常按「认证 → 授权 → 审计」三层回答。认证解决「你是谁」:密码用 bcrypt/argon2 加盐哈希存储、登录失败次数限制与验证码、敏感操作二次验证;服务间用 mTLS 或签名。授权解决「你能做什么」:RBAC(用户-角色-权限)或 ABAC 做细粒度控制,接口层统一拦截而不是每个 handler 自己判断,避免漏判;对象级权限尤其要在查询条件里带上归属(WHERE owner_id = currentUser),否则容易出越权(IDOR)。审计解决「你做了什么」:关键操作落结构化日志,含操作者、时间、参数摘要、结果。工程上的常见加固还有:最小权限原则给密钥和数据库账号,密钥走 KMS/Secret 管理而不是硬编码,出网做白名单,内部接口也要鉴权(别假设内网可信)。
Canal 保证顺序消费要讲到 Canal 本身的语义和消费端的配合。Canal 伪装成 MySQL 从库,向主库发 dump 请求拿 binlog。MySQL 的 binlog 在单个实例内是按事务提交顺序严格有序的,所以只要客户端不并发处理同一个 canal instance 的数据,顺序天然成立。要拆的是三层:① 单实例内——MySQL 有 group commit 优化,同一时刻多个事务的 binlog 会交错写入事件流,Canal 需要按事务边界(BEGIN/COMMIT)缓冲后整体分发,消费端也要按事务粒度处理,不能拆开;② 消费者侧——这是顺序被打破的常见根因:多线程消费时相同主键的消息必须路由到同一个线程(按主键哈希取模),否则同一行的两条变更会被并发处理导致乱序;跨线程用内存队列传递时也要保证同 key 入同一队列;③ 多实例/分库分表——binlog 只在单实例内有全局序,跨库之间没有顺序保证,涉及跨库的同一条业务数据要靠业务键收敛到同一实例,或引入全局序号(如单点的发号器、按业务键做一致性哈希),消费端再按键做全局有序处理。实际组合拳是「Canal 推送 → MQ(按 canal instance 或业务主键选分区)→ 消费端单分区单线程或按 key 哈希到线程」。必须补一句可靠性:Canal 的 ack 要放在业务处理成功之后,失败要能重放,所以消费端必须幂等(按 binlog 位点或业务版本号去重),否则顺序解决了也会因重放产生重复状态。
状态变更的一致性先分清问题类型再给方案:单库单表用事务(ACID)就够;跨服务/跨库的分布式场景要在 2PC(强一致但性能差、有协调者单点)、TCC(业务补偿,Try-Confirm-Cancel)、Saga(长事务补偿)、本地消息表/事务消息(最终一致,最常用)之间取舍。方法论上记住「一锁二判三更新」:更新前用乐观锁版本号或状态机做前置判断(UPDATE ... SET status='PAID' WHERE id=? AND status='PENDING'),受影响行数为 0 就说明状态已被改过、直接返回,这是最简单有效的幂等手段。对外部调用的场景用「先落本地事务 + 本地消息表,再由投递任务发出去重试」保证不丢;下游必须幂等,用业务唯一键做去重表。避免的方案是「双写」——同时写库和写缓存/写两个库,中间任意一步失败都会不一致,宁可改成基于 binlog 或消息的异步派生。答这题时把「一致性要求是什么级别、能容忍多长时间的延迟」先问清楚再给方案,比直接甩技术名词得分高。
**「实习中的技术难点」**建议固定用 STAR 变体:背景是什么 → 具体卡在哪个技术点 → 你试过哪些方案、为什么否掉 → 最终怎么解决 → 结果怎么量化。难点要挑「有非显然取舍」的那种(比如一致性 vs 性能、顺序 vs 吞吐),而不是「这个功能以前没人做过」。如果确实没有硬难点,可以讲一次排查过程:现象、初判、怎么用日志/指标缩小范围、根因、以及事后补的防护——排查类故事反而更容易讲出技术密度。