In today’s online world, having strong security measures is more important than ever. Traditional ways of logging in, like using a username and password, are not always secure enough. This has led to more cases of hacking and identity theft. As a result, there’s a big push to find better ways to check who’s trying to access an account or system. Facial recognition for secure login system is one of the new methods. It’s becoming a popular choice because it adds an extra layer of security. Instead of just typing in a password, the system can recognize your face to make sure it’s really you. This technology is starting to be used in many different places to keep things safer.
In this blog, we’re going to talk about how deep learning, a type of artificial intelligence, is being used to make online security much better. We’re focusing on how combining two advanced technologies, called Multi-task Cascaded Convolutional Networks (MTCNN) and FaceNet, can create a really strong two-step way to check who’s trying to log in or access a system.
This article was published as a part of the Data Science Blogathon.
Problems like stolen passwords, people’s identities being used without their permission, and hackers getting into places they shouldn’t be are all reasons why we need a new kind of security system. This new system should not only be super secure but also dependable.
Yet, the need for a robust and reliable authentication method, especially in scenarios where security is paramount, continues to grow. Traditional systems often fall short, paving the way for a more sophisticated approach—one that doesn’t just ensure high security but also guarantees reliability, scalability, and user-friendliness.
We’re working on a new way to check who’s trying to log in to a system, which is really important for keeping things secure. We’re using a mix of two smart technologies. One is great at spotting faces (MTCNN), and the other is really good at telling faces apart (FaceNet). By putting these two together, we’re making a security system that knows you by your face, which is perfect for places that need to be very careful about who they let in.
This architectural design showcases the flow of processes within the facial recognition-based login authentication system. It involves multiple components working together seamlessly to ensure secure user authentication.
We’re building a well-organized system that uses facial recognition to make sure the right people are getting access to secure areas. The system is set up in a way that each part has its own space, like folders for different tasks. This makes it easier to work on, improve, and make bigger over time.
controller/
│
├── app_controller/
├── auth_controller/
└── __init__.py
docs/
│
└── setup.md
venv/
face_auth/
│
├── src/
│ ├── business_val/
│ │ ├── user_embedding_val.py
│ │ └── user_val.py
│ │
│ ├── config/
│ │ └── database/
│ │ └── (config files)
│ │
│ ├── constant/
│ │ ├── auth_constant.py
│ │ ├── database_constants.py
│ │ └── embedding_constants.py
│ │
│ ├── data_access/
│ │ ├── user_data.py
│ │ └── user_embedding_data.py
│ │
│ ├── entity/
│ │ ├── user.py
│ │ └── user_embedding.py
│ │
│ ├── exception/
│ │ └── (exception handling)
│ │
│ ├── logger/
│ │ └── (logging configuration)
│ │
│ ├── utils/
│ │ └── util.py
│ │
│ └── __init__.py
│
└── logs/
└── (log files)
static/
│
└── application/
├── assets/
├── css/
├── images/
├── js/
└── vendor/
templates/
│
├── addd-app.html
├── error.html
├── index.html
├── login_embedding.html
├── login.html
├── register_embedding.html
├── register.html
├── unauthorized.html
└── view-app.html
.dockerignore
.gitignore
app.py
requirments.txt
setup.py
Here’s how we’ve set things up:
We also have parts like:
+---------------------+
| Pretrained Model |
| (e.g., FaceNet) |
+---------------------+
|
+---------------------+
| Transfer Learning|
| to New Task |
+---------------------+
Resource Efficiency
Concept
Utilization in Face Recognition
+---------------------+
| Facial Image |
| |
+---------------------+
|
+---------------------+
| Facial Embedding |
| (Dense Vector) |
+---------------------+
|
+---------------------+
| Face Recognition |
| (Cosine Similarity)|
+---------------------+
conda create -p ./venv python=3.8 -y
Virtual Environment Activation: Activate the virtual environment:
conda activate ./env
Install Required Packages: Use pip to install the necessary dependencies listed in the requirements.txt file:
pip install -r requirements.txt
SECRET_KEY=KlgH6AzYDeZeGwD288to79I3vTHT8wp7
ALGORITHM=HS256
DATABASE_NAME='UserDatabase'
USER_COLLECTION_NAME='User'
EMBEDDING_COLLECTION_NAME='Embedding'
MONGODB_URL_KEY= '[Put Your MongoDB url]'
python app.py
or
uvicorn app:app
Project FlowChart
The Python classes for User and Embedding have been coded and stored in the designated ‘entity‘ folder, ready for use in the authentication system. These classes will facilitate the management of user information and their corresponding facial embeddings.
user.py
import uuid
class User:
def __init__(
self,
Name: str,
username: str,
email_id: str,
ph_no: str,
password1: str,
password2: str,
uuid_: str = None,
):
self.Name = Name
self.username = username
self.email_id = email_id
self.ph_no = ph_no
self.password1 = password1
self.password2 = password2
self.uuid_ = uuid_
if not self.uuid_:
self.uuid_ = str(uuid.uuid4()) + str(uuid.uuid4())[0:4]
def to_dict(self) -> dict:
return self.__dict__
def __str__(self) -> str:
return str(self.to_dict())
user_embedding.py
class Embedding:
"""Entity class for user embedding"""
def __init__(self, UUID: str = None, user_embed=None) -> None:
self.UUID = UUID
self.user_embed = user_embed
def to_dict(self) -> dict:
return self.__dict__
def __str__(self) -> str:
return str(self.to_dict())
LoginValidation Class
RegisterValidation Class
These classes are essential for ensuring the security and accuracy of user authentication and registration processes within the system.
user_val.py
import re
import sys
from typing import Optional
from passlib.context import CryptContext
from face_auth.data_access.user_data import UserData
from face_auth.entity.user import User
from face_auth.exception import AppException
from face_auth.logger import logging
bcrypt_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
class LoginValidation:
"""_summary_
"""
def __init__(self, email_id: str, password: str):
"""_summary_
Args:
email_id (str): _description_
password (str): _description_
"""
self.email_id = email_id
self.password = password
self.regex = re.compile(
r"([A-Za-z0-9]+[.-_])*[A-Za-z0-9]+@[A-Za-z0-9-]+(\.[A-Z|a-z]{2,})+"
)
def validate(self) -> bool:
"""validate: This validates the user input
Args:
email_id (str): email_id of the user
password (str): password of the user
"""
try:
msg = ""
if not self.email_id:
msg += "Email Id is required"
if not self.password:
msg += "Password is required"
if not self.isEmailValid():
msg += "Invalid Email Id"
return msg
except Exception as e:
raise e
def isEmailValid(self) -> bool:
if re.fullmatch(self.regex, self.email_id):
return True
else:
return False
def verifyPassword(self, plain_password: str, hashed_password: str) -> bool:
"""_summary_
Args:
plain_password (str): _description_
hashed_password (str): _description_
Returns:
bool: _description_
"""
return bcrypt_context.verify(plain_password, hashed_password)
def validateLogin(self) -> dict:
"""This checks all the validation conditions for the user registration
"""
print(self.validate())
if len(self.validate()) != 0:
return {"status": False, "msg": self.validate()}
return {"status": True}
def authenticateUserLogin(self) -> Optional[str]:
"""_summary_: This authenticates the user and returns the token
if the user is authenticated
Args:
email_id (str): _description_
password (str): _description_
"""
try:
print(self.validateLogin())
logging.info("Authenticating the user details.....")
if self.validateLogin()["status"]:
userdata = UserData()
logging.info("Fetching the user details from the database.....")
user_login_val = userdata.get_user({"email_id": self.email_id})
if not user_login_val:
logging.info("User not found while Login")
return False
if not self.verifyPassword(self.password, user_login_val["password"]):
logging.info("Password is incorrect")
return False
logging.info("User authenticated successfully....")
return user_login_val
return False
except Exception as e:
raise AppException(e, sys) from e
class RegisterValidation:
"""_summary_: This authenticates the user and returns the status
"""
def __init__(self, user: User) -> None:
try:
self.user = user
self.regex = re.compile(
r"([A-Za-z0-9]+[.-_])*[A-Za-z0-9]+@[A-Za-z0-9-]+(\.[A-Z|a-z]{2,})+"
)
self.uuid = self.user.uuid_
self.userdata = UserData()
self.bcrypt_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
except Exception as e:
raise e
def validate(self) -> bool:
"""This checks all the validation conditions for the user registration
Returns:
_type_: string
"""
try:
msg = ""
if self.user.Name == None:
msg += "Name is required"
if self.user.username == None:
msg += "Username is required"
if self.user.email_id == None:
msg += "Email is required"
if self.user.ph_no == None:
msg += "Phone Number is required"
if self.user.password1 == None:
msg += "Password is required"
if self.user.password2 == None:
msg += "Confirm Password is required"
if not self.isEmailValid():
msg += "Email is not valid"
if not self.isPasswordValid():
msg += "Length of the pass`word should be between 8 and 16"
if not self.isPasswordMatch():
msg += "Password does not match"
if not self.isDetailsExists():
msg += "User already exists"
return msg
except Exception as e:
raise e
def isEmailValid(self) -> bool:
"""_summary_: This validates the email id
Returns:
bool: True if the email id is valid else False
"""
if re.fullmatch(self.regex, self.user.email_id):
return True
else:
return False
def isPasswordValid(self) -> bool:
if len(self.user.password1) >= 8 and len(self.user.password2) <= 16:
return True
else:
return False
def isPasswordMatch(self) -> bool:
if self.user.password1 == self.user.password2:
return True
else:
return False
def isDetailsExists(self) -> bool:
username_val = self.userdata.get_user({"username": self.user.username})
emailid_val = self.userdata.get_user({"email_id": self.user.email_id})
uuid_val = self.userdata.get_user({"UUID": self.uuid})
if username_val == None and emailid_val == None and uuid_val == None:
return True
return False
@staticmethod
def getPasswordHash(password: str) -> str:
return bcrypt_context.hash(password)
def validateRegistration(self) -> bool:
"""This checks all the validation conditions for the user registration
"""
if len(self.validate()) != 0:
return {"status": False, "msg": self.validate()}
return {"status": True}
def saveUser(self) -> bool:
"""_summary_: This saves the user details in the database
only after validating the user details
Returns:
bool: _description_
"""
try:
logging.info("Validating the user details while Registration.....")
if self.validateRegistration()["status"]:
logging.info("Generating the password hash.....")
hashed_password: str = self.getPasswordHash(self.user.password1)
user_data_dict: dict = {
"Name": self.user.Name,
"username": self.user.username,
"password": hashed_password,
"email_id": self.user.email_id,
"ph_no": self.user.ph_no,
"UUID": self.uuid,
}
logging.info("Saving the user details in the database.....")
self.userdata.save_user(user_data_dict)
logging.info("Saving the user details in the database completed.....")
return {"status": True, "msg": "User registered successfully"}
logging.info("Validation failed while Registration.....")
return {"status": False, "msg": self.validate()}
except Exception as e:
raise e
Application Overview – Web-App Initialization
UserLoginEmbeddingValidation Class
UserRegisterEmbeddingValidation Class
These classes are pivotal for ensuring the accuracy of user authentication by comparing embeddings and facilitating secure registration by storing image embeddings for future verification.
import io
import sys
from ast import Bytes
from typing import List
import numpy as np
from deepface import DeepFace
from deepface.commons.functions import detect_face
from PIL import Image
from face_auth.constant.embedding_constants import (
DETECTOR_BACKEND,
EMBEDDING_MODEL_NAME,
ENFORCE_DETECTION,
SIMILARITY_THRESHOLD,
)
from face_auth.data_access.user_embedding_data import UserEmbeddingData
from face_auth.exception import AppException
from face_auth.logger import logging
class UserLoginEmbeddingValidation:
def __init__(self, uuid_: str) -> None:
self.uuid_ = uuid_
self.user_embedding_data = UserEmbeddingData()
self.user = self.user_embedding_data.get_user_embedding(uuid_)
def validate(self) -> bool:
try:
if self.user["UUID"] == None:
return False
if self.user["user_embed"] == None:
return False
return True
except Exception as e:
raise e
@staticmethod
def generateEmbedding(img_array: np.ndarray) -> np.ndarray:
"""
Generate embedding from image array"""
try:
faces = detect_face(
img_array,
detector_backend=DETECTOR_BACKEND,
enforce_detection=ENFORCE_DETECTION,
)
# Generate embedding from face
embed = DeepFace.represent(
img_path=faces[0],
model_name=EMBEDDING_MODEL_NAME,
enforce_detection=False,
)
return embed
except Exception as e:
raise AppException(e, sys) from e
@staticmethod
def generateEmbeddingList(files: List[Bytes]) -> List[np.ndarray]:
"""
Generate embedding list from image array
"""
embedding_list = []
for contents in files:
img = Image.open(io.BytesIO(contents))
# read image array
img_array = np.array(img)
# Detect faces
embed = UserLoginEmbeddingValidation.generateEmbedding(img_array)
embedding_list.append(embed)
return embedding_list
@staticmethod
def averageEmbedding(embedding_list: List[np.ndarray]) -> List:
"""Function to calculate the average embedding of the list of embeddings
Args:
embedding_list (List[np.ndarray]): _description_
Returns:
List: _description_
"""
avg_embed = np.mean(embedding_list, axis=0)
return avg_embed.tolist()
@staticmethod
def cosine_simmilarity(db_embedding, current_embedding) -> bool:
"""Function to calculate cosine similarity between two embeddings
Args:
db_embedding (list): This embedding is extracted from the database
current_embedding (list): This embedding is extracted from the current images
Returns:
int: simmilarity value
"""
try:
return np.dot(db_embedding, current_embedding) / (
np.linalg.norm(db_embedding) * np.linalg.norm(current_embedding)
)
except Exception as e:
raise AppException(e, sys) from e
def compareEmbedding(self, files: bytes) -> bool:
"""Function to compare the embedding of the current image with the embedding of the database
Args:
files (list): Bytes of images
Returns:
bool: Returns True if the similarity is greater than the threshold
"""
try:
if self.user:
logging.info("Validating User Embedding ......")
# Validate user embedding
if self.validate() == False:
return False
logging.info("Embedding Validation Successfull.......")
# Generate embedding list
logging.info("Generating Embedding List .......")
embedding_list = UserLoginEmbeddingValidation.generateEmbeddingList(
files
)
logging.info("Embedding List generated.......")
# Calculate average embedding
logging.info("Calculating Average Embedding .......")
avg_embedding_list = UserLoginEmbeddingValidation.averageEmbedding(
embedding_list
)
logging.info("Average Embedding calculated.......")
# Get embedding from database
db_embedding = self.user["user_embed"]
logging.info("Calculating Cosine Similarity .......")
# Calculate cosine similarity
simmilarity = UserLoginEmbeddingValidation.cosine_simmilarity(
db_embedding, avg_embedding_list
)
logging.info("Cosine Similarity calculated.......")
if simmilarity >= SIMILARITY_THRESHOLD:
logging.info("User Authenticated Successfully.......")
return True
else:
logging.info("User Authentication Failed.......")
return False
logging.info("User Authentication Failed.......")
return False
except Exception as e:
raise AppException(e, sys) from e
# def get_user_embeeding_object(self, uuid_:str) -> Embedding:
# """_summary_
# Args:
# user_embedding (dict): _description_
# Returns:
# Embedding: _description_
# """
# try:
# user_embedding = self.user_embedding_data.get_user_embedding(uuid_)
# return user_embedding
# except Exception as e:
# raise AppException(e, sys) from e
class UserRegisterEmbeddingValidation:
def __init__(self, uuid_: str) -> None:
self.uuid_ = uuid_
self.user_embedding_data = UserEmbeddingData()
def saveEmbedding(self, files: bytes):
"""This function will generate embedding list and save it to database
Args:
files (dict): Bytes of images
Returns:
Embedding: saves the image to database
"""
try:
embedding_list = UserLoginEmbeddingValidation.generateEmbeddingList(files)
avg_embedding_list = UserLoginEmbeddingValidation.averageEmbedding(
embedding_list
)
self.user_embedding_data.save_user_embedding(self.uuid_, avg_embedding_list)
except Exception as e:
raise AppException(e, sys) from e
Camera Activation for Registration Embedding
Generating Embedding in the Backend
import pymongo
from face_auth.constant.database_constants import (
DATABASE_NAME,
MONGODB_URL_KEY
)
class MongodbClient:
client = None
def __init__(self, database_name=DATABASE_NAME) -> None:
if MongodbClient.client is None:
mongo_db_url = MONGODB_URL_KEY
if "localhost" in mongo_db_url:
MongodbClient.client = pymongo.MongoClient(mongo_db_url)
else:
MongodbClient.client=pymongo.MongoClient(mongo_db_url)
self.client = MongodbClient.client
self.database = self.client[database_name]
self.database_name = database_name
This FastAPI controller module facilitates user authentication via facial recognition. It consists of multiple endpoints:
# [Imports]
# Router initialization
router = APIRouter(
prefix="/application",
tags=["application"],
responses={"401": {"description": "Not Authorized!!!"}},
)
# Templates initialization
templates = Jinja2Templates(directory=os.path.join(os.getcwd(), "templates"))
# Environment variable setup
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
# ImageForm class for handling image data
class ImageForm:
# Constructor to initialize image attributes
def __init__(self, request: Request):
# Initialize image attributes
self.request: Request = request
self.image_list = [f"image{i}" for i in range(1, 9)]
self.images = [None] * 8
# Method to handle form data and decode base64 images
async def create_oauth_form(self):
form = await self.request.form()
for idx, image_name in enumerate(self.image_list):
image_data = form.get(image_name)
if image_data:
self.images[idx] = io.BytesIO(base64.b64decode(image_data.split(",")[1])).getvalue()
# Route for the main application page
@router.get("/", response_class=HTMLResponse)
async def application(request: Request):
try:
user = await get_current_user(request)
if user is None:
return RedirectResponse(url="/auth", status_code=status.HTTP_302_FOUND)
return templates.TemplateResponse("login_embedding.html", context={
"request": request,
"status_code": status.HTTP_200_OK,
"msg": "Logged in Successfully",
"user": user['username']
})
except Exception as e:
# Error handling for exceptions
msg = "Error in Login Embedding in Database"
return templates.TemplateResponse("error.html",
status_code=status.HTTP_404_NOT_FOUND,
context={"request": request, "status": False, "msg": msg},
)
# [Other Routes - loginEmbedding, registerEmbedding, etc.]
This controller handles user authentication and embedding storage through FastAPI endpoints, incorporating facial recognition functionality for login and registration.
This FastAPI module manages user authentication and session handling. It comprises endpoints for user login, registration, token creation, and logout.
import os
import io
import base64
from typing import Optional
from fastapi import APIRouter, File, Request, status
from starlette.responses import RedirectResponse, HTMLResponse
from fastapi.templating import Jinja2Templates
from controller.auth_controller.authentication import get_current_user
from face_auth.business_val.user_embedding_val
import UserLoginEmbeddingValidation, UserRegisterEmbeddingValidation
router = APIRouter(prefix="/application", tags=["application"],
responses={"401": {"description": "Not Authorized!!!"}})
templates = Jinja2Templates(directory=os.path.join(os.getcwd(), "templates"))
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
class ImageForm:
def __init__(self, request: Request):
self.request: Request = request
self.images: List[Optional[str]] = [None] * 8
async def create_oauth_form(self):
form = await self.request.form()
for i in range(8):
self.images[i] = form.get(f"image{i + 1}")
@router.get("/", response_class=HTMLResponse)
async def application(request: Request):
try:
user = await get_current_user(request)
if user is None:
return RedirectResponse(url="/auth",
status_code=status.HTTP_302_FOUND)
return templates.TemplateResponse("login_embedding.html",
context={"request": request, "status_code": status.HTTP_200_OK,
"msg": "Logged in Successfully", "user": user['username']})
except Exception as e:
msg = "Error in Login Embedding in Database"
response = templates.TemplateResponse("error.html",
status_code=status.HTTP_404_NOT_FOUND, context={"request": request, "
status": False, "msg": msg})
return response
# Define other routes (loginEmbedding, register_embedding, etc.) similarly...
This module encapsulates user authentication functionalities, enabling login, registration, and session handling within the FastAPI framework.
For Exception and Logger scripting files follow on GitHub
Application Overview – Web-App Initialization
Camera Activation – Registration Embedding
Collecting Images after Camera Activation
View MongoDB Embedding Information
Generating Embedding in the Backend
Application Overview – Web-App Initialization
Setting Up the Login Camera
User Authentication Successful
Figure 14: Formula of Cosine Similarity
This flow illustrates the sequential steps a user takes within the application, from registration to authentication, leveraging the camera to verify identity through image comparison.
In facial recognition, two primary steps involve capturing images and comparing similarities. Initially, the system collects images either during registration or login through camera activation. The backend processes these images to generate unique embeddings stored in a database, such as MongoDB. During login, the camera captures a new image for comparison, and the backend computes the cosine similarity against stored embeddings, authenticating the user if a match is found.” This two-step process ensures secure access using facial recognition technology.
A. Facial recognition is a biometric technology that identifies and verifies individuals by analyzing unique facial features. It uses deep learning algorithms to match patterns in images or video frames with stored templates.
A. Facial recognition finds applications in security and surveillance, user authentication in devices, access control systems, personalized marketing, and social media tagging.
A. Ethical concerns include privacy violations, potential misuse for surveillance, biases in algorithms leading to discrimination, and the collection and storage of personal data without consent.
A. It works by capturing an image or video frame, detecting facial landmarks, extracting distinctive features (like distance between eyes or nose shape), creating a unique faceprint, and comparing it with a database for identification or verification.
A. Limitations include accuracy issues in varying lighting conditions or angles, vulnerability to spoofing or hacking, ethical and privacy concerns regarding data collection and storage, and potential biases in algorithms leading to misidentification.
The media shown in this article is not owned by Analytics Vidhya and is used at the Author’s discretion.