Java EE的RESTful身份验证

时间:2013-05-23 10:08:36

标签: ajax rest java-ee authentication servlets

我花了一些时间来评估可用于在 Java EE 应用程序中对用户进行身份验证的选项。

因此,请建议以下列出的选项是否有效以及有关优缺点的陈述。可能是我缺少可能使身份验证方法可行的细节。或者可能是我错过了另一个选项(我们再次严格地谈论java EE所以没有查询身份验证除非可以在符合EE标准的方式)

  

1。 DIGEST / BASIC认证

 <security-constraint>
     <web-resource-collection>
        <web-resource-name>admin</web-resource-name>
        <url-pattern>/protected/*</url-pattern>
     </web-resource-collection>
     <auth-constraint>
        <role-name>admin</role-name>
     </auth-constraint>
</security-constraint>
<login-config>
    <auth-method>DIGEST/BASIC</auth-method>
    <realm-name>as-defined-secuity-realm</realm-name>
</login-config>

优点

  1. 这是一种REST友好的身份验证方式。您可以通过AJAX调用发送授权凭据。一旦用户通过身份验证,浏览器将伴随具有正确Authorization: Basic/Digest QWxhZGRpbjpvcGVuIHNlc2FtZQ==标头的任何请求。如果凭据不良,将向用户显示丑陋的浏览器登录屏幕 - 如果您可以使用它,那么BASIC / DIGEST auth就是您的选择。

  2. 在Digest的情况下,传递给服务器的字符串是MD5加密字符串,它比Basic更安全(这是&#39; user:password&#39;字符串的Base64编码)但是,decipherable。因此,在安全性方面,BASIC与FORM身份验证一样安全,而DIGEST是最安全的。总之,如果您的网站完全是HTTPS(我的意思是完全,因为如果某些资源是通过HTTP获取的,例如您的授权标题将对第三方可见)您可以安全地使用BASIC / DIGEST 。

  3. 易于设置。
  4. 缺点

    1. 退出是很棘手的。请参阅herehere。当然,您有一个很好的AJAX请求可以对用户进行身份验证,但您还需要一个?AJAX?注销用户的请求 - 触发浏览器登录窗口再次出现)。 BTW好的servlet 3.0 request.logout()方法does not work properly in this case
    2. 会话超时很难实现。会话到期确实发生(它是servlet容器的工作),但浏览器将在下一个请求上发送授权标头,从而触发重新身份验证。
    3. 没有个性化登录页面。没有。
    4. 难以跟踪经过身份验证的会话。
    5.   

      2。基于表单的身份验证

       <security-constraint>
           <web-resource-collection>
              <web-resource-name>admin</web-resource-name>
              <url-pattern>/protected/*</url-pattern>
           </web-resource-collection>
           <auth-constraint>
              <role-name>admin</role-name>
           </auth-constraint>
      </security-constraint>
      <login-config>
          <auth-method>FORM</auth-method>
          <realm-name>as-defined-security-realm</realm-name>
          <form-login-config>
              <form-login-page>/auth/login.html</form-login-page>
              <form-error-page>/auth/error.html</form-error-page>
          </form-login-config>
      </login-config>
      

      简而言之,如果用户访问protected/*网址,则响应中的登录页面包含。因此,用户期望他将获得在form-login-page标记中配置的登录页面而不是内容。如果密码正常,他将被转发(302 Paged Moved Permanently)到最初请求的protected/*网址。如果密码为NOK,则会将用户转发(永久移动分页)到错误页面。

      优点

      1. 个性化登录页面 - 这个似乎是最受欢迎的:)
      2. 注销很容易实现。只需要使HttpSession无效或调用request.logout()方法(Servlet 3.0)。
      3. 会话超时
      4. IF和ONLY如果您接受单独的登录页面,那么这就是您的解决方案。
      5. 缺点

        1. REST不友好(我不打算挖掘休息的哲学,保持服务器端状态不是RESTful辩论。我们以JAVA EE方式分析REST身份验证,服务器端状态是始终保持任何经过身份验证的主题)。使用FORM身份验证的真正原因是,不能在浏览器之间保持一致的行为。这完全归功于302重定向,一些浏览器在AJAX响应函数中处理,而其他浏览器重定向整个页面(更改导航栏中的URL)。更多详情herehere。您无法解决302重定向问题,因此您没有为您提供FORM和REST身份验证!
        2.   

          第3。程序化身份验证

          设置用于身份验证的URL。在该URL后面,您可以拥有一个servlet,它实例化一个登录模块(JAAS方式)并调用HttpServletRequest.login(user,pass)方法以及凭据。如果登录失败,它应该生成401/403响应。

          您可以通过在web.xml中指定安全性约束来实现它:

          <security-constraint>
               <web-resource-collection>
                  <web-resource-name>admin</web-resource-name>
                  <url-pattern>/protected/*</url-pattern>
               </web-resource-collection>
               <auth-constraint>
                  <role-name>admin</role-name>
               </auth-constraint>
          </security-constraint>
          

          在服务器端,您只需设置一个RESTFul服务,该服务对呼叫者进行身份验证。以下是一些示例代码:

          @Path("/auth")
          @ApplicationPath("/rest")
          public class AuthenticationRestFacade {
          
          @POST
          @Path("/login")
          @Consumes(MediaType.APPLICATION_JSON)
          @Produces(MediaType.APPLICATION_JSON)
          public User login(User loginInfo, @Context HttpServletRequest request) throws LoginException, ServletException {
          
              // nasty work-around for Catalina AuthenticatorBase to be able to 
              // change/create the session cookie 
              request.getSession();
              request.login(loginInfo.getName(), loginInfo.getPassword());
          

          优点

          1. 个性化登录页面。
          2. 兼容AJAX / REST
          3. 退出网址(如果设置了网址)
          4. 会话超时(容器管理)
          5. 您可以在回复中返回登录数据(用户名,电子邮件,角色,群组等)(非常好,因为您在成功登录后不必再拨打电话)
          6. 缺点

            1. 需要一些代码编写。
            2. 需要应用程序能够处理401/403响应并显示登录窗口
            3. 总而言之,最好的可行选择:

              1. 如果您不关心会话超时或注销 - &gt; DIGEST
              2. 如果以上内容对您不起作用,并且您不需要拥有嵌入式登录页面(或类似模板面板的页面),您可以使用一个页面进行身份验证 - &gt; FORM
              3. 如果以上内容对您不起作用,并且您希望全世界的所有灵活性和兼容性符合PROGRAMMATIC方法。您必须定义登录/注销URL,并且您的客户端代码应该能够处理401/403响应(不容易)。
              4. 真的很期待你们提出一些可行的替代解决方案。因为现在我讨厌采用PROGRAMMATIC方法

2 个答案:

答案 0 :(得分:3)

根据我的经验,很难使用Java EE身份验证和授权服务来实现一个系统,该服务同时适用于REST服务和服务器端MVC(如JSP或JSF)。我的所有经验都倾向于为MVC部分使用基于表单的身份验证,以及为REST服务使用某种令牌身份验证(OAuth,Kerberos,LTPA)。使用REST服务的表单或基本身份验证通常很难实现,尽管我们这样做了,它在两个项目上运行良好。

它还取决于首选的服务器实现。

答案 1 :(得分:0)

可能有争议的是这些是否是RESTful,但至少可以解决以下问题:

Keberos 怎么样? 使用Windows AD等身份验证服务器

公钥证书怎么样?依靠客户提供的证书来识别用户......

令牌怎么样?第三方令牌发行商,例如OpenID ......