I have been working on a small web app and I decided it would be a good idea if I used email verification. Well, when I attempted to add email verification I sort of broke my code... I keep getting a traceback telling me the following:
TypeError: <'peewee.CharField object at 0x7f46c6a7ba50> is not JSON serializable
I have come to the conclusion that I need to make my users model JSON serializable but I am not 100% sure that's what I need to do. Even if I am right, I wouldn't know how to do that.
Here is my user model:
class User(UserMixin, Model):
username = CharField(unique=True)
password = CharField(max_length=20)
email = CharField(unique=True)
confirmed = BooleanField(default=False)
confirmed_on = DateTimeField(default=datetime.datetime.now())
joined_at = DateTimeField(default=datetime.datetime.now)
class Meta:
database = db
order_by = ('-joined_at',)
#classmethod
def create_user(cls, username, email, password, confirmed):
try:
with db.transaction():
cls.create(
username=username,
email=email,
password=generate_password_hash(password),
confirmed=False)
except IntegrityError:
raise ValueError("User already exists")
as far as email verification goes here is what I tried:
def generate_serializer(secret_key=None):
return URLSafeTimedSerializer(app.config['SECRET_KEY'])
def generate_activation_url(user):
serializer = generate_serializer()
token = serializer.dumps(user.username)
return url_for('activate_user', token=token, _external=True)
#app.route('/', methods=('GET', 'POST'))
def index():
form = forms.RegisterForm()
if form.validate_on_submit():
models.User.create_user(
username=form.username.data,
email=form.email.data,
password=form.password.data,
confirmed=False
)
token = generate_activation_url(models.User)
msg =Message(render_template('activation_email.html', token=token),
recipients=[models.User.email])
mail.send(msg)
return render_template('activate.html', user=models.User)
return render_template('index.html', form=form)
#app.route('/activate/<token>')
def activate_user(token, expiration=3600):
serializer = generate_serializer()
try:
serializer.loads(token, salt=app.config[
'SECRET_KEY'], max_age=expiration)
except (BadSignature, SignatureExpired):
abort(404)
models.User.confirmed = True
flash('User activated')
return redirect(url_for('index'))
Related
I am trying to do password validation on wtform like this:
email = StringField('Email', validators=[DataRequired(), Email()])
def validate_password(self, password):
print(self)
user = dbSession.execute(
"SELECT * FROM users WHERE email = :email",
{"email": self.email.data}
).fetchone()
print(user)
if not bcrypt.check_password_hash(user.password, password.data):
raise ValidationError('Incorrect Password.')
i want to get the email from other field, but i guess it's not working, i tried email.data but it isn't defined. also, it's not logging in console. in js, you log an object like this. I wanted to see the self's properties and the user, i want to log like this in python.
console.log('user =', user);
help?
This answer reformulates this little snippet
Sometimes you are in the situation where you need to validate a form with custom logic that can not necessarily be reduced to a validator on a single field. A good example are login forms where you have to make sure a user exists in the database and has a specific password.
class LoginForm(Form):
email = TextField('Email', [validators.InputRequired(), Email()])
password = PasswordField('Password', [validators.InputRequired()])
def __init__(self, *args, **kwargs):
Form.__init__(self, *args, **kwargs)
self.user = None
def validate(self):
rv = Form.validate(self)
if not rv:
return False
user = User.query.filter_by(
email=self.email.data).first()
if user is None:
self.email.errors.append('Unknown email')
return False
if not bcrypt.check_password_hash(user.password, self.password.data):
self.password.errors.append('Invalid Password')
return False
self.user = user
return True
I am trying to find a way to retrieve information such as 'mail', 'displayName', 'telephoneNumber' from an LDAP authenticated/logged in user in Flask.
My user can successfully authenticate and log in using LDAP. However how would I be able to get additional information about the user?
I am using standard python-ldap and flask-login modules and I'm trying to create a string variable for these attributes so I can call on them later in the session. When trying to run the query I am getting ldap.FILTER_ERROR: {'desc': u'Bad search filter'} . Any ideas on how to get this working?
class UserInfo():
def whoami(username, password):
conn = get_ldap_connection()
conn.simple_bind_s(username,password)
basedn = 'OU=...,OU=...,DC=...,DC=...'
userfilter = "(|(SamAccountName=\*" + username + "\*)"
userattribute = ['displayName']
userresults = conn.search_s(basedn,ldap.SCOPE_SUBTREE,userfilter, userattribute)
userinfos = UserInfo()
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(100))
def __init__(self, username, password):
self.username = username
#staticmethod
def try_login(username, password):
conn = get_ldap_connection()
conn.simple_bind_s(domain+username, password)
def is_authenticated(self):
return True
def is_active(self):
return True
def is_anonymous(self):
return False
def get_id(self):
return unicode(self.id)
#login_manager.user_loader
def load_user(id):
return User.query.get(int(id))
#app.before_request
def get_current_user():
g.user = current_user
I needed to use ldap.filter.filter_format for proper character escaping.
import ldap.filter
criteria= ldap.filter.filter_format('(&(objectClass=user)(sAMAccountName=%s))', [username])
I am facing 2 issues here.
1) If user has not old token, a new one should be generated and logged in but it is not happening so.
2)A newly created user when logs in gets 'You have multiple authentication backends configured and therefore must provide the backend argument or set the backend attribute on the user.'
3)old user when trying to login gets an error of get() returned more than one AccessToken -- it returned 8!
Expert might understand from my code
class UserLoginAPI(APIView):
permission_classes = [AllowAny]
serializer_class = UserLoginSerializer
def post(self, request, *args, **kwargs):
access_token = request.GET.get('access_token')
data = request.data
print('data',data)
serializer = UserLoginSerializer(data=data)
if serializer.is_valid(raise_exception=True):
new_data = serializer.data
if new_data:
app = Application.objects.get(name="Foodie")
try:
user = User.objects.get(username=data['username'])
print ('user',user)
except ObjectDoesNotExist:
return HttpResponse("Can't find this user")
else:
try:
access_token = AccessToken.objects.get(user=user)
except ObjectDoesNotExist:
return HttpResponse('Have not set any token')
else:
access_token.delete()
new_token = generate_token()
print('new_token',new_token)
AccessToken.objects.create(user=user, application=app, expires=datetime.now() + timedelta(days=365),token=new_token)
print('aceess',AccessToken)
login(request, user)
return Response(new_data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializers.py
class UserLoginSerializer(ModelSerializer):
username = CharField()
class Meta:
model = User
fields = ['username', 'password']
class UserCreateSerializer(ModelSerializer):
class Meta:
model = User
extra_kwargs = {"password": {"write_only": True}}
def create(self, validated_data):
user_obj = User(
username = username,
first_name = first_name,
last_name = last_name,
email = email
)
user_obj.set_password(password)
user_obj.save()
if user_obj:
expire_seconds = oauth2_settings.user_settings['ACCESS_TOKEN_EXPIRE_SECONDS']
scopes = oauth2_settings.user_settings['SCOPES']
application = Application.objects.get(name="Foodie")
expires = datetime.now() + timedelta(seconds=expire_seconds)
access_token = AccessToken.objects.create(user=user_obj,
application=application,
token = generate_token(),
expires=expires,
scope=scopes)
return validated_data
I'm trying to learn the Peewee ORM in combination with Flask by following the Flask Mega Tutorial. In part 5 of the tutorial I create a login using OpenID. After overcoming a bunch of hurdles already I now get an AttributeError in the function pasted below on the following line: login_user(user, remember = remember_me).
#oid.after_login
def after_login(resp):
if resp.email is None or resp.email == "":
flash('Invalid login. Please try again.')
return redirect(url_for('login'))
user = User.select().where(User.email == resp.email)
if user.wrapped_count() == 0:
nickname = resp.nickname
if nickname is None or nickname == "":
nickname = resp.email.split('#')[0]
user = User(nickname = nickname, email = resp.email, role = models.ROLE_USER)
user.save()
remember_me = False
if 'remember_me' in session:
remember_me = session['remember_me']
session.pop('remember_me', None)
login_user(user, remember = remember_me)
return redirect(request.args.get('next') or url_for('index'))
is_active is found in my User model as follows:
class User(db.Model):
nickname = TextField()
email = TextField()
role = IntegerField(default = ROLE_USER)
def is_authenticated(self):
return True
def is_active(self):
return True
def is_anonymous(self):
return False
def get_id(self):
return self.id
def __repr__(self):
return '<User %r>' % (self.nickname)
I have no clue what I'm doing wrong here though. Could anybody give me a helping hand in what I'm doing wrong here?
All tips are welcome!
As the error suggests, user = User.select().where(User.email == resp.email) gives you back a SelectQuery, not an instance of User. You'll want to include an additional method call to actually fetch the record, something like .first(). first will return either an instance of User or None.
This would allow you to slightly adjust your code:
user = User.select().where(User.email == resp.email).first()
if not user: # or if user is None:
nickname = resp.nickname
...
So far I made my user object and my login function, but I don't understand the user_loader part at all. I am very confused, but here is my code, please point me in the right direction.
#app.route('/login', methods=['GET','POST'])
def login():
form = Login()
if form.validate():
user=request.form['name']
passw=request.form['password']
c = g.db.execute("SELECT username from users where username = (?)", [user])
userexists = c.fetchone()
if userexists:
c = g.db.execute("SELECT password from users where password = (?)", [passw])
passwcorrect = c.fetchone()
if passwcorrect:
#session['logged_in']=True
#login_user(user)
flash("logged in")
return redirect(url_for('home'))
else:
return 'incorrecg pw'
else:
return 'fail'
return render_template('login.html', form=form)
#app.route('/logout')
def logout():
logout_user()
return redirect(url_for('home'))
my user
class User():
def __init__(self,name,email,password, active = True):
self.name = name
self.email = email
self.password = password
self.active = active
def is_authenticated():
return True
#return true if user is authenticated, provided credentials
def is_active():
return True
#return true if user is activte and authenticated
def is_annonymous():
return False
#return true if annon, actual user return false
def get_id():
return unicode(self.id)
#return unicode id for user, and used to load user from user_loader callback
def __repr__(self):
return '<User %r>' % (self.email)
def add(self):
c = g.db.execute('INSERT INTO users(username,email,password)VALUES(?,?,?)',[self.name,self.email,self.password])
g.db.commit()
my database
import sqlite3
import sys
import datetime
conn = sqlite3.connect('data.db')#create db
with conn:
cur = conn.cursor()
cur.execute('PRAGMA foreign_keys = ON')
cur.execute("DROP TABLE IF EXISTS posts")
cur.execute("DROP TABLE IF EXISTS users")
cur.execute("CREATE TABLE users(id integer PRIMARY KEY, username TEXT, password TEXT, email TEXT)")
cur.execute("CREATE TABLE posts(id integer PRIMARY KEY, body TEXT, user_id int, FOREIGN KEY(user_id) REFERENCES users(id))")
I also set up the LoginManager in my init. I am not sure what to do next, but I know I have to some how set up this
#login_manager.user_loader
def load_user(id):
return User.query.get(id)
how do I adjust this portion code to work for my database?
EDIT: please let me know if this looks correct or can be improved :)
#login_manager.user_loader
def load_user(id):
c = g.db.execute("SELECT id from users where username = (?)", [id])
userid = c.fetchone()
return userid
#app.route('/login', methods=['GET','POST'])
def login():
form = Login()
if form.validate():
g.user=request.form['name']
g.passw=request.form['password']
c = g.db.execute("SELECT username from users where username = (?)", [g.user])
userexists = c.fetchone()
if userexists:
c = g.db.execute("SELECT password from users where password = (?)", [g.passw])
passwcorrect = c.fetchone()
if passwcorrect:
user = User(g.user, 'email', g.passw)
login_user(user)
flash("logged in")
return redirect(url_for('home'))
else:
return 'incorrecg pw'
else:
return 'fail'
return render_template('login.html', form=form)
#app.route('/logout')
def logout():
logout_user()
return redirect(url_for('home'))
import sqlite3
from flask import g
class User():
def __init__(self,name,email,password, active = True):
self.name = name
self.email = email
self.password = password
self.active = active
def is_authenticated(self):
return True
#return true if user is authenticated, provided credentials
def is_active(self):
return True
#return true if user is activte and authenticated
def is_annonymous(self):
return False
#return true if annon, actual user return false
def get_id(self):
c = g.db.execute('SELECT id from users where username = (?)', [g.user])
id = c.fetchone()
return unicode(id)
#return unicode id for user, and used to load user from user_loader callback
def __repr__(self):
return '<User %r>' % (self.email)
def add(self):
c = g.db.execute('INSERT INTO users(username,email,password)VALUES(?,?,?)',[self.name,self.email,self.password])
g.db.commit()
user_loader callback function is a way to tell Flask-Login on "how" to look for the user id from the database ? Since you are using sqllite3, you need to implement the user_loader function to query your sqllite database and fetch/return the userid/username that you have stored. Something like:
#login_manager.user_loader
def load_user(id):
c = g.db.execute("SELECT username from users where username = (?)", [id])
userrow = c.fetchone()
userid = userrow[0] # or whatever the index position is
return userid
When you call login_user(user), it calls the load_user function to figure out the user id.
This is how the process flow works:
You verify that user has entered correct username and password by checking against database.
If username/password matches, then you need to retrieve the user "object" from the user id. your user object could be userobj = User(userid,email..etc.). Just instantiate it.
Login the user by calling login_user(userobj).
Redirect wherever, flash etc.
Are you using SQLAlchemy by any chance?
Here is an example of my model.py for a project I had a while back that used Sqlite3 & Flask log-ins.
USER_COLS = ["id", "email", "password", "age"]
Did you create an engine?
engine = create_engine("sqlite:///ratings.db", echo=True)
session = scoped_session(sessionmaker(bind=engine, autocommit=False, autoflush=False))
Base = declarative_base()
Base.query = session.query_property()
Base.metadata.create_all(engine)
Here is an example of User Class:
class User(Base):
__tablename__ = "Users"
id = Column(Integer, primary_key = True)
email = Column(String(64), nullable=True)
password = Column(String(64), nullable=True)
age = Column(Integer, nullable=True)
def __init__(self, email = None, password = None, age=None):
self.email = email
self.password = password
self.age = age
Hope that helps give you a little bit of a clue.
Use SQLAlchemy it completely handles all the queries for you, so you don't have to write it all out.
But if you continue using it this way, then your user_loader function should create a "User" class object. Like:
userrow = c.fetchone()
username = userrow[0]
u = User(username=username)
return u