如何将基本身份验证,GlassFish,REST和单页应用程序与我自己的登录表单一起使用?

时间:2015-08-26 01:29:11

标签: authentication servlets glassfish jersey basic-authentication

我使用Glassfish 4作为服务器,将AngularJS应用程序作为客户端。 Glassfish通过JAX-RS(Jersey)公开REST API。我正在通过HTTPS连接使用基本身份验证。我有自己的登录表单,并通过JavaScript在我的REST请求中设置Authorization标头。我的问题是,如果我使用基于web.xml的普通权限(< auth-constraint> inside< security-constraint>),那么响应将返回401,其中包含WWW-Authenticate标头(如果凭据不正确)。这会强制浏览器执行基本身份验证对话框而不是我自己的对话框,并且看起来浏览器端没有可行的跨浏览器工作来阻止它。所以我需要以某种方式抑制401 / WWW-Authenticate响应。

我停止使用基于web.xml的权限,因为似乎正在执行401内容的Servlet级别。我能够使用过滤器进行Jersey身份验证并启用“RolesAllowedDynamicFeature”功能(类似于Glassfish @RolesAllowed with custom SecurityContext)。这看起来效果很好,并且返回403以获取错误的凭据(因此没有浏览器对话框)。但是,当我调用我的EJB时,他们看不到自定义安全上下文和我设置的用户,因此我获得了权限异常。如果重要的是:EJB是在一个罐子里,泽西岛的东西是在战争中,而且两者都捆绑在一起。从我可以收集的内容中获得EJB正确处理凭据的唯一方法是使用web.xml。

我似乎把自己画成一个角落,看不出如何使这项工作。也许我可以退出并返回使用基于web.xml的权限并以某种方式过滤servlet响应以不返回401 / WWW-Authenticate?如果是这样,我无法找到如何做到这一点。或者有什么方法可以设置EJB的安全上下文?或完全不同的东西?我不认为将AngularJS与GlassFish一起使用,REST API和基本身份验证将是非常独特的,有没有人这样做?

1 个答案:

答案 0 :(得分:1)

自发布此问题以来,我发现了有关实现Servlet过滤器的信息,并使用它来尝试将401响应更改为其他状态代码。但是,如果你有< auth-constraint>,过滤器永远不会获得控制权。在你的web.xml中,请求未经授权,因此对我没有帮助。我仍然无法阻止401回应。

但现在我觉得我终于找到了答案。我删除了< auth-constraint>来自web.xml的标记。我更改了Servlet过滤器,现在自己解压缩AUTHENTICATION_HEADER并对其进行解码(通过javax.xml.bind.DatatypeConverter)。接下来,我使用解码的用户名和密码调用HttpServletRequest.login(在请求对象上)。如果用户名/密码组合错误,我会捕获ServletException并使用HttpServletResponse.sendError发送SC_FORBIDDEN。如果我有一个好的登录,我调用doFilter继续处理请求,并在返回时调用HttpServletRequest.logout。

如果我与RolesAllowedDynamicFeature和Jersey例程上的注释结合使用,一切似乎都有效,包括使用自己的安全注释调用EJB。

旁注:在确定HttpServletRequest.login之前,我曾尝试使用HttpServletRequest.authenticate,然后检查返回的布尔值,但是当你在那种情况下获得控制时,响应已经被提交为401而你无法改变它。我甚至尝试传递一个HttpServletResponseWrapper进行身份验证以阻止提交发生,但authenticate似乎通过其他方式获取响应对象,它似乎忽略了你传递它的那个(我甚至尝试传递null,它甚至没有注意到)。