{"title":"加密签名","version":"5.1","locale":"zh-hans","docname":"topics/signing","url":"/zh-hans/5.1/topics/signing/","canonical":"https://djangodocs.dev/zh-hans/5.1/topics/signing/","summary":"Web 应用安全的黄金法则是永远不要信任来自不可信来源的数据。有时，通过不可信渠道传递数据可能会很有用。通过加密签名的值可以通过不可信渠道传递，因为我们可以安全地知道任何篡改都将被检测到。 Django 提供了用于签名值的低级 API 和用于设置和读取签名 cookie 的高级 API，签名在 web…","html":"<span id=\"cryptographic-signing\"></span><h1>加密签名<a class=\"heading-anchor\" href=\"#module-django.core.signing\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>Web 应用安全的黄金法则是永远不要信任来自不可信来源的数据。有时，通过不可信渠道传递数据可能会很有用。通过加密签名的值可以通过不可信渠道传递，因为我们可以安全地知道任何篡改都将被检测到。</p>\n<p>Django 提供了用于签名值的低级 API 和用于设置和读取签名 cookie 的高级 API，签名在 web 应用程序中最常见的用途之一就是签名 cookie。</p>\n<p>你可能还发现签名对以下方面很有用：</p>\n<ul class=\"simple\">\n<li><p>生成“找回我的账户”URL 以发送给丢失密码的用户。</p></li>\n<li><p>确认存储在表单隐藏字段中的数据未被篡改。</p></li>\n<li><p>生成一次性的秘密 URL，允许临时访问受保护的资源，例如用户付费下载的文件。</p></li>\n</ul>\n<section id=\"protecting-secret-key-and-secret-key-fallbacks\">\n<h2>保护 <code class=\"docutils literal notranslate\">SECRET_KEY</code> 和 <code class=\"docutils literal notranslate\">SECRET_KEY_FALLBACKS</code><a class=\"heading-anchor\" href=\"#protecting-secret-key-and-secret-key-fallbacks\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>当你使用 <a class=\"reference internal\" href=\"/zh-hans/5.1/ref/django-admin/#django-admin-startproject\"><code class=\"xref std std-djadmin docutils literal notranslate\">startproject</code></a> 创建一个新的Django项目时，<code class=\"docutils literal notranslate\">settings.py</code> 文件会自动生成，并随机得到一个 <a class=\"reference internal\" href=\"/zh-hans/5.1/ref/settings/#std-setting-SECRET_KEY\"><code class=\"xref std std-setting docutils literal notranslate\">SECRET_KEY</code></a> 值。这个值是保证签名数据安全的关键——你必须保证这个值的安全，否则攻击者可以用它来生成自己的签名值。</p>\n<p><a class=\"reference internal\" href=\"/zh-hans/5.1/ref/settings/#std-setting-SECRET_KEY_FALLBACKS\"><code class=\"xref std std-setting docutils literal notranslate\">SECRET_KEY_FALLBACKS</code></a> 可以用于轮换密钥。这些值不会用于签署数据，但如果指定了，它们将用于验证签署的数据，并必须保持安全。</p>\n</section>\n<section id=\"using-the-low-level-api\">\n<h2>使用低级 API<a class=\"heading-anchor\" href=\"#using-the-low-level-api\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Django 的签名方法位于 <code class=\"docutils literal notranslate\">django.core.signing</code> 模块中。要签署一个值，首先实例化一个 <code class=\"docutils literal notranslate\">Signer</code> 实例：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.core.signing</span> <span class=\"kn\">import</span> Signer\n<span class=\"gp\">&gt;&gt;&gt; </span>signer <span class=\"o\">=</span> Signer<span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>value <span class=\"o\">=</span> signer<span class=\"o\">.</span>sign<span class=\"p\">(</span><span class=\"s2\">&quot;My string&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>value\n<span class=\"go\">&#39;My string:GdMGD6HNQ_qdgxYP8yBZAdAIV1w&#39;</span>\n</code></pre></div>\n<p>签名被追加到字符串的末尾，跟在冒号后面。你可以使用 <code class=\"docutils literal notranslate\">unsign</code> 方法检索原始值：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>original <span class=\"o\">=</span> signer<span class=\"o\">.</span>unsign<span class=\"p\">(</span>value<span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>original\n<span class=\"go\">&#39;My string&#39;</span>\n</code></pre></div>\n<p>如果你将一个非字符串值传递给 <code class=\"docutils literal notranslate\">sign</code>，该值将在签名之前被强制转换为字符串，而 <code class=\"docutils literal notranslate\">unsign</code> 的结果将给你该字符串值：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>signed <span class=\"o\">=</span> signer<span class=\"o\">.</span>sign<span class=\"p\">(</span><span class=\"mf\">2.5</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>original <span class=\"o\">=</span> signer<span class=\"o\">.</span>unsign<span class=\"p\">(</span>signed<span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>original\n<span class=\"go\">&#39;2.5&#39;</span>\n</code></pre></div>\n<p>如果你希望保护一个列表、元组或字典，可以使用 <code class=\"docutils literal notranslate\">sign_object()</code> 和 <code class=\"docutils literal notranslate\">unsign_object()</code> 方法来实现：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>signed_obj <span class=\"o\">=</span> signer<span class=\"o\">.</span>sign_object<span class=\"p\">({</span><span class=\"s2\">&quot;message&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Hello!&quot;</span><span class=\"p\">})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>signed_obj\n<span class=\"go\">&#39;eyJtZXNzYWdlIjoiSGVsbG8hIn0:Xdc-mOFDjs22KsQAqfVfi8PQSPdo3ckWJxPWwQOFhR4&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>obj <span class=\"o\">=</span> signer<span class=\"o\">.</span>unsign_object<span class=\"p\">(</span>signed_obj<span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>obj\n<span class=\"go\">{&#39;message&#39;: &#39;Hello!&#39;}</span>\n</code></pre></div>\n<p>详见 <a class=\"reference internal\" href=\"#signing-complex-data\"><span class=\"std std-ref\">保护复杂的数据结构</span></a>。</p>\n<p>如果签名或值已经被以任何方式更改，将会引发 <code class=\"docutils literal notranslate\">django.core.signing.BadSignature</code> 异常：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.core</span> <span class=\"kn\">import</span> signing\n<span class=\"gp\">&gt;&gt;&gt; </span>value <span class=\"o\">+=</span> <span class=\"s2\">&quot;m&quot;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">try</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>    original <span class=\"o\">=</span> signer<span class=\"o\">.</span>unsign<span class=\"p\">(</span>value<span class=\"p\">)</span>\n<span class=\"gp\">... </span><span class=\"k\">except</span> signing<span class=\"o\">.</span>BadSignature<span class=\"p\">:</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&quot;Tampering detected!&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">...</span>\n</code></pre></div>\n<p>默认情况下，<code class=\"docutils literal notranslate\">Signer</code> 类使用 <a class=\"reference internal\" href=\"/zh-hans/5.1/ref/settings/#std-setting-SECRET_KEY\"><code class=\"xref std std-setting docutils literal notranslate\">SECRET_KEY</code></a> 设置来生成签名。你可以通过将不同的秘钥传递给 <code class=\"docutils literal notranslate\">Signer</code> 构造函数来使用不同的秘钥：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>signer <span class=\"o\">=</span> Signer<span class=\"p\">(</span>key<span class=\"o\">=</span><span class=\"s2\">&quot;my-other-secret&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>value <span class=\"o\">=</span> signer<span class=\"o\">.</span>sign<span class=\"p\">(</span><span class=\"s2\">&quot;My string&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>value\n<span class=\"go\">&#39;My string:EkfQJafvGyiofrdGnuthdxImIJw&#39;</span>\n</code></pre></div>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.core.signing.Signer\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-name descname\">Signer</span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"keyword-only-separator o\"><abbr title=\"Keyword-only parameters separator (PEP 3102)\">*</abbr></span></em>, <em class=\"sig-param\">key<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">sep<span class=\"o\">=</span><span class=\"default_value\">':'</span></em>, <em class=\"sig-param\">salt<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">algorithm<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">fallback_keys<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.signing.Signer\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>返回一个使用 <code class=\"docutils literal notranslate\">key</code> 生成签名并使用 <code class=\"docutils literal notranslate\">sep</code> 分隔值的签名器。<code class=\"docutils literal notranslate\">sep</code> 不能包含在 <span class=\"target\" id=\"index-2\"></span><a class=\"rfc reference external\" href=\"https://datatracker.ietf.org/doc/html/rfc4648.html#section-5\"><strong>URL 安全的 base64 字母表</strong></a> 中。这个字母表包含字母数字字符、连字符和下划线。<code class=\"docutils literal notranslate\">algorithm</code> 必须是 <a class=\"reference external\" href=\"https://docs.python.org/3/library/hashlib.html#module-hashlib\" title=\"(in Python v3.14)\"><code class=\"xref py py-mod docutils literal notranslate\">hashlib</code></a> 支持的算法，默认值为 <code class=\"docutils literal notranslate\">'sha256'</code>。<code class=\"docutils literal notranslate\">fallback_keys</code> 是一个用于验证签名数据的附加值列表，默认为 <a class=\"reference internal\" href=\"/zh-hans/5.1/ref/settings/#std-setting-SECRET_KEY_FALLBACKS\"><code class=\"xref std std-setting docutils literal notranslate\">SECRET_KEY_FALLBACKS</code></a>。</p>\n</dd></dl>\n\n<section id=\"using-the-salt-argument\">\n<h3>使用 <code class=\"docutils literal notranslate\">salt</code> 参数<a class=\"heading-anchor\" href=\"#using-the-salt-argument\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果你不希望每次出现特定字符串时都具有相同的签名哈希值，可以使用 <code class=\"docutils literal notranslate\">Signer</code> 类的可选参数 <code class=\"docutils literal notranslate\">salt</code>。使用盐会为签名哈希函数提供盐和你的 <a class=\"reference internal\" href=\"/zh-hans/5.1/ref/settings/#std-setting-SECRET_KEY\"><code class=\"xref std std-setting docutils literal notranslate\">SECRET_KEY</code></a>：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>signer <span class=\"o\">=</span> Signer<span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>signer<span class=\"o\">.</span>sign<span class=\"p\">(</span><span class=\"s2\">&quot;My string&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">&#39;My string:GdMGD6HNQ_qdgxYP8yBZAdAIV1w&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>signer<span class=\"o\">.</span>sign_object<span class=\"p\">({</span><span class=\"s2\">&quot;message&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Hello!&quot;</span><span class=\"p\">})</span>\n<span class=\"go\">&#39;eyJtZXNzYWdlIjoiSGVsbG8hIn0:Xdc-mOFDjs22KsQAqfVfi8PQSPdo3ckWJxPWwQOFhR4&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>signer <span class=\"o\">=</span> Signer<span class=\"p\">(</span>salt<span class=\"o\">=</span><span class=\"s2\">&quot;extra&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>signer<span class=\"o\">.</span>sign<span class=\"p\">(</span><span class=\"s2\">&quot;My string&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">&#39;My string:Ee7vGi-ING6n02gkcJ-QLHg6vFw&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>signer<span class=\"o\">.</span>unsign<span class=\"p\">(</span><span class=\"s2\">&quot;My string:Ee7vGi-ING6n02gkcJ-QLHg6vFw&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">&#39;My string&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>signer<span class=\"o\">.</span>sign_object<span class=\"p\">({</span><span class=\"s2\">&quot;message&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Hello!&quot;</span><span class=\"p\">})</span>\n<span class=\"go\">&#39;eyJtZXNzYWdlIjoiSGVsbG8hIn0:-UWSLCE-oUAHzhkHviYz3SOZYBjFKllEOyVZNuUtM-I&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>signer<span class=\"o\">.</span>unsign_object<span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"s2\">&quot;eyJtZXNzYWdlIjoiSGVsbG8hIn0:-UWSLCE-oUAHzhkHviYz3SOZYBjFKllEOyVZNuUtM-I&quot;</span>\n<span class=\"gp\">... </span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;message&#39;: &#39;Hello!&#39;}</span>\n</code></pre></div>\n<p>以这种方式使用盐，会将不同的签名放入不同的命名空间。 来自一个命名空间的签名（一个特定的盐值）不能用于验证在使用不同盐值设置的不同命名空间中的同一明文字符串。这样做的结果是防止攻击者将代码中某个地方生成的签名字符串作为输入，输入到使用不同盐值生成（和验证）签名的另一段代码中。</p>\n<p>与你的 <a class=\"reference internal\" href=\"/zh-hans/5.1/ref/settings/#std-setting-SECRET_KEY\"><code class=\"xref std std-setting docutils literal notranslate\">SECRET_KEY</code></a> 不同，你的盐参数不需要保密。</p>\n</section>\n<section id=\"verifying-timestamped-values\">\n<h3>验证时间戳值<a class=\"heading-anchor\" href=\"#verifying-timestamped-values\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p><code class=\"docutils literal notranslate\">TimestampSigner</code> 是 <a class=\"reference internal\" href=\"#django.core.signing.Signer\" title=\"django.core.signing.Signer\"><code class=\"xref py py-class docutils literal notranslate\">Signer</code></a> 的子类，它会在值后附加一个带签名的时间戳。这允许你确认一个签名值是否在指定的时间段内创建：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">datetime</span> <span class=\"kn\">import</span> timedelta\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.core.signing</span> <span class=\"kn\">import</span> TimestampSigner\n<span class=\"gp\">&gt;&gt;&gt; </span>signer <span class=\"o\">=</span> TimestampSigner<span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>value <span class=\"o\">=</span> signer<span class=\"o\">.</span>sign<span class=\"p\">(</span><span class=\"s2\">&quot;hello&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>value\n<span class=\"go\">&#39;hello:1NMg5H:oPVuCqlJWmChm1rA2lyTUtelC-c&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>signer<span class=\"o\">.</span>unsign<span class=\"p\">(</span>value<span class=\"p\">)</span>\n<span class=\"go\">&#39;hello&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>signer<span class=\"o\">.</span>unsign<span class=\"p\">(</span>value<span class=\"p\">,</span> max_age<span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"go\">SignatureExpired: Signature age 15.5289158821 &gt; 10 seconds</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>signer<span class=\"o\">.</span>unsign<span class=\"p\">(</span>value<span class=\"p\">,</span> max_age<span class=\"o\">=</span><span class=\"mi\">20</span><span class=\"p\">)</span>\n<span class=\"go\">&#39;hello&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>signer<span class=\"o\">.</span>unsign<span class=\"p\">(</span>value<span class=\"p\">,</span> max_age<span class=\"o\">=</span>timedelta<span class=\"p\">(</span>seconds<span class=\"o\">=</span><span class=\"mi\">20</span><span class=\"p\">))</span>\n<span class=\"go\">&#39;hello&#39;</span>\n</code></pre></div>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.core.signing.TimestampSigner\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-name descname\">TimestampSigner</span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"keyword-only-separator o\"><abbr title=\"Keyword-only parameters separator (PEP 3102)\">*</abbr></span></em>, <em class=\"sig-param\">key<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">sep<span class=\"o\">=</span><span class=\"default_value\">':'</span></em>, <em class=\"sig-param\">salt<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">algorithm<span class=\"o\">=</span><span class=\"default_value\">'sha256'</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.signing.TimestampSigner\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.core.signing.TimestampSigner.sign\">\n<span class=\"sig-name descname\">sign</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">value</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.signing.TimestampSigner.sign\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>签名 <code class=\"docutils literal notranslate\">value</code> 并附加当前时间戳。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.core.signing.TimestampSigner.unsign\">\n<span class=\"sig-name descname\">unsign</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">value</em>, <em class=\"sig-param\">max_age<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.signing.TimestampSigner.unsign\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>检查 <code class=\"docutils literal notranslate\">value</code> 是否在 <code class=\"docutils literal notranslate\">max_age</code> 秒前被签署，否则引发 <code class=\"docutils literal notranslate\">SignatureExpired</code>。<code class=\"docutils literal notranslate\">max_age</code> 参数可以接受一个整数或一个 <a class=\"reference external\" href=\"https://docs.python.org/3/library/datetime.html#datetime.timedelta\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">datetime.timedelta</code></a> 对象。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.core.signing.TimestampSigner.sign_object\">\n<span class=\"sig-name descname\">sign_object</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">obj</em>, <em class=\"sig-param\">serializer<span class=\"o\">=</span><span class=\"default_value\">JSONSerializer</span></em>, <em class=\"sig-param\">compress<span class=\"o\">=</span><span class=\"default_value\">False</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.signing.TimestampSigner.sign_object\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>对复杂的数据结构（例如列表、元组或字典）进行编码，可选地压缩数据，追加当前时间戳，并对其进行签名。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.core.signing.TimestampSigner.unsign_object\">\n<span class=\"sig-name descname\">unsign_object</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">signed_obj</em>, <em class=\"sig-param\">serializer<span class=\"o\">=</span><span class=\"default_value\">JSONSerializer</span></em>, <em class=\"sig-param\">max_age<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.signing.TimestampSigner.unsign_object\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>检查 <code class=\"docutils literal notranslate\">signed_obj</code> 是否在不超过 <code class=\"docutils literal notranslate\">max_age</code> 秒之前签名，否则会引发 <code class=\"docutils literal notranslate\">SignatureExpired</code> 异常。<code class=\"docutils literal notranslate\">max_age</code> 参数可以接受整数或 <a class=\"reference external\" href=\"https://docs.python.org/3/library/datetime.html#datetime.timedelta\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">datetime.timedelta</code></a> 对象。</p>\n</dd></dl>\n\n</dd></dl>\n\n</section>\n<section id=\"protecting-complex-data-structures\">\n<span id=\"signing-complex-data\"></span><h3>保护复杂的数据结构<a class=\"heading-anchor\" href=\"#protecting-complex-data-structures\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果你希望保护一个列表、元组或字典，可以使用 <code class=\"docutils literal notranslate\">Signer.sign_object()</code> 和 <code class=\"docutils literal notranslate\">unsign_object()</code> 方法，或者使用签名模块的 <code class=\"docutils literal notranslate\">dumps()</code> 或 <code class=\"docutils literal notranslate\">loads()</code> 函数（它们是 <code class=\"docutils literal notranslate\">TimestampSigner(salt='django.core.signing').sign_object()/unsign_object()</code> 的快捷方式）。这些方法在底层使用了 JSON 序列化。JSON 确保即使你的 <a class=\"reference internal\" href=\"/zh-hans/5.1/ref/settings/#std-setting-SECRET_KEY\"><code class=\"xref std std-setting docutils literal notranslate\">SECRET_KEY</code></a> 被窃取，攻击者也无法通过利用 pickle 格式来执行任意命令：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.core</span> <span class=\"kn\">import</span> signing\n<span class=\"gp\">&gt;&gt;&gt; </span>signer <span class=\"o\">=</span> signing<span class=\"o\">.</span>TimestampSigner<span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>value <span class=\"o\">=</span> signer<span class=\"o\">.</span>sign_object<span class=\"p\">({</span><span class=\"s2\">&quot;foo&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;bar&quot;</span><span class=\"p\">})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>value\n<span class=\"go\">&#39;eyJmb28iOiJiYXIifQ:1kx6R3:D4qGKiptAqo5QW9iv4eNLc6xl4RwiFfes6oOcYhkYnc&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>signer<span class=\"o\">.</span>unsign_object<span class=\"p\">(</span>value<span class=\"p\">)</span>\n<span class=\"go\">{&#39;foo&#39;: &#39;bar&#39;}</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>value <span class=\"o\">=</span> signing<span class=\"o\">.</span>dumps<span class=\"p\">({</span><span class=\"s2\">&quot;foo&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;bar&quot;</span><span class=\"p\">})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>value\n<span class=\"go\">&#39;eyJmb28iOiJiYXIifQ:1kx6Rf:LBB39RQmME-SRvilheUe5EmPYRbuDBgQp2tCAi7KGLk&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>signing<span class=\"o\">.</span>loads<span class=\"p\">(</span>value<span class=\"p\">)</span>\n<span class=\"go\">{&#39;foo&#39;: &#39;bar&#39;}</span>\n</code></pre></div>\n<p>由于 JSON 的性质（没有本地区分列表和元组的方式），如果你传递一个元组，你将从 <code class=\"docutils literal notranslate\">signing.loads(object)</code> 得到一个列表：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.core</span> <span class=\"kn\">import</span> signing\n<span class=\"gp\">&gt;&gt;&gt; </span>value <span class=\"o\">=</span> signing<span class=\"o\">.</span>dumps<span class=\"p\">((</span><span class=\"s2\">&quot;a&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;b&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;c&quot;</span><span class=\"p\">))</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>signing<span class=\"o\">.</span>loads<span class=\"p\">(</span>value<span class=\"p\">)</span>\n<span class=\"go\">[&#39;a&#39;, &#39;b&#39;, &#39;c&#39;]</span>\n</code></pre></div>\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.core.signing.dumps\">\n<span class=\"sig-name descname\">dumps</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">obj</em>, <em class=\"sig-param\">key<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">salt<span class=\"o\">=</span><span class=\"default_value\">'django.core.signing'</span></em>, <em class=\"sig-param\">serializer<span class=\"o\">=</span><span class=\"default_value\">JSONSerializer</span></em>, <em class=\"sig-param\">compress<span class=\"o\">=</span><span class=\"default_value\">False</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.signing.dumps\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>返回 URL 安全的，经过签名的 base64 压缩 JSON 字符串。使用 <a class=\"reference internal\" href=\"#django.core.signing.TimestampSigner\" title=\"django.core.signing.TimestampSigner\"><code class=\"xref py py-class docutils literal notranslate\">TimestampSigner</code></a> 对序列化对象进行签名。</p>\n</dd></dl>\n\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.core.signing.loads\">\n<span class=\"sig-name descname\">loads</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">string</em>, <em class=\"sig-param\">key<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">salt<span class=\"o\">=</span><span class=\"default_value\">'django.core.signing'</span></em>, <em class=\"sig-param\">serializer<span class=\"o\">=</span><span class=\"default_value\">JSONSerializer</span></em>, <em class=\"sig-param\">max_age<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">fallback_keys<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.signing.loads\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>与 <code class=\"docutils literal notranslate\">dumps()</code> 相反，如果签名失败引发 <code class=\"docutils literal notranslate\">BadSignature</code>。如果给定，则检查 <code class=\"docutils literal notranslate\">max_age</code> （以秒为单位）。</p>\n</dd></dl>\n\n</section>\n</section>","rootId":"module-django.core.signing","toc":[{"title":"保护 SECRET_KEY 和 SECRET_KEY_FALLBACKS","anchor":"protecting-secret-key-and-secret-key-fallbacks","children":[]},{"title":"使用低级 API","anchor":"using-the-low-level-api","children":[{"title":"使用 salt 参数","anchor":"using-the-salt-argument","children":[]},{"title":"验证时间戳值","anchor":"verifying-timestamped-values","children":[]},{"title":"保护复杂的数据结构","anchor":"protecting-complex-data-structures","children":[]}]}],"breadcrumbs":[{"docname":"topics/index","title":"使用 Django","url":"/zh-hans/5.1/topics/"}],"prev":{"docname":"topics/conditional-view-processing","title":"条件视图处理","url":"/zh-hans/5.1/topics/conditional-view-processing/"},"next":{"docname":"topics/email","title":"发送邮件","url":"/zh-hans/5.1/topics/email/"},"formats":{"html":"/zh-hans/5.1/topics/signing/","markdown":"/zh-hans/5.1/topics/signing.md","json":"/zh-hans/5.1/topics/signing.json"},"source":"https://github.com/django/django/blob/stable/5.1.x/docs/topics/signing.txt","official":"https://docs.djangoproject.com/zh-hans/5.1/topics/signing/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0"],"inLocales":["en","zh-hans","fr","ja","id","it","pt-br","ko","es","el","pl"]}