pythonpython-3.xtornado

Tornado - '_xsrf' argument missing from POST


As can be seen in the following code, I have a GET for registration, that delegates its work to POST.

class RegistrationHandler(tornado.web.RequestHandler):
    def get(self):
        s = """
          <h1>Register</h1>
              <form method="post" action="/register">
                  <div>
                      <label>User</label>
                      <input name="user_name" value="test@test.com"/>
                  </div>
                  <div>
                      <label>password</label>
                      <input name="password" type="password"/>
                  </div>
                  <div>
                      <input type="submit" value="submit"/>
                  </div>
              </form>
        """
        self.write(s)

    @log_exception()
    def post(self):
        user_name = self.request.arguments['user_name']
        password = self.request.arguments['password']
        log.debug('Registering user with credentials %r' % (user_name, password))
        with sa_session() as db_session:
            User.register(user_name, password, db_session)

When I access the URL from my web browser, I get a registration form, after submitting which I get "403: Forbidden".

Console log:

2012-10-15 11:27:42,482 - __main__ - DEBUG - Starting server on port 8080
2012-10-15 11:27:49,377 - root - INFO - 304 GET /register (127.0.0.1) 0.78ms
2012-10-15 11:27:53,143 - root - WARNING - 403 POST /register (127.0.0.1): '_xsrf' argument missing from POST
2012-10-15 11:27:53,144 - root - WARNING - 403 POST /register (127.0.0.1) 1.05ms

What does this error mean and how do I correct it? Thanks.


Solution

  • I imagine you have Cross-site request forgery cookies enabled in your settings (by default it is on).

    Tornado's XSRF is here

    To fix this turn it off in your settings:

    settings = {
        "xsrf_cookies": False,
    }
    

    Note: Normally you dont want to turn this off and normally you'd be generating HTML in a template like this: Please note the xsrf bit which adds the XSRF cookie.

     <form method="post" action="/register">
         <input name="user_name" value="test@test.com"/>
         <input name="password" type="password"/>
         <input type="submit" value="submit"/>
    {% raw xsrf_form_html() %}
     </form>
    

    ---EDIT following comments--- Instead of:

      def get(self):
            loader = template.Loader("resources")
            page_contents = loader.load('register_page.html').generate()
            self.write(page_contents)
    

    Do:

      def get(self):
         self.render("../resources/register_page.html")
    

    or better:

      def get(self):
         self.render("register_page.html")
    

    (and put it in your templates directory)