2011-03-22 67 views
2

我正忙於開發一個需要REST API的項目,以允許用戶訪問服務器上的信息。我有系統使用Spring MVC和​​在需要時返回JSON。Spring MVC,REST風格的服務和Apache Shiro策略

我現在想要在系統中包含安全性,首先要確保用戶對自己進行身份驗證並擁有訪問資源的正確權限,其次我希望對數據有足夠的細粒度控制以確保用戶能夠只訪問資源的公共可用部分,或者如果他們擁有整個資源的正確權限。

因此,例如:

場景A:用戶A想訪問他們的郵件列表,以及他們的名字和電話號碼。然後他們會得到身份驗證,他們的權限將允許他們訪問他們自己的所有信息。

情景B:用戶A想要訪問用戶B的電話號碼 - 因此排除用戶B的響應中的消息列表,因爲A沒有權限訪問該部分信息。

  • Q1:有沒有要去 有關執行此操作使用Apache四郎 和Spring MVC一種巧妙的方法?
  • Q2:是否有人 對如何別人取得 這樣的例子或鏈接到一個教程 ?
  • Q3:什麼樣的權限 方案,使用四郎的,將是最有效的 允許這種類型的細 細粒度控制的?

我以前沒有和Shiro一起工作過,但是從玩例子和閱讀文檔來看,這看起來像是可能的,而且Shiro最適合這個解決方案。儘管我接受其他解決方案。

編輯:一個解決方案,我不知道這是否可能與四郎&傑克遜,是標註在我的POJO的屬性,我可以標記爲公共或私人。或者更好的是,用訪問它們所需的許可標記它們。然後,當傑克遜打印出對象的JSON表示時,它可以檢查當前屬性的權限,並決定是否從其註釋打印屬性。

回答

1

這個問題的解決方案非常簡單。我創建了傑克遜一組視圖類:

@JsonView(SecureViews.Authenticated.class) 
public String getPhoneNumber() { 
    return phoneNumber; 
} 

什麼上面的規則的意思是:

public class SecureViews { 
    public static class Public{}; 
    public static class Authenticated extends Public{}; 
    public static class User extends Authenticated{}; 
    public static class Internal extends User {}; 
} 

我然後通過添加以下帶標註的所有每個實體的getter方法我想固定只有在系統內進行身份驗證的用戶才能查看用戶的電話號碼。

或者

@JsonView(SecureViews.User.class) 
public List<Event> getEvents() { 
    return Collections.unmodifiableList(events); 
} 

然後我創建了一個接口,並實現在我所有的安全實體的接口:

public interface SecurePropertyInterface { 
    Class<?> getMaxPermissionLevel(Long userID); 
} 

這裏是方法的實現:

public Class<?> getMaxPermissionLevel(Long userID) { 
     if (userID != null && userID == uid) { 
      return SecureViews.User.class; 
     } 
     if (SecurityUtils.getSubject().isAuthenticated()) { 
      return SecureViews.Authenticated.class; 
     } 

     return SecureViews.Public.class; 
    } 

現在的魔法。擴展​​並覆蓋下面的方法:

@Override 
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, 
      HttpServletResponse response) throws Exception { 

     Long userID = CTConversionUtils.convertToLong(request.getParameter("id")); 
     model = (Map<String, Object>) super.filterModel(model); 

     Class<?> viewClass = SecureViews.Public.class; 

     if(SecurityUtils.getSubject().isAuthenticated()) { 
      viewClass = SecureViews.Authenticated.class; 
     } 

     for (Entry<String, Object> modelEntry : model.entrySet()) { 
      if (modelEntry.getValue() instanceof SecurePropertyInterface) { 
       viewClass = ((SecurePropertyInterface)modelEntry.getValue()).getMaxPermissionLevel(userID); 
      } 
     } 
     objectMapper.viewWriter(viewClass).writeValue(getJsonGenerator(response), model); 
    } 

您也可以覆蓋setObjectMapper方法來捕獲objectMapper當春天設置您的​​。

我的Spring配置如下:

<bean 
     class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver" 
     p:order="1"> 
     <property name="mediaTypes"> 
      <map> 
       <entry key="json" value="*/*" /> 
      </map> 
     </property> 
     <property name="defaultViews"> 
      <list> 
       <bean 
        class="com.bytesizecreations.connecttext.json.SecureMappingJacksonJsonView"> 
        <property name="objectMapper"> 
         <bean 
          class="org.codehaus.jackson.map.ObjectMapper" /> 
        </property> 
       </bean> 
      </list> 
     </property> 
    </bean> 

那麼,我們現在在這裏?每次需要將響應反序列化爲JSON時,都會調用renderedMergedOutputModel方法。如果用戶的ID在請求中,我們將其存儲。然後,我們可以遍歷模型映射並檢查每個值是否爲SecurePropertyInterface,以及它是否獲得其最大權限級別。

這個策略似乎正確地服務於我的目的。當用戶請求用戶列表時,他們只能獲得已認證的屬性,但當用戶請求自己的詳細信息時,他們只能獲得其私有屬性。

雖然我懷疑這個代碼可以進一步改進,但是我花了太多的時間試圖讓它變得更簡單。

+0

你可以做'Class ',並取消原始類型警告。 – 2011-03-30 06:52:04

+0

謝謝。我已經添加了它。 – 2011-03-30 15:45:42

相關問題