{"title":"加密签名","version":"4.1","locale":"zh-hans","docname":"topics/signing","url":"/zh-hans/4.1/topics/signing/","canonical":"https://djangodocs.dev/zh-hans/4.1/topics/signing/","summary":"The golden rule of web application security is to never trust data from untrusted sources. Sometimes it can be useful to pass data through an untrusted medium.…","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-secret-key-and-secret-key-fallbacks\">\n<h2>Protecting <code class=\"docutils literal notranslate\"><span class=\"pre\">SECRET_KEY</span></code> and <code class=\"docutils literal notranslate\"><span class=\"pre\">SECRET_KEY_FALLBACKS</span></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/4.1/ref/django-admin/#django-admin-startproject\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">startproject</span></code></a> 创建一个新的Django项目时，<code class=\"docutils literal notranslate\"><span class=\"pre\">settings.py</span></code> 文件会自动生成，并随机得到一个 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SECRET_KEY\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">SECRET_KEY</span></code></a> 值。这个值是保证签名数据安全的关键——你必须保证这个值的安全，否则攻击者可以用它来生成自己的签名值。</p>\n<p><a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SECRET_KEY_FALLBACKS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">SECRET_KEY_FALLBACKS</span></code></a> can be used to rotate secret keys. The\nvalues will not be used to sign data, but if specified, they will be used to\nvalidate signed data and must be kept secure.</p>\n<aside class=\"version-note version-changed\" data-version=\"4.1\">\n<p class=\"version-note-title\">Changed in Django 4.1</p><p>The <code class=\"docutils literal notranslate\"><span class=\"pre\">SECRET_KEY_FALLBACKS</span></code> setting was added.</p>\n</aside>\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\"><span class=\"pre\">django.core.signing</span></code> 模块中。要签署一个值，首先要实例化一个 <code class=\"docutils literal notranslate\"><span class=\"pre\">Signer</span></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=\"w\"> </span><span class=\"nn\">django.core.signing</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Signer</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">signer</span> <span class=\"o\">=</span> <span class=\"n\">Signer</span><span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">value</span> <span class=\"o\">=</span> <span class=\"n\">signer</span><span class=\"o\">.</span><span class=\"n\">sign</span><span class=\"p\">(</span><span class=\"s1\">&#39;My string&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">value</span>\n<span class=\"go\">&#39;My string:GdMGD6HNQ_qdgxYP8yBZAdAIV1w&#39;</span>\n</code></pre></div>\n<p>签名被附加在字符串的结尾，在冒号之后。你可以使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">unsign</span></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=\"n\">original</span> <span class=\"o\">=</span> <span class=\"n\">signer</span><span class=\"o\">.</span><span class=\"n\">unsign</span><span class=\"p\">(</span><span class=\"n\">value</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">original</span>\n<span class=\"go\">&#39;My string&#39;</span>\n</code></pre></div>\n<p>如果你将非字符串值传递给 <code class=\"docutils literal notranslate\"><span class=\"pre\">sign</span></code>，该值将在被签署前被强制变成字符串，并且 <code class=\"docutils literal notranslate\"><span class=\"pre\">unsign</span></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=\"n\">signed</span> <span class=\"o\">=</span> <span class=\"n\">signer</span><span class=\"o\">.</span><span class=\"n\">sign</span><span class=\"p\">(</span><span class=\"mf\">2.5</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">original</span> <span class=\"o\">=</span> <span class=\"n\">signer</span><span class=\"o\">.</span><span class=\"n\">unsign</span><span class=\"p\">(</span><span class=\"n\">signed</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">original</span>\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\"><span class=\"pre\">sign_object()</span></code> and <code class=\"docutils literal notranslate\"><span class=\"pre\">unsign_object()</span></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><span class=\"n\">signed_obj</span> <span class=\"o\">=</span> <span class=\"n\">signer</span><span class=\"o\">.</span><span class=\"n\">sign_object</span><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><span class=\"n\">signed_obj</span>\n<span class=\"go\">&#39;eyJtZXNzYWdlIjoiSGVsbG8hIn0:Xdc-mOFDjs22KsQAqfVfi8PQSPdo3ckWJxPWwQOFhR4&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">obj</span> <span class=\"o\">=</span> <span class=\"n\">signer</span><span class=\"o\">.</span><span class=\"n\">unsign_object</span><span class=\"p\">(</span><span class=\"n\">signed_obj</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">obj</span>\n<span class=\"go\">{&#39;message&#39;: &#39;Hello!&#39;}</span>\n</code></pre></div>\n<p>详见:ref:signing-complex-data</p>\n<p>如果签名或值被以任何方式修改，将引发 <code class=\"docutils literal notranslate\"><span class=\"pre\">django.core.signing.BadSignature</span></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=\"w\"> </span><span class=\"nn\">django.core</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">signing</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">value</span> <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>   <span class=\"n\">original</span> <span class=\"o\">=</span> <span class=\"n\">signer</span><span class=\"o\">.</span><span class=\"n\">unsign</span><span class=\"p\">(</span><span class=\"n\">value</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span><span class=\"k\">except</span> <span class=\"n\">signing</span><span class=\"o\">.</span><span class=\"n\">BadSignature</span><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\"><span class=\"pre\">Signer</span></code> 类使用 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SECRET_KEY\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">SECRET_KEY</span></code></a> 配置来生成签名。你可以使用不同的密钥传入 <code class=\"docutils literal notranslate\"><span class=\"pre\">Signer</span></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=\"n\">signer</span> <span class=\"o\">=</span> <span class=\"n\">Signer</span><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><span class=\"n\">value</span> <span class=\"o\">=</span> <span class=\"n\">signer</span><span class=\"o\">.</span><span class=\"n\">sign</span><span class=\"p\">(</span><span class=\"s1\">&#39;My string&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">value</span>\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\"><span class=\"pre\">class</span></span><span class=\"w\"> </span></em><span class=\"sig-name descname\"><span class=\"pre\">Signer</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">key</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">sep</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">':'</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">salt</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">algorithm</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">fallback_keys</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></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>Returns a signer which uses <code class=\"docutils literal notranslate\"><span class=\"pre\">key</span></code> to generate signatures and <code class=\"docutils literal notranslate\"><span class=\"pre\">sep</span></code> to\nseparate values. <code class=\"docutils literal notranslate\"><span class=\"pre\">sep</span></code> cannot be in the <span class=\"target\" id=\"index-0\"></span><a class=\"rfc reference external\" href=\"https://datatracker.ietf.org/doc/html/rfc4648.html#section-5\"><strong>URL safe base64 alphabet</strong></a>. This alphabet contains alphanumeric characters, hyphens,\nand underscores. <code class=\"docutils literal notranslate\"><span class=\"pre\">algorithm</span></code> must be an algorithm supported by\n<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\"><span class=\"pre\">hashlib</span></code></a>, it defaults to <code class=\"docutils literal notranslate\"><span class=\"pre\">'sha256'</span></code>. <code class=\"docutils literal notranslate\"><span class=\"pre\">fallback_keys</span></code> is a list\nof additional values used to validate signed data, defaults to\n<a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SECRET_KEY_FALLBACKS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">SECRET_KEY_FALLBACKS</span></code></a>.</p>\n<aside class=\"version-note version-changed\" data-version=\"4.1\">\n<p class=\"version-note-title\">Changed in Django 4.1</p><p>The <code class=\"docutils literal notranslate\"><span class=\"pre\">fallback_keys</span></code> argument was added.</p>\n</aside>\n</dd></dl>\n\n<section id=\"using-the-salt-argument\">\n<h3>使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">salt</span></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\"><span class=\"pre\">Signer</span></code> 类的可选 <code class=\"docutils literal notranslate\"><span class=\"pre\">salt</span></code> 参数。使用盐会将盐和你的 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SECRET_KEY\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">SECRET_KEY</span></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=\"n\">signer</span> <span class=\"o\">=</span> <span class=\"n\">Signer</span><span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">signer</span><span class=\"o\">.</span><span class=\"n\">sign</span><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><span class=\"n\">signer</span><span class=\"o\">.</span><span class=\"n\">sign_object</span><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><span class=\"n\">signer</span> <span class=\"o\">=</span> <span class=\"n\">Signer</span><span class=\"p\">(</span><span class=\"n\">salt</span><span class=\"o\">=</span><span class=\"s1\">&#39;extra&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">signer</span><span class=\"o\">.</span><span class=\"n\">sign</span><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><span class=\"n\">signer</span><span class=\"o\">.</span><span class=\"n\">unsign</span><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><span class=\"n\">signer</span><span class=\"o\">.</span><span class=\"n\">sign_object</span><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><span class=\"n\">signer</span><span class=\"o\">.</span><span class=\"n\">unsign_object</span><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.1/ref/settings/#std-setting-SECRET_KEY\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">SECRET_KEY</span></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\"><span class=\"pre\">TimestampSigner</span></code> 是 <a class=\"reference internal\" href=\"#django.core.signing.Signer\" title=\"django.core.signing.Signer\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Signer</span></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=\"w\"> </span><span class=\"nn\">datetime</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">timedelta</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.core.signing</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">TimestampSigner</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">signer</span> <span class=\"o\">=</span> <span class=\"n\">TimestampSigner</span><span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">value</span> <span class=\"o\">=</span> <span class=\"n\">signer</span><span class=\"o\">.</span><span class=\"n\">sign</span><span class=\"p\">(</span><span class=\"s1\">&#39;hello&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">value</span>\n<span class=\"go\">&#39;hello:1NMg5H:oPVuCqlJWmChm1rA2lyTUtelC-c&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">signer</span><span class=\"o\">.</span><span class=\"n\">unsign</span><span class=\"p\">(</span><span class=\"n\">value</span><span class=\"p\">)</span>\n<span class=\"go\">&#39;hello&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">signer</span><span class=\"o\">.</span><span class=\"n\">unsign</span><span class=\"p\">(</span><span class=\"n\">value</span><span class=\"p\">,</span> <span class=\"n\">max_age</span><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><span class=\"n\">signer</span><span class=\"o\">.</span><span class=\"n\">unsign</span><span class=\"p\">(</span><span class=\"n\">value</span><span class=\"p\">,</span> <span class=\"n\">max_age</span><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><span class=\"n\">signer</span><span class=\"o\">.</span><span class=\"n\">unsign</span><span class=\"p\">(</span><span class=\"n\">value</span><span class=\"p\">,</span> <span class=\"n\">max_age</span><span class=\"o\">=</span><span class=\"n\">timedelta</span><span class=\"p\">(</span><span class=\"n\">seconds</span><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\"><span class=\"pre\">class</span></span><span class=\"w\"> </span></em><span class=\"sig-name descname\"><span class=\"pre\">TimestampSigner</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">key</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">sep</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">':'</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">salt</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">algorithm</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">'sha256'</span></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\"><span class=\"pre\">sign</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">value</span></span></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\"><span class=\"pre\">value</span></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\"><span class=\"pre\">unsign</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">value</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">max_age</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></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\"><span class=\"pre\">value</span></code> 是否在 <code class=\"docutils literal notranslate\"><span class=\"pre\">max_age</span></code> 秒前被签署，否则引发 <code class=\"docutils literal notranslate\"><span class=\"pre\">SignatureExpired</span></code>。<code class=\"docutils literal notranslate\"><span class=\"pre\">max_age</span></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\"><span class=\"pre\">datetime.timedelta</span></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\"><span class=\"pre\">sign_object</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">obj</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">serializer</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">JSONSerializer</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">compress</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">False</span></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>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\"><span class=\"pre\">unsign_object</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">signed_obj</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">serializer</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">JSONSerializer</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">max_age</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></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>Checks if <code class=\"docutils literal notranslate\"><span class=\"pre\">signed_obj</span></code> was signed less than <code class=\"docutils literal notranslate\"><span class=\"pre\">max_age</span></code> seconds ago,\notherwise raises <code class=\"docutils literal notranslate\"><span class=\"pre\">SignatureExpired</span></code>. The <code class=\"docutils literal notranslate\"><span class=\"pre\">max_age</span></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\"><span class=\"pre\">datetime.timedelta</span></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\"><span class=\"pre\">Signer.sign_object()</span></code> and <code class=\"docutils literal notranslate\"><span class=\"pre\">unsign_object()</span></code> methods, or signing module's\n<code class=\"docutils literal notranslate\"><span class=\"pre\">dumps()</span></code> or <code class=\"docutils literal notranslate\"><span class=\"pre\">loads()</span></code> functions (which are shortcuts for\n<code class=\"docutils literal notranslate\"><span class=\"pre\">TimestampSigner(salt='django.core.signing').sign_object()/unsign_object()</span></code>).\nThese use JSON serialization under the hood. JSON ensures that even if your\n<a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SECRET_KEY\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">SECRET_KEY</span></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=\"w\"> </span><span class=\"nn\">django.core</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">signing</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">signer</span> <span class=\"o\">=</span> <span class=\"n\">signing</span><span class=\"o\">.</span><span class=\"n\">TimestampSigner</span><span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">value</span> <span class=\"o\">=</span> <span class=\"n\">signer</span><span class=\"o\">.</span><span class=\"n\">sign_object</span><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><span class=\"n\">value</span>\n<span class=\"go\">&#39;eyJmb28iOiJiYXIifQ:1kx6R3:D4qGKiptAqo5QW9iv4eNLc6xl4RwiFfes6oOcYhkYnc&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">signer</span><span class=\"o\">.</span><span class=\"n\">unsign_object</span><span class=\"p\">(</span><span class=\"n\">value</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;foo&#39;: &#39;bar&#39;}</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">value</span> <span class=\"o\">=</span> <span class=\"n\">signing</span><span class=\"o\">.</span><span class=\"n\">dumps</span><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><span class=\"n\">value</span>\n<span class=\"go\">&#39;eyJmb28iOiJiYXIifQ:1kx6Rf:LBB39RQmME-SRvilheUe5EmPYRbuDBgQp2tCAi7KGLk&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">signing</span><span class=\"o\">.</span><span class=\"n\">loads</span><span class=\"p\">(</span><span class=\"n\">value</span><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\"><span class=\"pre\">signing.loads(object)</span></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=\"w\"> </span><span class=\"nn\">django.core</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">signing</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">value</span> <span class=\"o\">=</span> <span class=\"n\">signing</span><span class=\"o\">.</span><span class=\"n\">dumps</span><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><span class=\"n\">signing</span><span class=\"o\">.</span><span class=\"n\">loads</span><span class=\"p\">(</span><span class=\"n\">value</span><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\"><span class=\"pre\">dumps</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">obj</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">key</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">salt</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">'django.core.signing'</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">serializer</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">JSONSerializer</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">compress</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">False</span></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\"><span class=\"pre\">TimestampSigner</span></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\"><span class=\"pre\">loads</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">string</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">key</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">salt</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">'django.core.signing'</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">serializer</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">JSONSerializer</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">max_age</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">fallback_keys</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></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\"><span class=\"pre\">dumps()</span></code> 相反，如果签名失败引发 <code class=\"docutils literal notranslate\"><span class=\"pre\">BadSignature</span></code>。如果给定，则检查 <code class=\"docutils literal notranslate\"><span class=\"pre\">max_age</span></code> （以秒为单位）。</p>\n<aside class=\"version-note version-changed\" data-version=\"4.1\">\n<p class=\"version-note-title\">Changed in Django 4.1</p><p>The <code class=\"docutils literal notranslate\"><span class=\"pre\">fallback_keys</span></code> argument was added.</p>\n</aside>\n</dd></dl>\n\n</section>\n</section>","rootId":"module-django.core.signing","toc":[{"title":"Protecting SECRET_KEY and 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/4.1/topics/"}],"prev":{"docname":"topics/conditional-view-processing","title":"条件视图处理","url":"/zh-hans/4.1/topics/conditional-view-processing/"},"next":{"docname":"topics/email","title":"发送邮件","url":"/zh-hans/4.1/topics/email/"},"formats":{"html":"/zh-hans/4.1/topics/signing/","markdown":"/zh-hans/4.1/topics/signing.md","json":"/zh-hans/4.1/topics/signing.json"},"source":"https://github.com/django/django/blob/stable/4.1.x/docs/topics/signing.txt","official":"https://docs.djangoproject.com/zh-hans/4.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"]}