2010-06-02 146 views
6

我正在提供一項服務,其中包括向用戶提供照片的「相冊」功能。用戶必須被「允許」才能看到相冊中的照片。所以發送直接鏈接給其他人不應該允許查看照片。Tomcat保護靜態內容

照片存儲在上下文之外的文件夾中。

我需要做的是在用戶請求照片時執行一些檢查,然後檢查是否正常 - 提供文件。我想避免製作一個輪子,讓tomcat像通常那樣爲靜態文件提供圖像。你能提供一些建議嗎?

+0

什麼信息這些檢查需要和這個信息存儲在哪裏? – BalusC 2010-06-02 14:41:42

+0

只有會話。用戶必須註冊並且必須具有訪問權限,該訪問權限是他的配置文件中描述的會話對象。 – Juriy 2010-06-02 15:56:58

回答

8

好的,夥計們。

經過這個問題努力奮鬥後,我想我終於找到了解決辦法。首先看起來問題實際上分解爲兩個獨立的任務。其中之一是確保訪問一些資源,第二個是從上下文之外的文件夾提供資源。

第一項任務很簡單,可以通過編寫一個掛在「/」上的簡單過濾器來解決。

第二項任務不重要,但幸運的是也可以解決。 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並將該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> 
    ... 
    ... 

現在,任何時候用戶請求/上傳/它會被解析爲C:\ TEMP。使用這種技術,您可以從幾乎任何位置實現加載資源:http,共享文件夾,數據庫,甚至版本控制系統。所以這很酷。

P.S.我殺了整整一天,以使這一切工作在一起,因此不要猶豫,投我的票,如果你喜歡的答案:-))

乾杯

Juriy