繁体   English   中英

Tomcat保护静态内容

[英]Tomcat secured static content

我正在提供一项服务,其中包括为用户提供照片的“相册”功能。 用户必须“被允许”才能看到相册中的照片。 因此,将直接链接发送给其他人不应该允许查看照片。

照片存储在上下文之外的文件夹中。

我需要做的是在用户请求照片时执行一些检查,然后检查是否正常 - 提供文件。 我想避免制作一个轮子,只是让tomcat像往常一样为静态文件服务。 你能就此提出一些建议吗?

好,朋友们。

在努力解决这个问题后,我想我终于找到了解决问题的方法。 首先,看起来问题实际上分解为两个独立的任务。 其中一个是保护对某些资源的访问,另一个是从上下文之外的文件夹中提供资源。

第一项任务是微不足道的,可以通过编写一个挂在“/”上的简单过滤器来解决。

第二项任务不那么简单,但幸运的是,也可以解决。 Tomcat使用javax.naming.directory.DirContext的实现来加载给定Web应用程序的所有资源,包括类文件。 它还允许您提供此接口的自定义实现,并在context.xml文件中对其进行配置。 默认实现是org.apache.naming.resources.FileDirContext。 详细信息: http//tomcat.apache.org/tomcat-6.0-doc/config/resources.html

我通过简单地扩展FileDirContext创建了我自己的DirContext实现。 幸运的是,有一种方法必须被覆盖才能“挂钩”文件发现。 该方法称为file()。

我在这里发布我的测试代码。 它远非完美,并没有考虑重命名文件等极端情况,但我不认为在正常运行的服务器下需要这些。

这段代码的基本思想是检查路径是否以“虚拟目录”前缀开头,如果是 - 在文件系统的其他位置搜索文件(我知道那里有一些重复的代码,但我希望你不是如果你想使用它,懒惰去除它:-)。 自动调用setVirtualName和setVirtualBase以注入配置参数。

/**
 * TODO: add javadocs
 *
 * @author Juriy Bura
 */
public class VirtualFolderDirContext extends FileDirContext {
    private String virtualName;
    private String realName;

    private File virtualBase;
    private String absoluteVirtualBase;


    public VirtualFolderDirContext() {
        super();
    }

    public VirtualFolderDirContext(Hashtable env) {
        super(env);
    }

    public void setVirtualName(String path) {
        virtualName = path;
    }

    public void setVirtualBase(String base) {
        this.realName = base;
        virtualBase = new File(realName);
        try {
            virtualBase = virtualBase.getCanonicalFile();
        } catch (IOException e) {
            // Ignore
        }
        this.absoluteVirtualBase = virtualBase.getAbsolutePath();
    }

    protected File file(String name) {
        File file = null;
        boolean virtualFile = name.startsWith(virtualName + "/");
        if (virtualFile) {
            file = new File(virtualBase, name.substring(virtualName.length()));
        } else {
            file = new File(base, name);
        }

        if (file.exists() && file.canRead()) {

            if (allowLinking)
                return file;

            // Check that this file belongs to our root path
            String canPath = null;
            try {
                canPath = file.getCanonicalPath();
            } catch (IOException e) {
            }
            if (canPath == null)
                return null;

            // Check to see if going outside of the web application root
            if (!canPath.startsWith(absoluteBase) && !canPath.startsWith(absoluteVirtualBase)) {
                return null;
            }

            // Case sensitivity check
            if (caseSensitive) {
                String fileAbsPath = file.getAbsolutePath();
                if (fileAbsPath.endsWith("."))
                    fileAbsPath = fileAbsPath + "/";
                String absPath = normalize(fileAbsPath);
                if (canPath != null)
                    canPath = normalize(canPath);
                if (virtualFile) {
                    if ((absoluteVirtualBase.length() < absPath.length())
                        && (absoluteVirtualBase.length() < canPath.length())) {
                        absPath = absPath.substring(absoluteVirtualBase.length() + 1);
                        if ((canPath == null) || (absPath == null))
                            return null;
                        if (absPath.equals(""))
                            absPath = "/";
                        canPath = canPath.substring(absoluteVirtualBase.length() + 1);
                        if (canPath.equals(""))
                            canPath = "/";
                        if (!canPath.equals(absPath))
                            return null;
                    }                   
                } else {
                    if ((absoluteBase.length() < absPath.length())
                        && (absoluteBase.length() < canPath.length())) {
                        absPath = absPath.substring(absoluteBase.length() + 1);
                        if ((canPath == null) || (absPath == null))
                            return null;
                        if (absPath.equals(""))
                            absPath = "/";
                        canPath = canPath.substring(absoluteBase.length() + 1);
                        if (canPath.equals(""))
                            canPath = "/";
                        if (!canPath.equals(absPath))
                            return null;
                    }
                }
            }

        } else {
            return null;
        }
        return file;

    }
}

在你有这个类之后你必须将它jar并将它放入Tomcat lib文件夹中。 由于显而易见的原因,它不能与war文件一起使用。 在context.xml中,您应该添加如下配置行:

<?xml version="1.0" encoding="UTF-8"?>
<Context antiResourceLocking="true" antiJARLocking="true">

    <Resources
            className="com.juriy.tomcat.virtualdir.VirtualFolderDirContext"
            virtualName="/upload"
            virtualBase="c:/temp/up">
    </Resources>
    ...
    ...

现在,只要用户要求/ upload /它将被解析为c:\\ temp。 使用此技术,您可以从几乎任何位置实现加载资源:http,共享文件夹,数据库,甚至版本控制系统。 所以这很酷。

PS我已经杀了整整一天让这一切都在一起工作所以如果你喜欢答案,请不要犹豫,给我你的投票:-))

干杯

Juriy

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM