tigron/skeleton-application-web

Skeleton 的 Web 应用程序

v1.0.0 2024-09-02 11:48 UTC

This package is auto-updated.

Last update: 2024-09-02 11:49:02 UTC


README

此骨架应用程序将创建一个 Web 应用程序。Web 应用程序将包含模块、模板和事件。

安装

通过 Composer 安装

composer require tigron/skeleton-application-web

设置应用程序

您的 Web 应用程序应遵循以下目录结构

- application_path from skeleton-core
  - APP_NAME
    - config
	- event
	- media
	  - css
	  - font
	  - image
	  - javascript
	- module
	- template

重要的是要理解,每个创建的类都应该在其正确的命名空间中。以下命名空间应被使用

module: \App\{APP_NAME}\Module
event: \App\{APP_NAME}\Event

配置

对于此应用程序,需要 skeleton-core 应用程序配置。更多信息可以在下面找到

路由

一个将 routes 映射到 modules 的数组。可以使用路由定义来生成漂亮的 URL 或翻译版本。最佳用法可以通过示例描述。

[
    'web_module_index' => [
        '$language/default/route/to/index',
        '$language/default/route/to/index/$action',
        '$language/default/route/to/index/$action/$id',
        '$language[en]/test/routing/engine',
        '$language[en]/test/routing/engine/$action',
        '$language[en]/test/routing/engine/$action/$id',
    ],
],

用法

路由到正确的应用程序

基于请求的 Host 标头,将启动正确的应用程序。这是应用程序配置文件(如上所示)中的 hostnames 数组将发挥作用的地方。

如果 skeleton-core 能够根据请求中提供的 Host 标头找到匹配的应用程序,则此应用程序将被启动。

如果您的应用程序已配置 base_uri,则也会考虑这一点。例如:可以通过将其 base_uri 设置为 /admin 来区分 CMS 应用程序。

路由到正确的模块

没有文件扩展名且不匹配 media 文件的请求将路由到模块和匹配的方法。模块根据请求 URI 确定,排除所有 $_GET 参数。模块是一个应该从 \Skeleton\Core\Application\Web\Module 继承的类。

以下是一些示例来说明这一点

如您在最后两个示例中看到的那样,index 模块有点特殊,因为如果它们位于子文件夹中,则可以使用它们代替基础模块。可以通过配置指令 module_default 配置 index

路由到正确的方法

模块可以包含多个可以处理请求的方法。每个这些请求都有一个以 'display' 开头的方法名。方法根据 $_GET['action'] 变量定义。

以下是一些示例

CSRF

skeleton-application-web 软件包可以自动注入和验证它收到的每个 POST 请求的 CSRF 令牌。已经定义了各种事件,您可以通过这些事件来控制 CSRF 流。以下可以找到这些事件的列表。

CSRF 默认情况下全局禁用。如果您想启用它,只需通过配置指令 csrf_enabledcsrf_enabled 标志设置为 true 即可。

启用后,它将适用于所有您的应用程序。如果您只想为特定应用程序禁用它,请在应用程序配置中将 csrf_enabled 标志设置为 false

有多个事件可用于控制 CSRF 行为,以下已进行了说明。

当启用时,具有正确令牌作为值的隐藏表单元素将自动注入到找到的每个 <form>...</form> 块中。这允许它在不需要更改您代码的情况下工作。

如果您需要访问令牌值和名称,您可以从自动分配给模板的 env 变量中访问它们。以下列出了可用的变量:

  • env.csrf_header_token_name
  • env.csrf_post_token_name
  • env.csrf_session_token_name
  • env.csrf_token

有一个需要注意的问题是 XMLHttpRequest 调用(或 AJAX)。如果您的应用程序使用 jQuery,您可以使用下面的示例自动为每个相关的 XMLHttpRequest 注入一个头。

首先,使令牌值和名称对您的视图可用。这样做的一个好地方可能是文档的 <head>...</head> 块。

<!-- CSRF token values -->
<meta name="csrf-header-token-name" content="{{ env.csrf_header_token_name }}">
<meta name="csrf-token" content="{{ env.csrf_token }}">

接下来,我们可以使用 jQuery$.ajaxSend()。这允许您配置将应用于每个后续的 $.ajax() 调用(或其衍生,如 $.post())的设置。

$(document).ajaxSend(function(e, xhr, settings) {
    if (!(/^(GET|HEAD|OPTIONS|TRACE)$/.test(settings.type)) && !this.crossDomain) {
	    xhr.setRequestHeader($('meta[name="csrf-header-token-name"]').attr('content'), $('meta[name="csrf-token"]').attr('content'));
	}
});

请注意对请求类型和跨域请求的检查。这可以避免将令牌随不需要它的请求发送。

重放

内置的重放检测试图通过用户双击提交按钮来解决重复表单提交的问题。通常,这种情况在用户界面中不会被捕获。

默认情况下禁用重放检测,如果您想启用它,将 replay_enabled 配置指令切换为 true。

您可以通过将各自的配置中的 replay_enabled 标志设置为 false 来为单个应用程序禁用重放检测。

当启用重放检测时,它将向每个它可以找到的 form 元素注入一个隐藏的 __replay-token 元素。每个令牌将是唯一的。一旦提交,该令牌将被添加到先前看到的令牌列表中。如果在 30 秒内再次出现相同的令牌,重放检测将被触发。

如果您的应用程序定义了 replay_detected 事件,这将被调用。应用程序必须决定采取什么行动。一个建议是将用户重定向到 HTTP 引用值,如果存在的话。

事件

可以在应用程序执行过程中的特定关键点创建事件以执行任务。此应用程序支持在 skeleton-core 中描述的所有可用事件。此外,以下事件也是可用的:

I18n上下文

get_translator_extractor

获取此应用程序的 Translator\Extractor。如果没有提供,将为应用程序的模板目录创建一个 Translator\Extractor\Twig。

public function get_translator_extractor(): \Skeleton\I18n\Translator\Extractor

get_translator_storage

获取此应用程序的 Translator\Storage。如果没有提供,将创建一个 Translator\Storage\Po,但前提是已配置默认存储路径。

public function get_translator_storage(): \Skeleton\I18n\Translator\Storage

get_translator

获取此应用程序的 Translator 对象。如果不需要翻译,则返回 null。默认情况下,使用上述方法的存储和提取器创建一个翻译器。

public function get_translator(): ?\Skeleton\I18n\Translator

detect_language

检测应用程序的语言。这是分 3 步进行的

  1. 是否有通过 $_GET['language'] 请求的语言
  2. 是否在 $_SESSION['language'] 中存储了语言
  3. 在 $_SERVER['HTTP_ACCEPT_LANGUAGE'] 和所有可用语言之间协商语言。

返回的语言将存储在会话中。

public function detect_language(): \Skeleton\I18n\LanguageInterface

模块上下文

bootstrap

在启动模块之前调用 bootstrap 方法。

public function bootstrap(\Skeleton\Core\Web\Module $module): void

teardown

当模块完成时调用 teardown 方法。

public function bootstrap(\Skeleton\Core\Web\Module $module): void

access_denied

每当请求一个用户无法访问的模块时,都会调用 access_denied 方法。模块中的可选 secure() 方法表示用户是否被授权访问。

public function access_denied(\Skeleton\Core\Web\Module $module): void

not_found

当请求一个不存在的模块时,会调用 not_found 方法。

public function not_found(): void

安全上下文

csrf_validate_enabled

csrf_validate_enabled 方法覆盖了完整的验证执行过程,这对于排除特定的路径非常有用。下面是一个示例实现。

public function csrf_validate_enabled(): bool {
    $excluded_paths = [
        '/no/csrf/*',
    ];

    foreach ($excluded_paths as $excluded_path) {
        if (fnmatch ($excluded_path, $_SERVER['REQUEST_URI']) === true) {
            return false;
        }
    }

    return true;
}

csrf_validate_success

csrf_validate_success 方法允许您在验证成功后覆盖检查结果。它期望返回一个布尔值。

public function csrf_validate_success(): bool

csrf_validate_failed

csrf_validate_failed 方法允许您在验证失败后覆盖检查结果。它期望返回一个布尔值。

public function csrf_validate_failed(): bool

csrf_generate_session_token

csrf_generate_session_token 方法允许您覆盖会话令牌的生成,并生成自定义值。它期望返回一个字符串。

public function csrf_generate_session_token(): string

csrf_inject

csrf_inject 方法允许您覆盖渲染模板的HTML表单中自动注入的隐藏CSRF令牌元素。它期望返回一个字符串,包含要发送回客户端的渲染HTML。

public function csrf_inject($html, $post_token_name, $post_token): string

csrf_validate

csrf_validate 方法允许您覆盖CSRF令牌的验证过程。它期望返回一个布尔值。

public function csrf_validate($submitted_token, $session_token): bool

replay_detected

replay_detected 方法允许您捕获重放检测事件。例如,如果存在HTTP引用头,您可以将用户重定向到该值。

public function replay_detected() {
    if (!empty($_SERVER['HTTP_REFERER'])) {
        Session::redirect($_SERVER['HTTP_REFERER'], false);
    } else {
        Session::redirect('/');
    }
}

replay_inject

replay_inject 方法允许您覆盖渲染模板的HTML表单中自动注入的隐藏重放令牌元素。它期望返回一个字符串,包含要发送回客户端的渲染HTML。

public function csrf_inject($html, $post_token_name, $post_token): string

session_cookie

session_cookie 方法允许您在会话开始之前设置会话cookie参数。通常,这会用于SameSite cookie属性。

public function session_cookie(): void