2012-01-18 32 views
2

我正在使用RESTeasy框架來開發我的Web服務。我已經成功設置了BASIC身份驗證,現在它正在正常工作。當然,我打算在此之上使用SSL。經過身份驗證的REST請求是否總是隱含數據庫請求?

的過程是簡單的(請有關read something HTTP基本身份驗證,如果你不知道這是什麼):

  1. 每個請求是由分析請求頭的方法截獲。
  2. 該頭文件被解碼並提取用戶名和密碼。
  3. 然後方法查詢數據庫以檢查用戶名和密碼是否匹配。
  4. 如果它們匹配請求繼續,如果它們不匹配,則返回401代碼。

使用這種方法,由於REST(以及HTTP本身)的無狀態特性,每個請求都意味着對數據庫的請求。

我的問題是:是否有可能不在每個經過驗證的請求上查詢數據庫?

可能的提示:一些使用cookie的機制?

這個問題在技術上是不可知的。


正如一個側面說明:

我真的覺得有這個REST認證方面的資料非常少。這僅僅是OAuth,OAuth,OAuth ......如果我們不想驗證第三方應用程序,信息分散到處,並且沒有任何具體的例子,就像使用OAuth一樣。 如果您有任何關於REST Web服務中身份驗證的好建議,我很樂意聽到他們的意見。

謝謝。

+3

有一個叫做緩存的新東西,您可能想研究它! – 2012-01-18 21:02:16

+1

如果您的憑證存儲在文件中,它並不意味着數據庫請求:-) – cmbuckley 2012-01-18 21:09:46

+0

@cbuckley文件請求可能比數據庫請求慢,所以我認爲它不是一個選項。 – miguelcobain 2012-01-18 21:56:09

回答

0

答案結束爲緩存

在我的特殊情況下,我將RESTeasy用作REST框架,將Google App Engine用作Application Server。不難發現GAE支持memcache

如果您使用的是Objectify(您確實應該;這很棒),它更容易。只需用@Cached註釋您的實體類。該過程如圖here所示。

Objectify在會話對象中支持另一種緩存。換句話說,只要Objectify對象被實例化,即使沒有使用memcache,它也可以提供對象(這很好,因爲在GAE中,使用memcache的配額雖然比數據存儲更便宜)。我強烈建議您在他們的wiki中閱讀Objectify的良好實踐。

作爲最後一點,我會考慮使用摘要式身份驗證而不是基本。它似乎更安全。密碼永遠不會通過網絡傳輸真的讓我感到安慰。

我希望這個問題對某些人和幫助我的人有用:謝謝。 :)

1

有許多方法可以通過cookie實現「Auth Ticket」(谷歌,你可能會發現一些非OAuth引用),這樣就不是每個請求都需要數據庫查詢。但是,這些通常涉及加密密鑰。

我不認爲最佳實踐應該是將加密密鑰存儲在源文件中(但這是教程通常如何實現的),因此您可能需要某種類型的磁盤訪問(通過屬性文件,密鑰存儲庫,等等),即使你不查詢數據庫。

正如Perception所述,向無狀態系統設計中添加cookie(狀態)是一種欺騙行爲。

+0

感謝您的「驗證票」洞察。我會進一步研究。 – miguelcobain 2012-01-18 22:17:05

+0

@miguelcobain:昨晚我剛剛爲一個客戶實現了一個(我只是用py-bcrypt中的pyramid構建了實際的隨機鹽散列函數)。換句話說:我欺騙了。 – ccoakley 2012-01-18 22:21:53

1

使用像memcached這樣的東西作爲數據庫的中間件。檢查證書是否被緩存,是否繼續請求,如果它們沒有被緩存,從數據庫中提取它們並驗證證書。如果證書匹配將它們緩存用於將來的請求,並繼續使用當前的證書。

請記住,訪問memchaced必須與訪問數據庫一樣安全,因爲它具有存儲在其中的密碼。這是很多網站使用OAuth的原因之一,特別是OAuth 2,您可以在其中分發短期訪問令牌和長期存在的刷新令牌,以便在需要時獲取新的訪問令牌。

+0

GAE似乎支持[memcache](http://code.google.com/intl/zh-CN/appengine/docs/java/memcache/overview.html)。我認爲這是個好消息,對吧? :) – miguelcobain 2012-01-18 22:14:46

+0

是的。那應該很容易實現。 – abraham 2012-01-18 22:32:58

1

歡迎來到代表性國家運輸安全的世界!您知道,我向Roy Fielding發送了一條消息,詢問您如何創建一個真正安全的RESTful服務。他還沒有回到我身邊。

您的兩個選項確實是基本身份驗證(希望使用SSL或有什麼意義)或OAuth。對於我目前參與的所有解決方案,我們正在使用OAuth。雖然它使測試複雜化,但它非常安全,並允許我們在我們的服務中創建可外部化的API。

我建議反對使用cookie來存儲會話信息。這不僅違反了REST的精神,而且還打開了會話劫持的應用程序。你可以做的一件事是加快速度,就是維護一個包含用戶信息的良好的二級緩存,這樣你的查詢就不會爲每個傳入的請求都實際訪問數據庫。這可以提供顯着的速度提升。這個策略同樣適用於基本認證和Oauth。

+0

我已經更新了提到的問題,當然我會使用SSL。 我正在使用Google App Engine及其數據存儲。我將研究這種基礎設施支持的緩存類型。我將從減少數據存儲請求中受益匪淺,因爲我們在一定數量的請求中支付GAE。 :)謝謝你的出色答案。 – miguelcobain 2012-01-18 22:02:44

+0

GAE似乎支持[memcache](http://code.google.com/intl/zh-CN/appengine/docs/java/memcache/overview.html)。我認爲這是個好消息,對吧? :)不幸的是,也有使用這項服務的配額。 – miguelcobain 2012-01-18 22:14:58

+0

我不太熟悉GAE中可用的ORM工具,但memcached是可靠和快速的,所以*是個好消息。 – Perception 2012-01-18 22:31:03

1

如果您與AppEninge的UserService集成(並且與Google帳戶同樣),則可以阻止任何查詢。 RESTlet擁有一個超級優雅的身份驗證程序,它附帶框架:

public class GaeAuthenticator extends Authenticator { 
    /** 
    * The GAE UserService that provides facilities to check whether a user has 
    * authenticated using their Google Account 
    */ 
    private UserService userService = UserServiceFactory.getUserService(); 

    /** 
    * Constructor setting the mode to "required". 
    * 
    * @param context 
    *   The context. 
    * @see #Authenticator(Context) 
    */ 
    public GaeAuthenticator(Context context) { 
     super(context); 
    } 

    /** 
    * Constructor using the context's default enroler. 
    * 
    * @param context 
    *   The context. 
    * @param optional 
    *   The authentication mode. 
    * @see #Authenticator(Context, boolean, Enroler) 
    */ 
    public GaeAuthenticator(Context context, boolean optional) { 
     super(context, optional); 
    } 

    /** 
    * Constructor. 
    * 
    * @param context 
    *   The context. 
    * @param optional 
    *   The authentication mode. 
    * @param enroler 
    *   The enroler to invoke upon successful authentication. 
    */ 
    public GaeAuthenticator(Context context, boolean optional, Enroler enroler) { 
     super(context, optional, enroler); 
    } 

    /** 
    * Integrates with Google App Engine UserService to redirect 
    * non-authenticated users to the GAE login URL. Upon successful login, 
    * creates a Restlet User object based values in GAE user object. The GAE 
    * "nickname" property gets mapped to the Restlet "firstName" property. 
    * 
    * @param request 
    *   The request sent. 
    * @param response 
    *   The response to update. 
    * @return True if the authentication succeeded. 
    */ 
    @Override 
    protected boolean authenticate(Request request, Response response) { 
     ClientInfo info = request.getClientInfo(); 
     if (info.isAuthenticated()) { 
      // The request is already authenticated. 
      return true; 
     } else if (userService.isUserLoggedIn()) { 
      // The user is logged in, create restlet user. 
      com.google.appengine.api.users.User gaeUser = userService 
        .getCurrentUser(); 
      User restletUser = new User(gaeUser.getUserId()); 
      restletUser.setEmail(gaeUser.getEmail()); 
      restletUser.setFirstName(gaeUser.getNickname()); 
      info.setUser(restletUser); 
      info.setAuthenticated(true); 
      return true; 
     } else { 
      // The GAE user service says user not logged in, let's redirect him 
      // to the login page. 
      String loginUrl = userService.createLoginURL(request 
        .getOriginalRef().toString()); 
      response.redirectTemporary(loginUrl); 
      return false; 
     } 
    } 
} 
+0

可能是一個很好的解決方案,但需要驗證我自己的用戶,而不是Google的。另外,我正在使用RESTeasy。 但是,謝謝你讓我知道這個功能。 :) – miguelcobain 2012-01-22 18:04:39