JavaRush /Java 博客 /Random-ZH /JAAS - 技术简介(第 2 部分)
Viacheslav
第 3 级

JAAS - 技术简介(第 2 部分)

已在 Random-ZH 群组中发布
继续有关 JAAS 的文章第一部分。我们来弄清楚JAAS是否可以只使用注解,以及会遇到什么问题。我们将在这一部分中了解哪些 Servlet API 工具可以让我们使代码更加通用。让我们总结一下我们读到的内容。
JAAS - 技术简介(第 2 部分)- 1

延续

在 JAAS 技术回顾的第一部分(参见“ JAAS - 技术简介(第 1 部分) ”)中,我们研究了 JAAS 和 Servlet API 的主要用例。我们看到 Tomcat servlet 容器使用 JAAS 架构来管理 Web 应用程序的安全性。了解了“auth-method”和“Security Realm”之后,Tomcat 容器本身为我们提供了身份验证机制的必要实现,并为我们提供了 CallbackHandler,我们只需在登录模块中使用它即可。唯一需要记住的重要事情是浏览器保存通过 BASIC 身份验证传输的登录名和密码数据。因此,对于使用 Chrome 进行的每次新扫描,您可以按Ctrl+Shift+N打开一个新窗口以在隐身模式下工作。
JAAS - 技术简介(第 2 部分)- 2

注释

使用 XML 进行配置早已过时。因此,重要的是,从 Servlet API 3.0 版开始,我们有机会使用注释来设置 servlet 设置,而无需使用 web.xml 部署描述符文件。让我们看看如果使用注释,安全管理将如何改变。是否可以使用注释来实现上述方法?Servlet API 规范及其“注释和可插拔性”部分将再次帮助我们理解注释。本节说明 servlet 声明web.xml可以用注释代替@WebServlet。因此,我们的 servlet 将如下所示:
@WebServlet(name="app", urlPatterns = "/secret")
public class App extends HttpServlet {
接下来,我们看“ 13.3 程序安全”章节。它说我们还可以通过注释声明安全约束:
@WebServlet(name="app", urlPatterns = "/secret")
@ServletSecurity(httpMethodConstraints = {
        @HttpMethodConstraint(value = "GET", rolesAllowed = "admin")
})
public class App extends HttpServlet {
现在web.xml我们的只剩下一个街区了—— login-config。问题是,碰巧没有办法轻松简单地更换它。由于 Web 应用程序安全设置和 Web 服务器安全设置之间的紧密联系,因此没有简单且通用的方法来执行此操作,即使是通过编程也是如此。这是使用 JAAS 和 Servlet API 进行身份验证的问题之一。说到块login-config,值得理解的是,它是身份验证机制的声明性描述,即 身份验证机制。仍然没有简单的通用方法来替代它,因为...... 处理web.xml发生在 servlet 容器的深处。例如,在 Tomcat 中,您可以查看源ContextConfig.java。因此,即使对于 Tomcat servlet 容器,也有多种选择,而且它们都是不同的。例如,如果我们使用嵌入式 Tomcat servlet 容器(即我们从代码启动 Web 服务器),那么您可以在此处阅读有关此类选项的信息:​​“通过代码进行基本身份验证的嵌入式 Tomcat ”。另外,提高Embedde Tomcat的一般示例可以在Heroku PaaS平台指南中看到:“使用嵌入式Tomcat创建Java Web应用程序”。如果Tomcat不是在Embedded模式下使用,那么对于Tomcat你可以使用一种常用的方式——事件监听器。在 Tomcat 中,这是“生命周期监听器组件”。同时,重要的是要了解 servlet 容器(在我们的例子中是 Tomcat)可能有自己的类加载器,并且不可能简单地获取和使用您的类。对于Tomcat你需要了解“ Class Loader HOW-TO ”。在另一个名为 Undertow 的 servlet 容器中,这可以使用“ Servlet Extensions ”来实现。正如您所看到的,有些提供了更灵活的机制,而另一些则没有。正如您所看到的,没有单一的选择。他们都很不同。是否有可能仅使用 Servlet API 和 JAAS 来做一些通用的事情?在Internet上您可以找到使用Servlet Filter来执行无阻塞身份验证的建议login-config。最后让我们考虑一下这个选项。这将使我们能够重复 JAAS 的工作原理。
JAAS - 技术简介(第 2 部分)- 3

验证过滤器

因此,我们的目标是完全删除web.xml该文件。如果我们摆脱它,那么不幸的是,我们将无法再使用安全约束,因为 它们的处理可以比应用 servlet 过滤器早得多。这是您为使用过滤器的“多功能性”而必须支付的费用。那些。我们必须删除注释@ServletSecurity,并且我们之前在安全约束中描述的所有检查都必须以编程方式执行。正如您所看到的,这个选项也给我们带来了许多令人不快的限制。首先,让我们@ServletSecurity从资源中删除注释并login-configweb.xml. 现在,我们自己必须实施基本身份验证。现在让我们添加过滤器:
@WebFilter("/*")
public class JaasFilter implements javax.servlet.Filter {
到目前为止看起来很简单。我们来写一个初始化方法:
@Override
public void init(FilterConfig filterConfig) throws ServletException {
	String jaas_conf = filterConfig.getServletContext().getRealPath("/WEB-INF/jaas.config");
	System.getProperties().setProperty("java.security.auth.login.config",jaas_conf);
}
正如您所看到的,我们现在被迫使用基本的 JAAS 工具来搜索 jaas 配置文件。这有一个很大的缺点 - 如果有多个应用程序,那么一个应用程序可能会破坏另一个应用程序的身份验证。JAAS 文档中详细描述了通常如何设置 Jaas 配置文件:“附录 A:java.security 安全属性文件中的 JAAS 设置”。接下来,我们将描述过滤方法本身。让我们从接收 HTTP 请求开始:
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
	HttpServletRequest req = (HttpServletRequest) request;
	// Если в реквесте уже есть Principal - ничего не делаем
	if (req.getUserPrincipal() != null ) {
		chain.doFilter(request, response);
	}
这里一切都很简单。如果主体可用,则身份验证成功。接下来,您需要描述当用户未通过身份验证时过滤器的操作,即 他还没有被认出。前面我们描述了基本身份验证方法 BASIC。因为 由于我们现在自己编写过滤器,因此我们必须弄清楚 BASIC 身份验证的实际工作原理。您可以使用“ MDN Web 文档:HTTP 授权”。还有“ HTTP 身份验证如何工作? ” 从Basic身份验证如何工作的描述中可以清楚地看出,如果服务器想要执行BASIC身份验证,并且用户没有提供数据,那么服务器会发送一个特殊的标头“WWW-Authenticate”和错误代码401。让我们创建一个内部方法:
private void requestNewAuthInResponse(ServletResponse response) throws IOException {
	HttpServletResponse resp = (HttpServletResponse) response;
	String value = "Basic realm=\"JaasLogin\"";
	resp.setHeader("WWW-Authenticate", value);
	resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
现在让我们使用这个方法并将doFilter以下代码块添加到该方法中:
// Получаем security Header. А если его нет - запрашиваем
String secHeader = req.getHeader("authorization");
if (secHeader == null) {
	requestNewAuthInResponse(response);
}
现在让我们添加一个分支if,它将在标头已经传输时执行:
// Проверяем аутентификацию
else {
	String authorization = secHeader.replace("Basic ", "");
	Base64.Decoder decoder = java.util.Base64.getDecoder();
	authorization = new String(decoder.decode(authorization));
	String[] loginData = authorization.split(":");
	try {
		if (loginData.length == 2) {
			req.login(loginData[0], loginData[1]);
			chain.doFilter(request, response);
		} else {
			requestNewAuthInResponse(response);
		}
	} catch (ServletException e) {
		requestNewAuthInResponse(response);
	}
}
你可以给这段代码添加授权,例如:req.isUserInRole("admin") 这样我们就用过滤器给你做了认证。一方面,有大量的代码和手动处理。另一方面,具有多功能性和服务器独立性。
JAAS - 技术简介(第 2 部分)- 4

结论

现在我们已经结束了本次审查。我希望现在能更清楚什么是 JAAS、什么是主题以及什么是主体。安全领域和登录配置这两个词将不再引起问题。此外,我们现在知道如何一起使用 JAAS 和 Servlet API。此外,我们还了解了 Servlet API 中的注释无法拯救我们的瓶颈。当然,这还不是全部。例如,Java 中的身份验证可能不仅仅是 BASIC。您可以在“ 13.6 身份验证”部分中查看 Servlet API 规范中的其他类型。在互联网上很难找到有关 JAAS 的详细信息。但我可以推荐这个材料: 我希望这篇评论中的信息有用且易于理解。#维亚切斯拉夫
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION