# OOP design for multiple user authentication

I'm learning OOPs design principles and design patterns. As an exercise, I came up with this model for multiple user authentication using OOPs. I plan to build this on top of a Flask server, but I've just mocked the behavior for now.

User Model:

class User:
def __init__(self, name: str = None, ph_no: str = None, username: str = None, password: str = None):
self.ph_no = ph_no
self.name = name

Utils.persist_in_db(self)

else:

def __repr__(self):
return f'<User: {OrderedDict(self.__dict__)}>'


Core logic:

import threading
import time
from models.user import User

class BMSApp:
def __init__(self):
self.mock()

@staticmethod
def mock():
ph_no='xxxxx',

ph_no='xxxx',

user1.start()
user2.start()

user1.join()
user2.join()

def __init__(self, **kwargs):
super().__init__()
self.kwargs = kwargs

def run(self) -> None:
BookingStrategy.execute(**self.kwargs)

class BookingStrategy:
@staticmethod
def execute(**kwargs):
else:


class LoginService:
@staticmethod
#         TODO: implement proper login functionality
user = User(**kwargs)
return random.choice([(True, user), (False, user)])

• Independent of whether this is good OOP, your password update function seems to expect that Utils,encrypt() is self-reversible. That would be a horrible choice for password safety! All serious password storage mechanisms go to great lengths to ensure passwords can not simply be decrypted. Dec 2 '19 at 5:54
• Sorry, I meant to write Utils.encrypt(old_password) == self.password. Fixed it now. Dec 2 '19 at 7:12
• That still does not consider salting. And the name encrypt() implies that there is a matching decrypt() function, and if there is, you're still not doing it right. Dec 2 '19 at 8:11
• Considering there are answers posted now, please don't edit your code further or it will be considered invalidation of the current answers. The response to such will be a rollback of the edit. Consider posting a follow-up question linking back to this one if you have updated code that you'd like to have reviewed.
– Mast
Dec 2 '19 at 9:38
• Would recommend you to read this book github.com/cosmicpython/book Dec 2 '19 at 10:00

First of all, I am not at all sure it is good idea to learn OOP by re-implementing security-sensitive feature for a web-framework, which already has support for such things. Please, at least consider using Flask-Security, Flask-Login, Flask-Principal unless you plan a total rewrite of all those. Also, I see plain text passwords in use - most of the time a security risk.

That said, I can find the following problems:

1. Persistence service is too intrusive and its logic is not clear. For example, you are creating a user just to login: Why do you want to persist anything someone tries to enter as a login attempt? Consider using some ORM, where you can control object's persistence, or come up with something better than object dealing with its persistence.

Those aspects better be invisible in the model. In Python, it's probably best to use a DTO (data-transfer object, received from the login form, usually a dict) until identity is verified.

2. I do not really understand why you are using threads. In the Flask environment one can use a session as an abstraction, so dealing at thread level is strange and can make your code too dependent on a specific implementation, preventing porting it to multiprocessing, async/greenlets and the like.

There are some naming problems (what is ph_no?).

In my opinion the best place for OOP in user authentication is (in addition to User class) a possibility to define different authentication strategies (and inject dependencies like Utils.encrypt that way). Then, if a more complex system is in question - role-based authorization, etc, etc. The code you presented above is not geared towards those goals. Instead, it deals with low-level concerns which are already solved in the framework.

• Encrypted, not plaintext. Although it should be hashed. Esp. since OP is treating it as a hash, ie. he is not decrypting the password. Dec 2 '19 at 9:11
• Hmmm... Question was changed after my answer. I believe it was Utils.decrypt - so plain text password could be obtained. Dec 2 '19 at 16:32

In general objects that the parameters of the constructors have dependencies, for example username with password with name, should be readonly in order to avoid changes during the execution, in python basically is make that parameters private and have a decorator that only allows read them. You will avoid issues such has create an object and after that change the username, or even the password.