2

我正在使用 RESTeasy 框架来开发我的 Web 服务。我已经设法设置了 BASIC 身份验证,现在它工作正常。当然,我确实计划在此之上使用 SSL。

这个过程很简单(如果你不知道这是关于什么的,请阅读一些关于 HTTP 基本身份验证的内容):

  1. 每个请求都被一个分析请求标头的方法拦截。
  2. 此标头被解码并提取用户名和密码。
  3. 然后该方法查询数据库以检查用户名和密码是否匹配。
  4. 如果它们匹配请求继续,如果不匹配,则返回 401 代码。

使用这种方法,由于 REST(和 HTTP 本身)的无状态特性,每个请求都意味着对数据库的请求。

我的问题是:是否可以不对每个经过身份验证的请求查询数据库?

可能的提示:一些使用cookies的机制?

这个问题在技术上是不可知的。


顺便说一句:

我真的觉得关于这个 REST 身份验证问题的信息很少。只是 OAuth、OAuth、OAuth……如果我们不想对 3rd 方应用程序进行身份验证,信息分散在各处,没有任何具体示例,例如使用 OAuth。如果您对 REST WebServices 中的身份验证有任何好的建议,我很想听听。

谢谢你。

4

5 回答 5

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;
        }
    }
}
于 2012-01-21T10:31:51.367 回答
1

有多种方法可以使用 cookie 实现“Auth Ticket”(谷歌搜索,您可能会找到一些非 OAuth 引用),因此并非每个请求都需要数据库查询。但是,这些通常涉及加密密钥。

我不相信最佳实践应该是将加密密钥存储在源文件中(但这是教程通常实现它的方式),因此您可能会涉及某种磁盘访问(通过属性文件、密钥库等),即使你不查询数据库。

正如 Perception 所说,在无状态系统设计中添加 cookie(状态)是一种欺骗。

于 2012-01-18T21:00:26.933 回答
1

使用memcached 之类的东西作为数据库的中间体。检查凭据是否被缓存,如果它们继续请求,如果它们没有被缓存,则从数据库中提取它们并验证凭据。如果凭据匹配,则缓存它们以供将来请求并继续当前请求。

请记住,对 memchaced 的访问必须与对数据库的访问一样安全,因为其中存储了密码。这是许多站点使用 OAuth 的原因之一,尤其是 OAuth 2,您可以在其中分发一个短期访问令牌和一个长期刷新令牌,以便在需要时获得新的访问令牌。

于 2012-01-18T21:00:41.473 回答
1

欢迎来到代表性国家转移安全的世界!你知道,我向 Roy Fielding 发送了一条消息,询问如何创建一个真正安全的 RESTful 服务。他还没有回我。

您的两个选项确实是基本身份验证(希望使用 SSL,或者有什么意义)或 OAuth。对于我目前参与的所有解决方案,我们都在使用 OAuth。虽然它使测试复杂化,但它非常安全,并允许我们从我们的服务中创建可外部化的 API。

我建议不要使用 cookie 来存储会话信息。这不仅违反了 REST 的精神,而且还会使您的应用程序遭受会话劫持。为了加快速度,您可以做的一件事是使用用户信息维护一个良好的二级缓存,这样您的查询实际上不会针对每个传入请求访问数据库。这可以显着提高速度。这种策略同样适用于基本身份验证和 Oauth。

于 2012-01-18T21:01:23.533 回答
0

答案最终是cache

在我的特殊情况下,我使用 RESTeasy 作为 REST 框架,使用 Google App Engine 作为应用程序服务器。不难发现 GAE 支持memcache

如果您正在使用Objectify(您真的应该这样做;这太棒了),那就更容易了。只需使用@Cached注释您的实体类。此处说明了此过程。

Objectify 在会话对象中支持另一种缓存。换句话说,只要您的 Objectify 对象被实例化,即使不使用 memcache,它也可以提供您的对象(这很好,因为在 GAE 中有使用 memcache 的配额,尽管它们比数据存储区的便宜)。我强烈建议您在他们的 wiki 中阅读 Objectify 的良好实践。

最后一点,我将考虑使用Digest 身份验证而不是Basic。它似乎更安全。密码从不通过网络传播的事实真的让我松了一口气。

我希望这个 SO 问题对某人和帮助我的人有用:谢谢。:)

于 2012-01-20T16:16:12.313 回答