有网友吐槽,业务负责人娶小老婆,居然要求下面员工随份子。不交的人被暗示“不懂事”,交了的人也觉得憋屈。
这种事情表面看是职场人情,实际上暴露的是一个更危险的问题:权力没有边界。

技术团队里也一样。很多线上事故不是代码写错,而是某个人权限太大、某个服务职责太乱,最后所有人都被迫为一个错误买单。
比如一个业务负责人既能改订单规则,又能直接操作数据库,还能绕过审批发布代码。平时看起来效率很高,出问题时就是灾难。
今天聊一个真实开发中经常出现的问题:为什么权限越集中,系统越容易失控,以及 Java 系统 如何设计权限隔离。
一个接口上线后,订单金额被改了
生产环境出现异常:
09:12:31 订单服务报警
payment_amount异常增长
09:13:02 数据库监控
order_detail表 update QPS 突增
09:15:44 开发群:
“谁改了订单金额字段?”
查数据库:
select
id,
order_no,
payment_amount,
update_user,
update_time
from order_detail
where update_time > '2026-08-22 09:00:00';
结果:
id order_no payment_amount update_user
10021 A20260822001 1999 admin
10022 A20260822002 2999 admin
10023 A20260822003 4999 admin
继续查操作日志:
operator=admin
action=UPDATE_ORDER
source=后台管理系统
问题很快定位:后台系统给了一个超级管理员接口:
@PostMapping("/order/update")
public Result update(@RequestBody OrderDTO dto){
orderService.update(dto);
return Result.success();
}
代码没报错,权限也通过了,但设计本身有问题。
因为这个接口实际上允许:改金额、改状态、改商品、改用户信息。一个入口控制全部业务。这就是典型的“大老板权限模型”,所有事情都归一个人管。
权限不是越大越方便,而是风险集中
很多系统早期都会这么设计:
if(user.isAdmin()){
return true;
}
简单,开发快。但是半年后:运营需要改库存,客服需要补订单,财务需要退款。最后所有人都申请 admin。
权限表变成:
user_id role
1001 admin
1002 admin
1003 admin
1004 admin
所谓权限控制,只剩一个按钮。
线上真正需要的是:角色控制资源,资源控制动作。
用户
|
角色
|
权限
|
接口
|
业务动作
数据库设计:
create table sys_permission(
id bigint primary key,
code varchar(64),
name varchar(128)
);
create table sys_role_permission(
role_id bigint,
permission_id bigint
);
权限不要只定义一个 UPDATE_ORDER,太粗了。应该拆成:
ORDER_VIEW
ORDER_CANCEL
ORDER_REFUND
ORDER_PRICE_EDIT
因为风险完全不同。查看订单:客服可以。修改价格:运营经理可以。退款:财务可以。这才是正常系统。
高风险操作必须二次确认
很多公司有权限,但是没有控制风险。例如退款:
public void refund(Long orderId){
orderService.refund(orderId);
}
如果只判断有没有退款权限,远远不够。线上环境还应该增加:金额限制、审批、操作记录、双人确认。
例如:
public void refund(RefundCommand command){
checkPermission();
if(command.getAmount()
.compareTo(new BigDecimal("5000")) > 0){
throw new BizException("large refund require approval");
}
saveAuditLog(command);
refundService.execute(command);
}
超过5000进入审批。不是因为技术复杂,而是因为错误成本高。
数据库权限也不能给开发“一把钥匙”
很多团队还有个习惯:开发拿着 root 账号直连生产库,图个排查方便。然后某天:
update user_account
set status=0;
忘记 where。几十万用户被冻结。
数据库层 应该拆账号:
读:app_read
写:app_write
发布:deploy_user
管理员:dba_user
例如 MySQL:
create user 'order_app'
identified by 'xxxx';
grant select, insert, update
on trade.*
to 'order_app';
不要:
grant all privileges
on *.*
to 'app';
这个权限看起来省事,实际上是在给未来事故留入口。
服务之间也需要边界
微服务 架构里也经常乱套:订单服务直接调用户库,库存服务直接改订单表。最后演变成:
订单服务
|
|
用户表
|
|
库存表
谁都能改,出了问题没人知道责任。更合理的方式是:
order-service
只负责:订单状态
inventory-service
只负责:库存扣减
payment-service
只负责:支付结果
调用流程:
createOrder
|
|
payment.pay()
|
|
inventory.lock()
而不是:
orderService.updateInventory();
orderService.updatePayment();
orderService.updateUser();
一个类知道太多事情,和一个人拥有太多权力,本质问题类似。边界消失,风险就会扩散。
线上排查时,我最先看权限链
遇到异常操作,我不会一上来就看代码,而是先看:
谁操作
↓
通过什么入口
↓
拥有哪个权限
↓
调用哪个服务
↓
修改什么数据
日志至少要记录:
{
"operator": "zhangsan",
"role": "finance_manager",
"action": "REFUND",
"resource": "order_10021",
"ip": "10.20.1.15",
"traceId": "abc123"
}
没有审计日志的问题,出了事故只能猜。猜一次没事,长期靠猜,系统一定会出问题。
这也是云栈社区上大家经常讨论的话题。职场里,没人应该为一个人的私人决定被迫买单;技术系统里,也不能让整个系统为一个超级权限设计买单。权限边界做好了,很多事故根本就不会发生。