十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

在Spring Cloud Gateway上实现RBAC权限控制

在Spring Cloud Gateway上实现RBAC权限控制 一、需求背景在 Spring Cloud Gateway 上实现 RBAC 权限控制两种角色member会员、admin管理员JWT 中的roleclaim 区分角色白名单路径写在application.yml中不查库sys_permission表雪花 ID存储路由与所需角色的映射Gateway 每 60 秒从数据库刷新一次权限配置二、完整实现过程Step 1搭建 Gateway 权限刷新机制做法Gateway 通过 HTTP 调用 users 服务获取权限配置而不是直接连数据库Gateway 是 WebFlux无法使用 MyBatis 的阻塞 SqlSession。新建GatewayConfigRefresher启动时执行一次 每 60 秒定时刷新调用lb://users/sysPermission/listEnabled获取所有status1的权限路由将结果写入SecurityRouteProperties.permissionsScheduled(fixedRate60000)publicvoidrefreshPermissions(){List?rawListwebClientBuilder.build().get().uri(lb://users/sysPermission/listEnabled).retrieve().bodyToFlux(Map.class).collectList().block();// 写入 securityRouteProperties.getPermissions()}Step 2SecurityRouteProperties配置类gateway:whitelist:-path:/user/admin/loginmethod:*-path:/user/member/loginmethod:*# ... 其他白名单配置类包含whitelist白名单路径登录、验证码、公开查询等permissions权限路由需要角色才能访问的路径Step 3JwtGlobalFilterorder -100职责JWT 解析 白名单放行 用户信息注入白名单路径直接放行无 token 或 token 无效 → 返回 401解析 JWT将mno、nickname、ano、aname、role注入到请求头X-User-Mno、X-User-Role等role为空时会员默认member管理员默认adminStep 4AuthorizationGlobalFilterorder -98职责基于角色的访问控制遍历securityRouteProperties.getPermissions()路径匹配上后检查requiredRoleany有登录X-User-Role不为null就放行member/admin精确匹配角色不匹配 → 返回 403未匹配到任何权限路由 → 放行Step 5users 服务提供权限查询接口SysPermissionController.listEnabled()GetMapping(/listEnabled)publicListSysPermissionlistEnabled(){returnsysPermissionMapper.selectList(newLambdaQueryWrapperSysPermission().eq(SysPermission::getStatus,1));}Step 6sys_permission表结构字段说明id雪花 IDpath路由路径如/production/pf/addrequired_role需要的角色admin/member/anystatus0禁用1启用describtion描述ctime/utime创建/更新时间三、遇到的问题及解决问题 1MyBatis 字段映射错误500java.sql.SQLSyntaxErrorException:Unknowncolumn requiredRole in field list现象Gateway 调用/sysPermission/listEnabled返回 500日志显示 SQL 错误Unknown column requiredRole in field list原因SysPermission实体类的requiredRole字段没有标注TableField(required_role)MyBatis 按驼峰生成 SQL但数据库列名是下划线required_role解决TableField(required_role)privateStringrequiredRole;问题 2SecurityRoutePropertiesBean 未注册FieldsecurityRouteProperties incom.zy.config.GatewayConfigRefresherrequired a bean of type com.zy.configs.SecurityRouteProperties that could not be found.现象GatewayConfigRefresher注入SecurityRouteProperties时为null原因Spring Boot 3 下EnableConfigurationProperties必须指定类才能注册 Bean解决EnableConfigurationProperties(com.zy.configs.SecurityRouteProperties.class)publicclassGatewayApp{}问题 3Gateway 无法直接使用 MyBatis现象Gateway 是 WebFlux响应式MyBatis 需要阻塞型SqlSession无法兼容解决Gateway 不直连数据库改为每 60 秒通过 WebClient HTTP 调用 users 服务的/sysPermission/listEnabled接口获取权限配置问题 4AuthorizationGlobalFilter.writeForbidden抛 NPEjava.lang.NullPointerException:nullat java.base/java.util.ImmutableCollections$MapN.init(...)atcom.zy.filter.AuthorizationGlobalFilter.writeForbidden(...)现象登录接口返回 500NullPointerException发生在Map.of()行原因Map.of()不接受null值参数虽然ResultEum枚举值本身正常但某处可能产生了空实例解决改用HashMapMapString,Objectbodynewjava.util.HashMap();body.put(code,542);body.put(msg,权限不足);body.put(data,null);问题 5AuthorizationGlobalFilter未检查白名单现象/user/admin/login在白名单中但仍然被拦截返回 403原因AuthorizationGlobalFilter只检查权限路由没有跳过白名单逻辑。当JwtGlobalFilter校验 token 失败时请求仍然进入了AuthorizationGlobalFilter解决在AuthorizationGlobalFilter.filter()开头加白名单判断if(securityRouteProperties.isWhitelisted(path,method)){returnchain.filter(exchange);}问题 6Gateway 中错误引入了 MyBatis MapperInvalidbean definitionwithnamesysPermissionMapper defined in file...PropertysqlSessionFactory or sqlSessionTemplate are required现象Gateway 模块里出现了SysPermissionMapper.java不应该存在原因开发过程中误创建解决删除snacknet156-gateWay/src/main/java/com/zy/web/mapper/SysPermissionMapper.java问题 7前端 ajax 请求未携带 JWT Token现象添加商品、添加类型等接口返回 401原因add.html和type.html的$.ajax()调用没有带Authorizationheader登录后 token 存在localStorage.adminToken中但从未读取使用解决在 ajax 中添加beforeSendbeforeSend:function(xhr){xhr.setRequestHeader(Authorization,Bearer localStorage.getItem(adminToken));}涉及文件D:\ideaIC\navy\static\back\manager\add.htmlD:\ideaIC\navy\static\back\manager\type.html问题 8orders 服务 500 但无日志现象PUT /order/adminUpdateStatus返回 500但 orders 服务控制台无输出原因GlobalExceptionHandle用ex.getCause()打印异常cause为null时只输出null无法定位问题解决改为ex.printStackTrace() ex.getMessage()最终定位到是NoResourceFoundExceptionController 未加载完全重启后恢复四、最终架构图浏览器请求 ↓ Nginx (端口80) ↓ Spring Cloud Gateway (端口11004) ↓ ① JwtGlobalFilter (order-100) - 读取 Authorization header - 白名单路径直接放行 - 解析 JWT注入 X-User-Role 等请求头 ↓ ② AuthorizationGlobalFilter (order-98) - 白名单路径直接放行 - 根据 sys_permission 表配置检查角色 - 匹配返回 403 ↓ 路由到具体微服务users / productions / orders 等 ↓ GatewayConfigRefresher后台每60秒执行一次 调用 lb://users/sysPermission/listEnabled 刷新 securityRouteProperties.permissions五、数据库sys_permission表示例idpathrequired_rolestatusdescribtion1/production/pf/addadmin1管理员添加商品2/production/type/addadmin1管理员添加类型3/order/adminUpdateStatusadmin1管理员更新订单状态4/order/listmember1会员查看订单5/production/pf/findsany1公开浏览商品
返回列表