我正在使用RESTeasy框架来开发我的Web服务。我已经设法建立BASIC身份验证,现在它正常工作。当然,我计划在此基础上使用SSL。
这个过程很简单(如果您不知道这是什么,请关于HTTP基本身份验证read something):
使用这种方法,由于REST(和HTTP本身)的无状态特性,每个请求都意味着对数据库的请求。
我的问题是:是否可以不在每个经过身份验证的请求中查询数据库?
可能的提示:使用cookie的一些机制?
这个问题在技术上是不可知的。
正如旁注:
我真的觉得这个REST身份验证问题的信息非常少。它只是OAuth,OAuth,OAuth ......如果我们不想验证第三方应用程序,那么信息就会分散在各处,而且没有任何具体的例子,比如使用OAuth。 如果您对REST WebServices中的身份验证有任何好的建议,我很乐意听到。
谢谢。
答案 0 :(得分:1)
有各种方法可以使用Cookie实现“Auth Ticket”(google,你可能会发现一些非OAuth引用),这样每个请求都不需要数据库查询。但是,这些通常涉及加密密钥。
我不相信最佳实践应该是将加密密钥存储在源文件中(但这是教程通常实现的方式),因此您可能涉及某种磁盘访问(通过属性文件,密钥库等) )即使你不查询数据库。
正如Perception所述,将cookie(状态)添加到无状态系统设计中是一种欺骗行为。
答案 1 :(得分:1)
使用memcached之类的东西作为数据库的中间件。检查凭据是否已缓存,是否继续请求,如果未缓存,请从数据库中提取凭据并验证凭据。如果凭据匹配,则将其缓存以供将来请求使用,并继续使用当前请求。
请记住,对memchaced的访问必须与访问数据库一样安全,因为它存储了密码。这是许多网站使用OAuth的原因之一,尤其是OAuth 2,您可以在其中分发一个短期访问令牌和一个长期存在的刷新令牌,以便在需要时获取新的访问令牌。
答案 2 :(得分:1)
欢迎来到具有代表性的国家转移安全世界!您知道,我向Roy Fielding发送了一条消息,询问您如何创建一个真正的RESTful服务,这也是安全的。他还没回到我身边。
您的两个选项实际上是Basic Auth(希望使用SSL,或者重点是什么),或OAuth。对于我目前参与的所有解决方案,我们都在使用OAuth。虽然它使测试变得复杂,但它非常安全,并且允许我们从我们的服务中创建可外部化的API。
我建议不要使用cookie来存储会话信息。这不仅违反了REST的精神,而且还打开了会话劫持的应用程序。您可以采取的一件事就是加快速度,保持一个良好的二级缓存和用户信息,这样您的查询就不会为每个传入的请求实际访问数据库。这可以提高 显着的 速度。这种策略同样适用于基本的auth和Oauth。
答案 3 :(得分: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;
}
}
}
答案 4 :(得分:0)
答案最终是缓存。
在我的特定情况下,我使用RESTeasy作为REST框架,使用Google App Engine作为Application Server。不难发现GAE支持memcache。
如果您正在使用Objectify(您真的应该这样做,那真棒),那就更容易了。只需使用 @Cached 注释您的实体类。此过程如here所示。
Objectify支持会话对象中的另一种缓存。换句话说,只要你的Objectify对象被实例化,它甚至可以在不使用memcache的情况下提供你的对象(这很好,因为在GAE中有使用memcache的配额,尽管它们比数据存储更便宜)。我强烈建议你阅读Objectify在他们的wiki中的良好做法。
作为最后一点,我会考虑使用摘要式身份验证而不是 Basic 。它似乎更安全。密码永远不会通过网络传播的事实让我感到宽慰。
我希望这个问题对某些人和帮助我的人有用:谢谢。 :)