Redmine插件中注册XML导入路由需在config/routes.rb添加POST路由并映射到自定义控制器;控制器须继承ApplicationController、跳过CSRF校验、强制校验登录与项目权限;解析XML时禁用外部实体、限制字段与长度、白名单过滤;创建任务应避免create!,改用save(validate: false)配合手动校验和事务包裹;前端需用FormData提交并携带authenticity_token,curl测试须用-F参数;权限上下文(如@project)必须显式传递,防止自定义字段等依赖丢失。
Redmine插件中如何注册XML导入路由和控制器
XML任务导入不是Redmine原生功能,必须通过插件新增控制器处理上传与解析。关键在于让Redmine识别你的路由,且不被权限系统拦截。
- 在插件的
config/routes.rb中添加资源路由,例如:match 'projects/:project_id/import_tasks_from_xml' => 'import_tasks_from_xml#create', :via => [:post], :as => 'import_tasks_from_xml'
- 控制器需继承
ApplicationController,并显式声明跳过CSRF保护(因为XML上传常由外部脚本发起):skip_before_action :verify_authenticity_token, only: [:create]
- 必须调用
require_login和find_project(或手动校验项目权限),否则普通用户可越权导入到任意项目
如何安全解析上传的XML并映射到Redmine Issue模型
直接用 Nokogiri::XML 解析用户上传的XML存在XXE和内存爆炸风险,不能无过滤加载外部实体或超大文档。
- 强制设置解析选项禁用外部实体:
doc = Nokogiri::XML(params[:xml_file].read) do |config| config.noent.noenc.noblanks end
- 只允许白名单字段:如
、、,忽略所有未知节点 - 对每个字段做长度限制(如
subject截断至 255 字符),防止数据库溢出或日志刷屏 - 用
Project.find_by_identifier而非params[:project_id]直接查库,避免整数ID被伪造为SQL注入载体
为什么用 Issue.create! 容易失败,该用什么替代
create! 会抛出异常中断整个导入流程,而XML通常含多条任务——一条失败不该导致全部回滚,且错误信息需返回给前端供排查。