Authenticating user is the process of checking and verifying to see if a given user was registered in the database or not. If he/she was registered, we can write code to allow him/her to get into the restricted areas on the website.
When a user is authenticated, we can create a session to save his/her user data on the cloud in Redis Enterprise database. And for security matter, we can encode user data in a JSON web token (JWT) before saving this token in Redis database on the cloud.
For the reference to the token, we can create a session id using uuid module from Python standard library and store it in a signed cookie. Doing so, the cookie can be seen but cannot be modified. Moreover, we can check to see whether a user was authenticated or not by using session id to pull the JWT from Redis database in order to decode it and see if a user data was encoded into the JWT or not. if the user was authenticated, he/she can go straight into the restricted areas without signing in again.
# routes/frontend/login.py
from bottle import Bottle, get, post, redirect
from controllers.frontend.login import Login
app = Bottle()
login = Login()
@app.get("/")
def getLogin():
if(login.checkLogged()):
return redirect("/admin/post")
else:
return login.getPage()
@app.post("/")
def postLogin():
return login.postItem()
# controllers/frontend/login.py
import config, copy, hashlib, jwt, uuid
from datetime import datetime, timezone, timedelta
from bottle import template, request, response, redirect
from models.user import User
class Login:
def __init__(self):
settings = copy.deepcopy(config.settings)
self.setup = settings()
self.redis = config.redis
self.secret_key = config.secret_key
self.user = User()
def getPage(self):
self.setup["pageTitle"] = "Log into Admin Page"
self.setup["route"] = "/login"
return template("base", data=self.setup)
def checkLogged(self):
sessionid = request.get_cookie('sessionid', secret=self.secret_key)
encoded_jwt = self.redis.get(sessionid)
try:
payload = jwt.decode(encoded_jwt, self.secret_key, algorithms=["HS256"])
if(payload["user"]):
return True
except jwt.ExpiredSignatureError:
return False
def postItem(self):
password = request.forms.getunicode('password')
email = request.forms.getunicode('email')
user = self.user.checkUser(email)
if user:
passw = hashlib.sha512(password.encode("utf-8") + user["salt"]).hexdigest()
if(passw == user["password"]):
self.setup["pageTitle"] = 'Post Page'
payload = {"userid": user["id"], "role": user["role"]}
exp = datetime.now(timezone.utc) + timedelta(seconds=60*60*24*15)
myjwt = jwt.encode({"user": payload, "exp": exp }, self.secret_key, algorithm="HS256")
sessionid = uuid.uuid4().hex
self.redis.set(sessionid, myjwt)
self.redis.expire(sessionid, 60*60*24*15)
response.set_cookie('sessionid', sessionid, path='/', secret=self.secret_key)
return redirect('/admin/post')
else:
self.setup["pageTitle"] = 'Log into Admin Page'
self.setup['message'] = 'Your password is wrong!'
self.setup['route'] = '/login'
return template("base", data=self.setup)
else:
self.setup["pageTitle"] = 'Log into Admin Page'
self.setup['message'] = 'Your Email is wrong!'
self.setup['route'] = '/login'
return template("base", data=self.setup)
# models/user.py
import config, hashlib, uuid
from bottle import request
class User:
def __init__(self):
self.db = config.conndb()
def createRootUser(self):
raw_salt = uuid.uuid4().hex
password = "xxxxxxxxxxxxxxxxxxx".encode('utf-8')
salt = raw_salt.encode('utf-8')
hashed_password = hashlib.sha512(password + salt).hexdigest()
user = {
"id": uuid.uuid4().hex,
"title": 'Guest',
"content": '',
"thumb": '',
"date": '',
"role": 'Guest',
"email": 'guest@khmerweb.app',
"salt": salt,
"password": hashed_password,
}
self.db["users"].insert_one(user)
def checkUser(self, email):
return self.db["users"].find_one({ 'email': email })