adlered / bolo-solo

🍍Bolo菠萝博客 专为程序员设计的精致Java博客系统 | 🎸基于Solo深度定制 | ❤️完善文档轻松安装,贴心的技术支持 | 免登录评论 | 邮件/微信提醒 | 自定义图床 | 备案模式 | ✨精致主题持续更新 | 一键备份 | 防火墙 | 评论过滤 | 独立分类 | 文章与GitHub同步 | ✅安装太轻松!支持 Tomcat Docker 宝塔面板 | 支持Windows Linux MacOS Web容器 | 支持ARM处理器 X86/64处理器 | 🚚支持从Solo轻松迁移
https://demo.stackoverflow.wiki
GNU Affero General Public License v3.0
1.19k stars 201 forks source link

非滴链图床上传的临时文件目录权限问题导致上传失败 #246

Open jianhong-li opened 9 months ago

jianhong-li commented 9 months ago

版本: bolo 2.6

问题描述:

使用了七牛云的图床功能. 在测试时发现上传时会报错. 具体的报错内容如下:

[INFO 11-26 17:20:16 c.PicUploadProcessor 104] Uploading image [temp=/home/xxx/www/bolo-web/webapps/ROOT/image.png]
java.io.FileNotFoundException: /home/xxx/www/bolo-web/webapps/ROOT/image.png (Permission denied)
    at java.io.FileOutputStream.open0(Native Method)
    at java.io.FileOutputStream.open(FileOutputStream.java:270)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:162)
    at org.apache.commons.fileupload.disk.DiskFileItem.write(DiskFileItem.java:423)
    at org.b3log.solo.bolo.pic.PicUploadProcessor.uploadPicture(PicUploadProcessor.java:106)
    at org.b3log.solo.bolo.pic.PicUploadProcessor_$$_jvstbc2_51._d10uploadPicture(PicUploadProcessor_$$_jvstbc2_51.java)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.b3log.latke.ioc.JavassistMethodHandler.invoke(JavassistMethodHandler.java:116)
    at org.b3log.solo.bolo.pic.PicUploadProcessor_$$_jvstbc2_51.uploadPicture(PicUploadProcessor_$$_jvstbc2_51.java)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

查看现在的源代码发现这个上传时会先把文件保存到本地.再使用UploadUtils上传到对应的目标地址:

            DiskFileItemFactory factory = new DiskFileItemFactory();
            factory.setRepository(new File("temp/"));
            ServletFileUpload upload = new ServletFileUpload(factory);
            upload.setHeaderEncoding("UTF-8");
            Map okPic = new HashMap();
            List<String> errFiles = new ArrayList<>();
            try {
                List<FileItem> itemList = upload.parseRequest(context.getRequest());
                for (FileItem item : itemList) {
                    String name = item.getName();
                    String config;
                    try {
                        config = optionRepository.get(Option.ID_C_TUCHUANG_CONFIG).optString(Option.OPTION_VALUE);
                    } catch (Exception e) {
                        config = "hacpai";
                    }
                    final ServletContext servletContext = SoloServletListener.getServletContext();
                    final String assets = "/"; //  这里应该是直接使用了webapp的目录
                    String path = servletContext.getResource(assets).getPath();
                    path = URLDecoder.decode(path);
                    LOGGER.info("Uploading image [temp=" + path + name + "]");
                    File file = new File(path + name);
                    item.write(file);
                    item.delete();
                    try {
                        String url = UploadUtil.upload(config, file);
                        if (url.isEmpty()) {
                            url = "接口调用错误,请检查偏好设置-自定义图床配置,清除浏览器缓存并重启服务端。";
                        }
                        okPic.put(name, url);
                    } catch (Exception e) {
                        errFiles.add(name);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

出于安全考虑一般部署的webapp目录是不可写的. 我看原来是写到的是temp目录,不知为何后面修改为了webapp?

修改建议:

  1. 使用temp目录进行缓存.
  2. 如果后续的上传不是异步.(看代码确实不是) 建议直接使用apache的upload的fileItem 直接获取inputstream进行上传. 这样则少一次本地缓存.