I've been working with some of Miguel Grinberg's auth tutorials and have come across an issue using flask_httpauth's HTTPBasicAuth decorators. Whenever I use one of them on a function I get an error stating that the decorator is missing required positional argument f. It was my understanding that the function beneath the decorator was implicitly passed to the decorator function as an argument. Am I wrong? I'm using Python 3.5.
My views file looks like this:
from mymodule import app, api, auth
from flask import abort, request, jsonify, g, url_for
from mymodule.users.models import User
@auth.verify_password
def verify_password(username_or_token, password):
# first try to authenticate by token
user = User.verify_auth_token(username_or_token)
if not user:
# try to authenticate with username/password
user = User.query.filter_by(username=username_or_token).first()
if not user or not user.verify_password(password):
return False
g.user = user
return True
@app.route('/api/users', methods=['POST'])
def new_user():
username = request.json.get('username')
password = request.json.get('password')
if username is None or password is None:
abort(400) # missing arguments
if User.query.filter_by(username=username).first() is not None:
abort(400) # existing user
user = User(username=username)
user.hash_password(password)
db.session.add(user)
db.session.commit()
return (jsonify({'username': user.username}), 201,
{'Location': url_for('get_user', id=user.id, _external=True)})
@app.route('/api/users/<int:id>')
def get_user(id):
user = User.query.get(id)
if not user:
abort(400)
return jsonify({'username': user.username})
@app.route('/api/token')
@auth.login_required
def get_auth_token():
token = g.user.generate_auth_token(600)
return jsonify({'token': token.decode('ascii'), 'duration': 600})
@app.route('/')
@auth.login_required
def index():
return "Hello, %s!" % g.current_user
@app.route('/api/resource')
@auth.login_required
def get_resource():
return jsonify({'data': 'Hello, %s!' % g.user.username})
and my init file (where auth, app, api, etc are imported from) looks like this:
import logging
from logging.handlers import RotatingFileHandler
from flask_sqlalchemy import SQLAlchemy
from flask_httpauth import HTTPTokenAuth, HTTPBasicAuth
from flask_restful import Api
from itsdangerous import TimedJSONWebSignatureSerializer as JWT
from flask import Flask
app = Flask(__name__)
"""
Database Config
"""
app.config['SQLALCHEMY_DATABASE_URL'] = 'sqlite:////db.sqlite'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config['SECRET_KEY'] = 'top secret!'
handler = RotatingFileHandler('logfile.log', maxBytes=10000, backupCount=1)
handler.setLevel(logging.INFO)
app.logger.addHandler(handler)
api = Api(app)
db = SQLAlchemy(app)
auth = HTTPBasicAuth
jwt = JWT(app.config['SECRET_KEY'], expires_in=3600)
import mymodule.users.views
Any idea why this isn't working for me? The exact error runs like this:
File "/.../users/views.py", line 14, in <module>
@auth.verify_password
TypeError: verify_password() missing 1 required positional argument: 'f'