在泽西岛获得rest服务

我对Web服务非常陌生。 我已经使用Jersey 2与Spring集成了一些REST服务。 现在我需要使用用户名/密码进行身份validation来保护这些rest服务。 我被告知不要使用Spring安全性。

我不知道该怎么做。 我在网上搜索,但各种链接显示各种实现,我无法决定如何继续它。

我知道这是一个模糊的问题但请在这方面提供帮助。

使用用户名和密码进行身份validation的常用方法是使用基本身份validation 。 基本上客户端需要发送请求标头Authorization ,标头值为Basic Base64Encoded(username:password) 。 所以我的用户名是peeskillet ,我的密码是pass ,作为客户端,我应该将标题设置为

 Authorization: Basic cGVlc2tpbGxldDpwYXNz 

在servlet环境中,容器应该支持基本身份validation。 您可以在web.xml上配置此支持。 您可以在48.2保护 Java EE的Web应用程序教程中看到一个示例。 您还会在一个示例中注意到

 CONFIDENTIAL 

这是为了SSL支持。 建议用于基本身份validation。

如果您不想处理使用安全域和登录模块,领域等的麻烦,那么需要自定义servlet支持,或者如果您不在servlet环境中,那么实现Basic Auth在ContainerRequestFilter中真的不是太难。

您可以在jersey / examples / https-clientserver-grizzly上看到完整的示例。 您应该专注于SecurityFilter

filter中的基本流程就是这样的

  1. 获取Authorization标头。 如果它不存在,则抛出AuthenticationException 。 在这种情况下, AuthenticationExceptionMapper将发送标题"WWW-Authenticate", "Basic realm=\"" + e.getRealm() + "\" ,这是Basic Auth协议的一部分

  2. 一旦我们有了标题,我们解析它只是为了获得Base64编码的用户名:密码。 然后我们解码它,然后拆分它,然后分开用户名和密码。 如果此进程中的任何一个失败,则再次抛出映射到400 Bad Request的WebApplicationException

  3. 检查用户名和密码。 示例源代码只检查用户名是否为user ,密码是否为password ,但您需要使用filter中的某些服务来validation此信息。 如果其中任何一个失败,则抛出AuthenticationException

  4. 如果一切顺利,则从authenticate方法创建User ,并将其注入Authorizer (这是一个SecurityContext )。 在JAX-RS中, SecurityContext通常用于授权。

对于授权,如果要保护某些资源的某些区域,可以对类或方法使用@RolesAllowed批注。 通过注册RolesAllowedDynamicFeature ,Jersey支持此注释。

引擎盖下发生的事情是SecurityContext将从请求中获得。 通过我链接到的示例,您可以看到Authorizer ,它有一个重写方法isUserInRole 。 将调用此方法来检查@RolesAllowed({"ADMIN"}) 。 因此,在创建SecurityContext ,应确保在重写方法中包含用户的角色。

要进行测试,您只需使用浏览器即可。 如果一切设置正确,当您尝试访问资源时,您应该看到(在Firefox中)一个对话框,如本文所示。 如果你使用cURL ,你可以这样做

 C:/>curl -v -u username:password http://localhost:8080/blah/resource 

这将发出基本身份validation请求。 由于-v开关,您应该看到所有涉及的标头。 如果您只想使用客户端API进行测试,可以在此处查看如何进行设置。 在上述三种情况中的任何一种情况下,Base64编码都将为您完成,因此您不必担心它。

至于SSL,您应该查看容器的文档,以获取有关如何设置它的信息。

安全性主要有两种:

  • 基于容器
  • 基于应用

保护spring应用程序的标准方法是使用Spring Security(以前称为Acegi)。 知道为什么你不被允许使用它会很有趣。

你可以使用基于容器的安全性,但我猜你使用spring也排除了这个选项。 由于选择Spring通常是为了避免使用完整的J2EE容器(编辑:虽然如下所述,但是大多数普通的servlet容器都允许你实现各种基于容器的安全方法)

这实际上只留下一个选项,即推出自己的安全性。

您对Jersey的使用表明这可能是一个REST应用程序。 在这种情况下,您确实应该坚持使用标准的HTTP身份validation方法,这些方法具有以下相同强度的相反顺序:

  • BASIC
  • 消化
  • 形成
  • 证书

REST应用程序通常被认为是“无状态”,它基本上排除了基于表单的身份validation(因为您需要使用Session),而您将使用BASIC,Digest和Certificate。

你的下一个问题是,我是谁在validation。 如果您可以根据他们请求的URL知道用户的用户名和密码(例如,如果它是所有用户的一组凭据),那么Digest是最好的选择,因为密码永远不会被发送,只有哈希。 如果您无法知道密码(因为您要求第三方系统对其进行validation等),那么您将无法使用BASIC。 但是,您可以通过使用SSL来增强BASIC的安全性,或者更好地将BASIC与客户端证书身份validation相结合。 事实上,基于HTTPS的BASIC身份validation是保护大多数REST应用程序的标准技术。

您可以轻松实现查找身份validation标头的Servletfilter并自行validation凭据。 这种filter有很多例子,它是一个自包含的类文件。 如果没有找到凭证,则filter返回401,在响应头中传递基本身份validation的提示。 如果凭据无效,则返回403.应用程序安全性本身几乎是整个职业,但我希望这会有所帮助。

正如之前的post所说,你可以使用不同的选项,实现的开销也各不相同。 从实际的角度来看,如果您要从这开始并寻找一种简单实现的舒适方式,我建议使用BASIC身份validation的基于容器的选项。

如果使用tomcat,则可以设置一个实现起来相对简单的领域 。 您可以使用JDBCRealm,它从数据库中的指定列获取用户和密码,并通过server.xml和web.xml进行配置。 每次您尝试访问您的应用程序时,这都会自动提示您输入凭据。 您没有任何应用程序端实现。

我现在可以告诉你的是,你已经完成了将Jersey与Spring整合在一起的大部分“脏”工作。 我建议您使用基于应用程序的解决方案,它不会将您绑定到特定容器。 Spring Security一开始可能会令人生畏,但是当你驯服野兽时,你会发现它实际上是一只友善的小狗。

事实上,只需实现接口,Spring Security就可以进行大规模定制。 并且有很多文档和支持。 此外,您已经拥有一个基于Spring的应用程序。

因为你所寻求的只是指导,我可以为你提供一些教程。 您可以利用此博客。

http://www.baeldung.com/rest-with-spring-series/ http://www.baeldung.com/2011/10/31/securing-a-restful-web-service-with-spring-security- 3-1-部分-3 /

其实昨天做了这件事。

所以这真的是你想要实现的东西。 我的理由是使用移动设备和One-Page-App JavaScript来运行这个东西。

基本上,您需要做的就是生成某种类型的标头,该标头在客户端将要进行的每个连续请求中都需要。

因此,您在等待具有用户/密码的post时执行端点:

 @Path("/login") public class AuthenticationResource { @POST @Consumes("application/json") public Response authenticate(Credentials credential) { boolean canBeLoggedIn = (...check in your DB or anywher you need to) if (canBeLoggedIn) { UUID uuid = UUID.randomUUID(); Token token = new Token(); token.setToken(uuid.toString()); //save your token with associated with user (...) return Response.ok(token).type(MediaType.APPLICATION_JSON_TYPE).build(); } else { return Response.status(Response.Status.UNAUTHORIZED).build(); } } 

}

现在您需要保护需要该令牌的资源:

  @Path("/payment") @AuthorizedWithToken public class Payments { @GET @Produces("application/json") public Response sync() { (...) } } 

注意@AuthorizedWithToken注释。 您可以使用特殊元注释@NameBinding自行创建此注释

 @NameBinding @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface AuthorizedWithToken {} 

现在,对于实现标头检查的filter:

 @AuthorizedWithToken @Provider public class XAuthTokenFilter implements ContainerRequestFilter { private static String X_Auth_Token = "X-Auth-Token"; @Override public void filter(ContainerRequestContext crc) throws IOException { String headerValue = crc.getHeaderString(X_Auth_Token); if (headerValue == null) { crc.abortWith(Response.status(Response.Status.FORBIDDEN).entity("Missing " + X_Auth_Token + " value").build()); return; } if(! TOKEN_FOUND_IN_DB) { crc.abortWith(Response.status(Response.Status.UNAUTHORIZED).entity("Wrong " + X_Auth_Token + " value").build()); return; } } } 

您可以创建任意数量的自己的注释,检查http请求中的各种内容并混合它们。 但是你需要注意优先级,但实际上很容易找到。 此方法需要使用https但这很明显。