polymer-cookie 生成重复的 Django csrf cookie

polymer-cookie generates duplicate Django csrf cookie

我刚 运行 遇到的奇怪问题。当我转到此页面时,Django 似乎正在生成 2 个 cookie。这两个 cookie 没有相同的标记,因此导致我的 post 失败,因为它验证了错误的 cookie。

有人知道为什么会这样吗?

视图中没有什么特别之处:

class ListingDetailView(TemplateView):
    template_name = "bidding/listing_detail.html"

    def get(self, request, *args, **kwargs):
        c = self.get_context_data(**kwargs)
        c['listing'] = get_object_or_404(Listing, id=kwargs['id'])
        return self.render_to_response(c)

...尽管违规代码似乎在我的自定义组件之一中(当我隐藏它时,不会生成额外的 cookie):

<polymer-element name="bts-place-bid" attributes="href">
    <template>
        <polymer-cookie id="csrfcookie" name="csrftoken"></polymer-cookie>
        <core-ajax
            id="bidxhr"
            method="post"
            body=""
            url="{{ href }}"
            headers='{"X-CSRFToken": "{{ csrftoken }}"}'
            on-core-response="{{ handleResponse }}">
        </core-ajax>

        <core-style ref="bts-place-bid"></core-style>
        <paper-button on-click="{{ toggleDialog }}">Place Bid</paper-button>

        <paper-action-dialog heading="Place Bid"
                      transition="core-transition-center"
                      id="bidDialog">
            <core-style ref="bts-bid-dialog"></core-style>

            <bts-field>
                <label for="id_amount">Bid Amount in Rands</label>
                <input type="number" name="amount" id="id_amount" value="{{ amount }}">
            </bts-field>

            <bts-field vertical layout>
                <label for="id_proposal">Short note or proposal for this bid</label>
                <textarea rows="4" id="id_proposal" name="proposal" value="{{ proposal }}"></textarea>
            </bts-field>

            <paper-button dismissive><core-icon icon="cancel"></core-icon> Cancel</paper-button>
            <paper-button on-click="{{ placeBid }}" affirmative><core-icon icon="note-add"></core-icon> Place Bid!</paper-button>
        </paper-action-dialog>
        <paper-toast id="toastMsg" text=""></paper-toast>

    </template>
    <script>
        Polymer({
            amount: 0,
            proposal: "",
            bidPayload: "",

            ready: function() {
                this.csrftoken = this.$.csrfcookie.value;
            },
            toggleDialog: function(ev, detail, sender) {
                this.$.bidDialog.toggle();
            },
            placeBid: function(ev, detail, sender) {
                this.$.toastMsg.text = "Placing bid, please wait..."
                this.$.toastMsg.show();

                this.$.bidxhr.body = "amount=" + this.amount + "&proposal=" + this.proposal;
                this.$.bidxhr.go();
            },
            handleResponse: function(ev, detail, sender) {
                this.$.toastMsg.text = "Bid placed, refreshing...";
                this.$.toastMsg.show();
                // Auto refresh the page...
                window.location = window.location;
            }
        });
    </script>
</polymer-element>

我怀疑问题可能出在 <polymer-cookie>,我会深入了解它的来源。

所以...您肯定是在创建第二个 cookie。这不是错误。但是让我们看看我们能否让您重回正轨。

polymer-cookie 的来源显示了几个 "hidden" 属性:

<polymer-element name="polymer-cookie" hidden attributes="name value expires secure domain path max-age">

您设置的 cookie 与 CSRF 令牌同名,但值是任意的。因此,最简单的解决方法可能是指定您希望它具有的值:

<polymer-cookie id="csrfcookie" name="csrftoken" value="{{ csrftoken }}"></polymer-cookie>

我预计您仍然会有重复的 cookie,但至少现在它们具有相同的值。

至于你应该如何做到这一点...跳过 polymer-cookie,只需将 {% csrftoken %} 放入你的模板中。这将创建一个名为 "csrfmiddlewaretoken" 的隐藏输入,您可以在客户端检查其值。然后你可以 return 这个价值与你的 ajax POSTs。

最后解决的办法很简单。早该考虑了。

我只是修改了我的自定义组件以接受一个名为 csrftoken 的额外属性,并且我可以向该属性传递 django {{ csrf_token }} 变量。无需查找 cookie,无需添加额外的输入字段等

这是最后一个组件:

<polymer-element name="bts-place-bid" attributes="href csrftoken">
    <template>
        <core-ajax
            id="bidxhr"
            method="post"
            body=""
            url="{{ href }}"
            headers='{"X-CSRFToken": "{{ csrftoken }}"}'
            on-core-response="{{ handleResponse }}">
        </core-ajax>

        <core-style ref="bts-place-bid"></core-style>
        <paper-button on-click="{{ toggleDialog }}">Place Bid</paper-button>

        <paper-action-dialog heading="Place Bid"
                      transition="core-transition-center"
                      id="bidDialog">
            <core-style ref="bts-bid-dialog"></core-style>

            <bts-field>
                <label for="id_amount">Bid Amount in Rands</label>
                <input type="number" name="amount" id="id_amount" value="{{ amount }}">
            </bts-field>

            <bts-field vertical layout>
                <label for="id_proposal">Short note or proposal for this bid</label>
                <textarea rows="4" id="id_proposal" name="proposal" value="{{ proposal }}"></textarea>
            </bts-field>

            <paper-button dismissive><core-icon icon="cancel"></core-icon> Cancel</paper-button>
            <paper-button on-click="{{ placeBid }}" affirmative><core-icon icon="note-add"></core-icon> Place Bid!</paper-button>
        </paper-action-dialog>
        <paper-toast id="toastMsg" text=""></paper-toast>

    </template>
    <script>
        Polymer({
            amount: 0,
            proposal: "",
            bidPayload: "",

            toggleDialog: function(ev, detail, sender) {
                this.$.bidDialog.toggle();
            },
            placeBid: function(ev, detail, sender) {
                this.$.toastMsg.text = "Placing bid, please wait..."
                this.$.toastMsg.show();

                this.$.bidxhr.body = "amount=" + this.amount + "&proposal=" + this.proposal;
                this.$.bidxhr.go();
            },
            handleResponse: function(ev, detail, sender) {
                this.$.toastMsg.text = "Bid placed, refreshing...";
                this.$.toastMsg.show();
                // Auto refresh the page...
                window.location = window.location;
            }
        });
    </script>
</polymer-element>

...然后将其用于主 django 模板中:

<bts-place-bid href="{% url 'bidding_listing_bid' id=listing.id %}"
               csrftoken="{{ csrf_token }}"></bts-place-bid>