15年前,我开始在Java EE平台上进行开发(是的,您没看错)。 那时,在Webapp中进行身份验证的唯一方法是通过回调。 最新的Java EE版本提供了替代方法。
这篇文章旨在描述它们的工作方式及其各自的优点。<!-more-→
传统方式
自J2EE 1.3(可能更早,但是我不是考古学家)以来,可用的方法是通过回调机制:平台仅在用户尝试访问受保护的资源时要求用户提供凭据。 如果凭据被接受,则对用户进行身份验证。 然后,将其访问权限与访问资源所需的访问权限进行匹配。 如果他们匹配,他被允许; 否则,他会收到403错误。
这引起了一些问题:
- 什么是资源?
- 如何将访问权限附加到资源?
- 如何要求用户提供凭据?
- 如何配置用户的访问权限?
- 如何注销?
资源和角色
在Java EE Web应用程序中,资源是纯URL:
-
admin
-
secure/configure
- 等等
可以使用简单的模式对资源进行分组(它在开始或结尾处允许*
,但不能更多)。
为了保护一个资源或一组资源,一个资源与一个角色相关联。 角色只是一个字符串。
角色及其相关资源都在web.xml
部署描述符中配置:
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<security-constraint>
<web-resource-collection>
<web-resource-name> Administration </web-resource-name>
<url-pattern> /administration/* </url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name> admin </role-name>
</auth-constraint>
</security-constraint>
<security-role>
<role-name> admin </role-name>
</security-role>
</web-app>
在<security-constraint>中使用角色之前,必须在单独的<security-role>标记中声明角色。
要求提供凭证
Java EE提供了4种验证方式:
- 基本的
- 消化
- 形成
- 和客户证书
我们将只介绍“基础”和“形式”,因为它们是最常用的。
-
基本的
-
基本身份验证基于浏览器。 当未经身份验证的用户尝试访问受保护的资源时,平台将返回401 HTTP状态代码。 浏览器拦截响应,并显示一个本机弹出窗口,要求输入登录名和密码。 如果凭据检查失败,则会再次向用户显示弹出窗口,直到成功为止。
通过身份验证的用户是否可以访问资源取决于其角色。
<?xml version="1.0" encoding="UTF-8"?> <web-app> <login-config> <auth-method> BASIC </auth-method> </login-config> </web-app>
形成
-
表单身份验证基于服务器。 当未经身份验证的用户尝试访问受保护的资源时,平台将返回配置的登录表单。
<?xml version="1.0" encoding="UTF-8"?> <web-app> <login-config> <auth-method> FORM </auth-method> <form-login-config> <form-login-page> /WEB-INF/page/login.jsp </form-login-page> <form-error-page> /WEB-INF/page/error.jsp </form-error-page> </form-login-config> </login-config> </web-app>
注销
过去,注销经过身份验证的用户的方法非常简单:
response.invalidate();
不幸的是,以上代码行有效地破坏了会话中存储的所有内容,包括与身份验证无关的数据,例如用户首选项( 例如主题)。
使用注释
Servlet API的版本3利用了注释,并允许使用它们来限制访问servlet所允许的角色。
例如,以下等效于第一个XML代码段:
@WebServlet("/adminstration/foo")
@ServletSecurity(
@HttpConstraint(rolesAllowed="admin")
)
publicclassFooServletextendsHttpServlet{
}
显然,它对于一个特定的servlet非常有效。 但是,如果不同的servlet需要由同一角色保护,则必须在每个servlet上复制注释。
程序化API
上述身份验证回调的主要问题在于,它是为基于页面的导航而设计的。 如果webapp是单页应用程序 ,则必须使用URL处理技巧才能使其正常工作。
权限检查
Java EE允许保护URL,甚至URL / HTTP方法对。 对于SPA,这还不够。 即使在传统的Web应用程序中,对于某些用例,不同的doXXX()
方法可能也不足够精确。 另外,根据用户角色,JSP的各个部分可能有所不同。
因此,Servlet API提供了HttpServletRequest.isUserInRole(String role)
方法来检查用户是否具有特定角色。
JSTL没有为此提供现成的等效方法。
验证中
像检查一样,绑定到URL的身份验证回调不容易与SPA集成。 为了解决这个问题,Servlet API v3提供了HttpServletRequest.login(String username, String password)
方法,以编程方式对用户进行身份验证。
对称的HttpServletRequest.logout()
方法允许取消对已验证用户的身份验证,而不会丢失此用户会话中存储的数据。
结论
与往常一样,了解可用工具是值得的。 为此,有必要保持最新的API更改。
翻译自: https://blog.frankel.ch/authentication-alternatives-javaee/