Tomcat защищенный статический контент - PullRequest
7 голосов
/ 02 июня 2010

Я делаю сервис, который помимо прочего имеет функцию «фотоальбомы», которая служит для предоставления фотографий пользователям. Пользователь должен быть «допущен» к просмотру фотографии из альбома. Поэтому отправка прямой ссылки другому лицу не должна позволять просматривать фото.

Фотографии хранятся в папке вне контекста.

Что мне нужно сделать, это выполнить некоторые проверки, когда пользователь запрашивает фотографию, а затем, если проверки в порядке, - отправить файл. Я хочу избежать создания колеса и просто позволить tomcat обслужить изображение, как это обычно делается для статических файлов. Можете ли вы дать совет по этому поводу?

1 Ответ

9 голосов
/ 04 июня 2010

Хорошо, ребята.

После борьбы трудно с этим вопросом, я думаю, что я наконец-то узнал, что нужно сделать, чтобы решить эту проблему. Прежде всего, похоже, что вопрос на самом деле разбивается на две независимые задачи. Один из них - защита доступа к некоторым ресурсам, а второй - подача ресурсов из папки вне контекста.

Первая задача тривиальна, и ее можно решить, написав простой фильтр, привязанный к "/".

Вторая задача гораздо менее тривиальна, но, к счастью, также может быть решена. Tomcat использует реализацию javax.naming.directory.DirContext для загрузки всех ресурсов данного веб-приложения, включая файлы классов. Это также позволяет вам предоставить пользовательскую реализацию этого интерфейса и настроить его в файле context.xml. Реализация по умолчанию - org.apache.naming.resources.FileDirContext. Подробности здесь: http://tomcat.apache.org/tomcat-6.0-doc/config/resources.html

Я создал собственную реализацию DirContext, просто расширив FileDirContext. К счастью, был один метод, который нужно было перезаписать, чтобы «подключить» обнаружение файлов. Метод называется 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. По понятным причинам он не может сочетаться с военным файлом. В вашем 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, общая папка, база данных, даже система контроля версий. Так что это довольно круто.

P.S. Я убил целый день, чтобы все это работало вместе, так что не стесняйтесь отдать мне свой голос, если вам нравится ответ: -))

Приветствия

Juriy

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...