{"title":"加密签名","version":"4.0","locale":"zh-hans","docname":"topics/signing","url":"/zh-hans/4.0/topics/signing/","canonical":"https://djangodocs.dev/zh-hans/4.0/topics/signing/","summary":"The golden rule of web application security is to never trust data from untrusted sources.","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>The golden rule of web application security is to never trust data from\nuntrusted sources. Sometimes it can be useful to pass data through an\nuntrusted medium. Cryptographically signed values can be passed through an\nuntrusted channel safe in the knowledge that any tampering will be detected.</p>\n<p>Django provides both a low-level API for signing values and a high-level API\nfor setting and reading signed cookies, one of the most common uses of\nsigning in web applications.</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-the-secret-key\">\n<h2>保护 <code class=\"docutils literal notranslate\">SECRET_KEY</code><a class=\"heading-anchor\" href=\"#protecting-the-secret-key\"><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/4.0/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/4.0/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=\"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=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</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=\"Code 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=\"s1\">&#39;My string&#39;</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=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</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=\"Code 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=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</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=\"Code 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>If you wish to protect a list, tuple, or dictionary you can do so using the\n<code class=\"docutils literal notranslate\">sign_object()</code> and <code class=\"docutils literal notranslate\">unsign_object()</code> methods:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</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=\"Code 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=\"s1\">&#39;message&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Hello!&#39;</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>See <a class=\"reference internal\" href=\"#signing-complex-data\"><span class=\"std std-ref\">保护复杂的数据结构</span></a> for more details.</p>\n<p>如果签名或值被以任何方式修改，将引发 <code class=\"docutils literal notranslate\">django.core.signing.BadSignature</code> 异常：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</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=\"Code 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=\"s1\">&#39;m&#39;</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</code></pre></div>\n<p>默认情况下，<code class=\"docutils literal notranslate\">Signer</code> 类使用 <a class=\"reference internal\" href=\"/zh-hans/4.0/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=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</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=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>signer <span class=\"o\">=</span> Signer<span class=\"p\">(</span><span class=\"s1\">&#39;my-other-secret&#39;</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=\"s1\">&#39;My string&#39;</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\">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><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>。</p>\n</dd></dl>\n\n<aside class=\"version-note version-changed\" data-version=\"3.2\" role=\"note\">\n<p class=\"version-note-title\">Changed in Django 3.2</p><p>The <code class=\"docutils literal notranslate\">sign_object()</code> and <code class=\"docutils literal notranslate\">unsign_object()</code> methods were added.</p>\n</aside>\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/4.0/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=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</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=\"Code 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=\"s1\">&#39;My string&#39;</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=\"s1\">&#39;message&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Hello!&#39;</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=\"s1\">&#39;extra&#39;</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=\"s1\">&#39;My string&#39;</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=\"s1\">&#39;My string:Ee7vGi-ING6n02gkcJ-QLHg6vFw&#39;</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=\"s1\">&#39;message&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Hello!&#39;</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><span class=\"s1\">&#39;eyJtZXNzYWdlIjoiSGVsbG8hIn0:-UWSLCE-oUAHzhkHviYz3SOZYBjFKllEOyVZNuUtM-I&#39;</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/4.0/ref/settings/#std-setting-SECRET_KEY\"><code class=\"xref std std-setting docutils literal notranslate\">SECRET_KEY</code></a> 不同，你的盐参数不需要保密。</p>\n<aside class=\"version-note version-changed\" data-version=\"3.2\" role=\"note\">\n<p class=\"version-note-title\">Changed in Django 3.2</p><p>The <code class=\"docutils literal notranslate\">sign_object()</code> and <code class=\"docutils literal notranslate\">unsign_object()</code> methods were added.</p>\n</aside>\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=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</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=\"Code 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=\"s1\">&#39;hello&#39;</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=\"gp\">...</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\">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><aside class=\"version-note version-added\" data-version=\"3.2\" role=\"note\">\n<p class=\"version-note-title\">New in Django 3.2</p></aside>\n<p>Encode, optionally compress, append current timestamp, and sign complex\ndata structure (e.g. list, tuple, or dictionary).</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><aside class=\"version-note version-added\" data-version=\"3.2\" role=\"note\">\n<p class=\"version-note-title\">New in Django 3.2</p></aside>\n<p>Checks if <code class=\"docutils literal notranslate\">signed_obj</code> was signed less than <code class=\"docutils literal notranslate\">max_age</code> seconds ago,\notherwise raises <code class=\"docutils literal notranslate\">SignatureExpired</code>. The <code class=\"docutils literal notranslate\">max_age</code> parameter can\naccept an integer or a <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> object.</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>If you wish to protect a list, tuple or dictionary you can do so using the\n<code class=\"docutils literal notranslate\">Signer.sign_object()</code> and <code class=\"docutils literal notranslate\">unsign_object()</code> methods, or signing module's\n<code class=\"docutils literal notranslate\">dumps()</code> or <code class=\"docutils literal notranslate\">loads()</code> functions (which are shortcuts for\n<code class=\"docutils literal notranslate\">TimestampSigner(salt='django.core.signing').sign_object()/unsign_object()</code>).\nThese use JSON serialization under the hood. JSON ensures that even if your\n<a class=\"reference internal\" href=\"/zh-hans/4.0/ref/settings/#std-setting-SECRET_KEY\"><code class=\"xref std std-setting docutils literal notranslate\">SECRET_KEY</code></a> is stolen an attacker will not be able to execute\narbitrary commands by exploiting the pickle format:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</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=\"Code 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=\"s1\">&#39;foo&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;bar&#39;</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=\"s1\">&#39;foo&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;bar&#39;</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=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</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=\"Code 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=\"s1\">&#39;a&#39;</span><span class=\"p\">,</span><span class=\"s1\">&#39;b&#39;</span><span class=\"p\">,</span><span class=\"s1\">&#39;c&#39;</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><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<aside class=\"version-note version-changed\" data-version=\"3.2\" role=\"note\">\n<p class=\"version-note-title\">Changed in Django 3.2</p><p>The <code class=\"docutils literal notranslate\">sign_object()</code> and <code class=\"docutils literal notranslate\">unsign_object()</code> methods were added.</p>\n</aside>\n</section>\n</section>","rootId":"module-django.core.signing","toc":[{"title":"保护 SECRET_KEY","anchor":"protecting-the-secret-key","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/4.0/topics/"}],"prev":{"docname":"topics/conditional-view-processing","title":"条件视图处理","url":"/zh-hans/4.0/topics/conditional-view-processing/"},"next":{"docname":"topics/email","title":"发送邮件","url":"/zh-hans/4.0/topics/email/"},"formats":{"html":"/zh-hans/4.0/topics/signing/","markdown":"/zh-hans/4.0/topics/signing.md","json":"/zh-hans/4.0/topics/signing.json"},"source":"https://github.com/django/django/blob/stable/4.0.x/docs/topics/signing.txt","official":"https://docs.djangoproject.com/zh-hans/4.0/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"]}