方法路由与业务鉴权
本章介绍方法路由、业务鉴权拦截器及其配置方式。tio-boot 使用 Java 8 编译,tio-boot-admin 使用 Java 21 编译;Java 版本与 Maven 组件版本是两回事。
1. 本地构建顺序
先在 t-io 根目录使用 JDK 8 执行,再在 tio-boot-admin 根目录使用 JDK 21 执行:
mvn install -Dgpg.skip=true -Dmaven.javadoc.skip=true
t-io 是包含 tio-http-common、tio-http-server、tio-boot 等模块的 reactor,相关模块应使用一致的版本并安装到本地仓库,不能只更新业务项目中的版本号。上述命令只安装到本地仓库,跳过发布签名和 Javadoc 打包,不执行 deploy。
业务工程使用 Java 21,并使 tio-boot-admin-web 依赖与本地安装的框架版本保持一致。检查依赖树,避免显式固定的旧版 tio-http-server 抢占新版本。
mvn dependency:tree -Dincludes=nexus.io
mvn test
2. 按方法注册路由
HttpRequestRouter router = TioBootServer.me().getRequestRouter();
router.get("/api/items", request -> Resps.json(request, "list"));
router.post("/api/items", request -> Resps.json(request, "created"));
router.add(HttpMethod.DELETE, "/api/items/{id}", request -> {
String id = request.getParam("id");
return Resps.json(request, id);
});
需要导入 nexus.io.tio.http.common.HttpMethod、nexus.io.tio.http.server.router.HttpRequestRouter、nexus.io.tio.http.server.util.Resps、nexus.io.tio.boot.server.TioBootServer。
- 同一路径可同时注册 GET 与 POST;重复注册同一
(method, path)会抛出IllegalArgumentException。 - 旧
add(path, handler)仍表示 ANY,重复注册仍覆盖。新接口优先于 ANY;迁移后应删除同一接口的旧 ANY 注册,避免其他方法通过兼容回退进入业务。 - 方法不支持时返回 405 和
Allow;路径不存在时返回 404。 - HEAD 优先使用显式 HEAD,其次 GET,身份策略继承选中的路由;编码器不发送内存/文件响应体。
- 自动 OPTIONS 对已知方法路由返回 204 与
Allow;显式 OPTIONS Handler 优先。CORS 预检另外由 CORS 配置处理。 - 框架生成的 405 没有业务 JSON 包装,前端必须检查 HTTP 状态,不能假定所有响应都有
code。
详细匹配与兼容规则见 分发与路由优先级。
3. 路由声明策略,拦截器执行鉴权
核心框架不内置 PUBLIC / USER / ADMIN 业务枚举。业务可以通过 metadata 声明策略:
router.add(HttpMethod.POST, "/api/items", handler,
java.util.Collections.singletonMap("app.access", "user"));
HttpRequestInterceptor 新增默认方法:
default HttpResponse doBeforeRoute(HttpRequest request, RequestLine line,
HttpResponse response, RouteMatch match) throws Exception {
return null;
}
普通 Handler 匹配成功后,match.getRoute().getMetadata() 是实际选中方法的策略。Groovy、Function、Controller 的回调中 match 为 null;这些路由继续使用既有权限配置,不能臆测它们具有 Handler 的 metadata。旧 doBeforeHandler 保持在匹配前执行,doAfterHandler 保留原有按路径规则调用的行为。
业务拦截器的职责:
- 按选中路由读取策略;对所负责的业务前缀,缺失策略应拒绝访问。
- 公开路由直接返回 null;用户路由验证用户 Token;后台路由验证管理员 Token 和后台账号权限。
- 成功后写入
TioRequestContext.setIdentity(new RequestIdentity(userId, "app-user", tenantId))。该方法同时设置兼容的request.userId。RequestIdentity位于nexus.io.tio.boot.token,也可直接使用旧setUserId。 - 失败返回明确的 401/403 响应;成功返回 null 后执行 Handler。
RequestIdentity 只保存已验证身份,不验证 Token。UserTokenInterceptor、TokenPredicate 仍可用于已有的匹配前鉴权。资源归属、租户条件、状态流转、额度和扣费事务继续由 Service 检查。
4. 拦截器组合
HttpInteceptorConfigure config = TioBootServer.me().getHttpInteceptorConfigure();
if (config == null) config = new HttpInteceptorConfigure();
HttpInterceptorModel model = new HttpInterceptorModel();
model.setName("app-business-auth");
model.addBlockUrl("/api/app/**");
model.setInterceptor(businessInterceptor);
config.add(model);
TioBootServer.me().setHttpInteceptorConfigure(config);
配置类型位于 nexus.io.tio.boot.http.interceptor。为模型设置稳定名称;同名注册用于替换同一个逻辑拦截器。未命名模型会获得不同的生成名称,不再因 null 键互相覆盖。
TioAdminInterceptorConfiguration 使用名称 tio-admin-token,加入现有配置;重复调用替换该管理员模型,不删除其他业务模型。原有六个标准配置调用保持不变,无需再次创建连接池或注册 ApiTable。
model.setMethods(HttpMethod.POST, HttpMethod.DELETE) 可限制模型作用的方法;未设置表示所有方法。方法过滤先于该模型的 URL 白名单/黑名单。URL 白名单仍是该模型内的路径规则,不应把公开 GET 路径加入全方法白名单后误放行 POST。
为业务前缀跳过管理员认证时,必须同时注册业务拦截器。不要放行 /api/table/**。
5. 验证迁移
- 同一路径 GET 公开、POST 要求登录:匿名 GET 成功,匿名 POST 为 401。
- 用户 Token 不能访问后台接口;管理员 Token 不能当作普通用户身份使用。
- 错误方法为 405 且包含 Allow;未知路径为 404;HEAD 不包含响应体。
- 启用 CORS 时,浏览器预检成功且实际写请求仍须鉴权。
- 拦截器短路和异常路径结束后,线程上的请求上下文已清理;after 阶段仍可读取身份。
- 数据库 SQL 仍由用户手动执行。升级框架不会自动建表、修改业务数据或安装 Redis、ES、Sa-Token。
单数据源业务直接调用静态 Db,Store 无需持有或注入 DbPro;事务和 JSONB 用法见 Db 与 PostgreSQL 业务实践。
