From 4592672dcee0e16f75da6ec8fd6f674e12e5251b Mon Sep 17 00:00:00 2001 From: vitaliy Date: Mon, 19 May 2025 13:04:38 +0300 Subject: [PATCH] db auth --- code/python/db_connect/authorization.py | 100 ++++++++++++++++++++ code/python/db_connect/database/database.py | 62 ++++++++++++ code/python/db_connect/sql/db.sql | 69 ++++++++++++++ code/python/db_connect/sql/select.sql | 68 +++++++++++++ 4 files changed, 299 insertions(+) create mode 100644 code/python/db_connect/authorization.py create mode 100644 code/python/db_connect/database/database.py create mode 100644 code/python/db_connect/sql/db.sql create mode 100644 code/python/db_connect/sql/select.sql diff --git a/code/python/db_connect/authorization.py b/code/python/db_connect/authorization.py new file mode 100644 index 0000000..fbdbf80 --- /dev/null +++ b/code/python/db_connect/authorization.py @@ -0,0 +1,100 @@ +import uuid +import csv +# Генерация случайного UUID (версия 4) +import hashlib +import database.database as database +random_uuid = uuid.uuid4() +DB = 'password_db.csv' + + +class UserFoundException(Exception): + pass + +class PasswordWrongException(Exception): + pass + +def get_db_password(): + """Читаем файл паролей в список""" + users = [ ] + with open(DB, newline='') as csvfile: + spamreader = csv.reader(csvfile, delimiter=':') + for row in spamreader: + users.append(row) + return users + + +def checkUser(login: str) -> bool: + """Проверяем пользователя в БД""" + db = get_db_password() + for row in db: + if login == row[1]: + return row + # raise UserFoundException("Такой пользователь существует!") + +# try: +# checkUser('user') +# except UserFoundException as e: +# print(e) + + + +def calculate_md5(data): + """Вычисляет MD5-хеш для данных.""" + md5_hash = hashlib.md5(data.encode('utf-8')).hexdigest() + return md5_hash + + +def login(username, passwd): + + _l , _p = database.get_list_account(username) + + # user = checkUser(username) + # print(user[2]) + passwd_md5 = calculate_md5(str(passwd)) + + # print(passwd_md5) + isRight = False if (_p == passwd_md5) else True + if isRight: + raise PasswordWrongException + else: + print("Пользователь авторизован") + +# try: +# checkUser('user') +# except UserFoundException as e: +# print(e) +# except PasswordWrongException as e: +# print(e) + +# login('oper', 123) +# exit(0) + +def logout(username): + #todo: Сделать флаг выхода из системы + pass + +def delete_user(username): + #todo: Дописать удаление пользователя + pass + +def registration(login, passwd, rep_passwd): + """Регистрация пользователей.""" + + if passwd == rep_passwd: + passwd_md5 = calculate_md5(passwd) + #print(f"MD5-хеш для '{passwd}': {passwd_md5}") + str = f"{random_uuid}:{login}:{passwd_md5}\n" + with open("password_db.csv", "a+") as fd: + fd.write(str) + + if not database.add_account(login, passwd_md5): + print("Запись добавлена") + + +_login = input("login:") +_passwd = input("passwd:") +_rep_passwd = input("rep_passwd:") + + +#registration( _login, _passwd,_rep_passwd ) +login( _login, _passwd ) \ No newline at end of file diff --git a/code/python/db_connect/database/database.py b/code/python/db_connect/database/database.py new file mode 100644 index 0000000..b3908ba --- /dev/null +++ b/code/python/db_connect/database/database.py @@ -0,0 +1,62 @@ +import psycopg2 + +try: + conn = psycopg2.connect("dbname='auth' user='auth' port='5432' host='localhost' password='123'") +except: + print("I am unable to connect to the database") + +def add_account(login, passwd): + + SQL_INSERT_ACCOUNT = f"""INSERT INTO account + (login, pswd, is_block, dt_create, "token", "refresh", dt_) + VALUES('{login}', '{passwd}', false, now(), '', '', now()); """ + + with conn.cursor() as curs: + try: + # simple single row system query + # conn.start() + # print(dir(conn)) + curs.execute(SQL_INSERT_ACCOUNT) + conn.commit() + # returns a single row as a tuple + #single_row = curs.fetchone() + + # use an f-string to print the single tuple returned + #print(f"{single_row}") + + # simple multi row system query + # curs.execute("SELECT query, backend_type FROM pg_stat_activity") + + # a default install should include this query and some backend workers + # use the * unpack operator to print many_rows which is a Python list + + # a more robust way of handling errors + except (Exception, psycopg2.DatabaseError) as error: + print(error) + + finally: + curs.close() + conn.close() + + + +def get_list_account(_login): + SQL_SELECT_ACCOUNT = f"""SELECT login, pswd + FROM account + WHERE login like '{_login}'""" + + with conn.cursor() as curs: + try: + + curs.execute(SQL_SELECT_ACCOUNT) + # returns a single row as a tuple + single_row = curs.fetchone() + print(f"{single_row}") + return single_row + + except (Exception, psycopg2.DatabaseError) as error: + print(error) + + finally: + curs.close() + conn.close() diff --git a/code/python/db_connect/sql/db.sql b/code/python/db_connect/sql/db.sql new file mode 100644 index 0000000..2fcb4d6 --- /dev/null +++ b/code/python/db_connect/sql/db.sql @@ -0,0 +1,69 @@ +CREATE TABLE "account" ( + "id" SERIAL PRIMARY KEY, + "login" VARCHAR(10) NOT NULL, + "pswd" VARCHAR(255) NOT NULL, + "is_block" BOOLEAN, + "dt_create" DATE, + "token" VARCHAR(255) NOT NULL, + "refresh" VARCHAR(255) NOT NULL +); + +CREATE TABLE "profile" ( + "id" SERIAL PRIMARY KEY, + "id_account" INTEGER NOT NULL, + "name" VARCHAR(100) NOT NULL, + "surname" VARCHAR(100) NOT NULL, + "sex" BOOLEAN, + "dt_birth" TIMESTAMP +); + +CREATE INDEX "idx_profile__id_account" ON "profile" ("id_account"); + +ALTER TABLE "profile" ADD CONSTRAINT "fk_profile__id_account" FOREIGN KEY ("id_account") REFERENCES "account" ("id"); + +CREATE TABLE "role" ( + "id" SERIAL PRIMARY KEY, + "name" TEXT NOT NULL +); + +CREATE TABLE "role_account" ( + "id_roles" INTEGER NOT NULL, + "acconts" INTEGER NOT NULL, + PRIMARY KEY ("id_roles", "acconts") +); + +CREATE INDEX "idx_role_account__acconts" ON "role_account" ("acconts"); + +ALTER TABLE "role_account" ADD CONSTRAINT "fk_role_account__acconts" FOREIGN KEY ("acconts") REFERENCES "account" ("id") ON DELETE CASCADE; + +ALTER TABLE "role_account" ADD CONSTRAINT "fk_role_account__id_roles" FOREIGN KEY ("id_roles") REFERENCES "role" ("id") ON DELETE CASCADE; + +CREATE TABLE "rules" ( + "id" SERIAL PRIMARY KEY, + "name" TEXT NOT NULL, + "body" JSONB NOT NULL +); + +CREATE TABLE "role_rules" ( + "id_roles" INTEGER NOT NULL, + "id_rules" INTEGER NOT NULL, + PRIMARY KEY ("id_roles", "id_rules") +); + +CREATE INDEX "idx_role_rules__id_rules" ON "role_rules" ("id_rules"); + +ALTER TABLE "role_rules" ADD CONSTRAINT "fk_role_rules__id_roles" FOREIGN KEY ("id_roles") REFERENCES "role" ("id") ON DELETE CASCADE; + +ALTER TABLE "role_rules" ADD CONSTRAINT "fk_role_rules__id_rules" FOREIGN KEY ("id_rules") REFERENCES "rules" ("id") ON DELETE CASCADE; + +CREATE TABLE "rules_rules" ( + "rules" INTEGER NOT NULL, + "rules_2" INTEGER NOT NULL, + PRIMARY KEY ("rules", "rules_2") +); + +CREATE INDEX "idx_rules_rules" ON "rules_rules" ("rules_2"); + +ALTER TABLE "rules_rules" ADD CONSTRAINT "fk_rules_rules__rules" FOREIGN KEY ("rules") REFERENCES "rules" ("id"); + +ALTER TABLE "rules_rules" ADD CONSTRAINT "fk_rules_rules__rules_2" FOREIGN KEY ("rules_2") REFERENCES "rules" ("id") \ No newline at end of file diff --git a/code/python/db_connect/sql/select.sql b/code/python/db_connect/sql/select.sql new file mode 100644 index 0000000..05f61df --- /dev/null +++ b/code/python/db_connect/sql/select.sql @@ -0,0 +1,68 @@ +-- Алиасы вычесление в столбцах, применение функций + select a.id, a.login || ' ' || a.login login, 2+2 as summ_ + from account a + where ( id in (1,2) and login ilike 'BOB') + + +--inner join с конструкцией CASE +select a.login, p."name" || ' ' || p.surname as fio, + to_char(p.dt_birth, 'DD.MM.YYYY') dt_birth, + CASE + when p.sex THEN 'Девушка' + ELSE 'Мужчина' + END as sex, r."name" + from account a, profile p, role_account ra ,"role" r + where a.id = p.id_account + and ra.acconts = a.id + and ra.roles = r.id + + +-- LEFT JOIN получение при запросе пересечение с NULL строками +-- Запрос представлен в виде таблицы + select * from +( SELECT a.login login, p."name" + FROM account a +LEFT JOIN profile p ON a.id = p.id_account + WHERE p."name" is null) null_acc + where null_acc.login not like 'bob' ; + + +-- Создание представления в БД на базе +create view v_account as +SELECT a.login +FROM account a +where NOT EXISTS (SELECT * FROM profile p + WHERE p.id_account = a.id ) +select * from v_account va; + + +-- Объединение запросов +union all +SELECT a.login +FROM account a +where NOT EXISTS (SELECT * FROM profile p + WHERE p.id_account = a.id ) + + +-- Запросы с группировкой group by, having + select ra.roles, count(ra.roles) + from account a, role_account ra + where a.id = ra.acconts + group by ra.roles + having count(ra.roles) > 2 + + + + + + + + + + + + + + + +