Banco de Dados: Criando um CRUD com Kivy e SQLite3 | Josiel Soares

Login de Usuários com Python, Kivy e SQLite3

Tutorial de programação de um ambiente seguro implementado com Base de Dados

Kivy é um framework multiplataforma para a linguagem de programação Python3

Trata-se de um app com sistema de login de usuários, o usuário só entra na aplicação se tiver sua senha cadastrada no banco de dados. Com um recurso de encriptação no qual a base de dados tem o campo de nome e senha protegidos com encriptação fazendo uso da biblioteca hashlib.

Este app tem quatro telas que são: a tela inicial de login, a tela de criação de usuário, a tela de alteração de senha e a tela de conteúdo do app após efetuado o login.



Com este tutorial você estará apto a fazer algo único com estes princípios exibidos aqui na implementação deste projeto, aprendendo e evoluindo de acordo com sua disposição para absorver o conteúdo e aplicar em sua necessidade de programação.


O que você vai ver nesta implementação de aplicativo:

Inicialmente precisamos acessar o diretório onde está instalado o ambiente virtual de programação em python e diretório de projetos do kivy, neste diretório crie um outro sub-diretório para nosso Sistema de Login com um novo arquivo main.py, note que a extensão do arquivo deve ser .py que é o formato utilizado pelo interpretador da linguagem de programação Python.

As classes que vamos importar para o Kivy:

            # arquivo main.py
            import kivy
            kivy.require('2.0.0')            
            from kivy.app import App            
            from kivy.lang import Builder
            from kivy.uix.screenmanager import ScreenManager, Screen
            from kivy.properties import ObjectProperty
            import hashlib
            import sqlite3
        

A arquitetura do projeto e classe principal e sua execução:

            # continuação do arquivo main.py
            class MenuScreen(Screen):
                pass
            class AppScreen(Screen):
                pass
            class AlterarScreen(Screen):
                pass
            class CadastrarScreen(Screen):
                pass
            class LoginApp(App):
                sm = ScreenManager()
                sm.add_widget(MenuScreen(name='menu'))
                sm.add_widget(AppScreen(name='app'))
                sm.add_widget(AlterarScreen(name='alterar'))
                sm.add_widget(CadastrarScreen(name='cadastrar'))
                def login_de_usuario(self):
                    pass
                def cadastrar_usuario(self):
                    pass
                def exibir_pergunta_secreta(self):   
                    pass     
                def alterar_senha(self): 
                    pass       
                def build(self):
                    App.title = "App de Login de Usuários"                
                    return self.sm
            LoginApp().run()
        

Não se esqueça de importar a interface gráfica na Linguagem Kv

        # continuação do arquivo main.py
        Builder.load_string(open("gui.kv", encoding="utf-8").read(), rulesonly=True) 
    

Esta importação da "gui" deve ser feita no arquivo main.py

A classe da tela de menu inicial:

            # continuação do arquivo main.py
            class MenuScreen(Screen):
                txt_usr = ObjectProperty(None)
                txt_pwd = ObjectProperty(None)
                lbl_saida = ObjectProperty(None)             
        

A classe da tela de acesso a usuário logado:

            # continuação do arquivo main.py
            class AppScreen(Screen):
                pass             
        

A classe da tela de Alteração de Senha:

            # continuação do arquivo main.py
            class AlterarScreen(Screen):
                meu_usuario = ObjectProperty(None)
                minha_resposta = ObjectProperty(None)
                minha_senha = ObjectProperty(None)
                minha_csenha = ObjectProperty(None)
                minha_saida  = ObjectProperty(None)
        

A classe da tela de Cadastro de Usuário:

            # continuação do arquivo main.py
            class CadastrarScreen(Screen):
                txt_usuario = ObjectProperty(None) 
                txt_email = ObjectProperty(None) 
                txt_senha = ObjectProperty(None) 
                txt_csenha = ObjectProperty(None)
                txt_pergunta = ObjectProperty(None) 
                txt_resposta = ObjectProperty(None) 
                lbl_saida = ObjectProperty(None)
        

O método de Login de Usuário Completo:

            # continuação do arquivo main.py
            def login_de_usuario(self):
                menu = self.sm.get_screen('menu')
                self.txt_user = menu.txt_usr.text
                self.txt_pass = menu.txt_pwd.text
                nome = hashlib.md5(self.txt_user.encode("utf-8"))
                senha = hashlib.md5(self.txt_pass.encode("utf-8"))        
                c = self.db.execute('SELECT id, usuario, senha FROM tb_usuarios WHERE  (usuario=? AND senha = ?)', (nome.hexdigest(),senha.hexdigest()))
                resultado = c.fetchone()
                if not(resultado is None):
                    if nome.hexdigest() == resultado[1] and senha.hexdigest() == resultado[2]:
                        self.id_usuario_logado = resultado[0]
                        menu.lbl_saida.text = "Efetuando Login..."
                        print("Usuário Correto!")
                        self.sm.current = 'app'
                else:
                    menu.lbl_saida.text = "Usuário Inválido."
                    print("Usuário Inválido.") 
        

O método de Cadastro de Usuário completo:

            # continuação do arquivo main.py
            def cadastrar_usuario(self):
                cadastro = self.sm.get_screen('cadastrar')
                campo_usuario = cadastro.txt_usuario.text
                campo_senha = cadastro.txt_senha.text
                campo_email = cadastro.txt_email.text       
                campo_csenha = cadastro.txt_csenha.text
                campo_pergunta = cadastro.txt_pergunta.text
                campo_resposta = cadastro.txt_resposta.text
                hash_usr = hashlib.md5(campo_usuario.encode("utf-8")).hexdigest()
                hash_sen = hashlib.md5(campo_senha.encode("utf-8")).hexdigest()
                try:
                    if (campo_usuario  != "" and campo_senha != "" and campo_csenha != "" and campo_email != "" and campo_pergunta != "" and campo_resposta != "") and  (campo_senha ==  campo_csenha):
                        c = self.db.execute('SELECT usuario, email FROM tb_usuarios WHERE (usuario=? OR email =?)', (hash_usr, campo_email))
                        resultado = c.fetchone()
                        if (resultado is None):
                                
                            sql="INSERT INTO tb_usuarios (usuario, email, senha, pergunta, resposta) VALUES (?, ?, ?, ?, ?)"
                            self.cursor.execute(sql, (str(hash_usr), str(campo_email), str(hash_sen), str(campo_pergunta), str(campo_resposta)))
                            self.db.commit() 
                            cadastro.lbl_saida.text = "Usuário Cadastrado com Sucesso."
                            print("Usuário Cadastrado com Sucesso.")
                        else:
                            cadastro.lbl_saida.text = "Já existe este Usuário ou Email."
                            print("Já existe este Usuário ou Email.")
                    elif (campo_senha != "" and campo_csenha != "") and (campo_senha !=  campo_csenha):
                        cadastro.lbl_saida.text = "As senhas devem ser iguais.."
                        print("As senhas devem ser iguais.")
                    else:
                        cadastro.lbl_saida.text = "Todos campos devem ser preenchidos."
                        print("Todos campos devem ser preenchidos.")
                except sqlite3.Error as error:
                    print("Algum erro ocorreu.", error)
        

O método para exibir a Pergunta Secreta:

            # continuação do arquivo main.py
            def exibir_pergunta_secreta(self):
                alteracao = self.sm.get_screen('alterar')
                self.txt_user = alteracao.meu_usuario.text          
                nome = hashlib.md5(self.txt_user.encode("utf-8"))            
                pergunta = alteracao.minha_pergunta.text        
                c = self.db.execute('SELECT  usuario, pergunta, resposta FROM tb_usuarios WHERE  (usuario=?)', (nome.hexdigest(),))
                resultado = c.fetchone()        
                try:
                    if not(resultado is None):
                        if nome.hexdigest() == resultado[0]:                    
                            alteracao.minha_pergunta.text = "Pergunta secreta: " + str(resultado[1])
                except sqlite3.Error as error:
                            print("Algum erro ocorreu.", error)
        

O método de Alteração de Senha:

            # continuação do arquivo main.py
            def alterar_senha(self):
                alteracao = self.sm.get_screen('alterar')
                self.txt_user = alteracao.meu_usuario.text        
                self.txt_pass = alteracao.minha_senha.text        
                resposta = alteracao.minha_resposta.text
                nome = hashlib.md5(self.txt_user.encode("utf-8"))
                senha = hashlib.md5(self.txt_pass.encode("utf-8"))       
                c = self.db.execute('SELECT id, usuario, resposta FROM tb_usuarios WHERE  (usuario=? AND resposta =?)', (nome.hexdigest(), resposta))
                resultado = c.fetchone()
                if not(resultado is None):
                    if nome.hexdigest() == resultado[1] and resposta == resultado[2]:
                        try:
                            ns = hashlib.md5(self.txt_pass.encode("utf-8"))
                            sql="UPDATE tb_usuarios SET senha = ? WHERE id=?"
                            self.cursor.execute(sql, (ns.hexdigest(), resultado[0]))
                            self.db.commit() 
                            alteracao.minha_saida.text = "Senha Cadastrada com Sucesso."
                            print("Senha Cadastrada com Sucesso.")
                        except sqlite3.Error as error:
                            print("Algum erro ocorreu.", error)
                else:
                    alteracao.minha_saida.text = "Informações Inválidas."
                    print("Informações Inválidas.")
        

O método construtor build vai ficar da seguinte forma

            # continuação do arquivo main.py
            def build(self): 
                App.title = "App de Login de Usuários"                
                self.db = sqlite3.connect('acesso.db')
                self.db.execute('CREATE TABLE IF NOT EXISTS tb_usuarios (id INTEGER PRIMARY KEY AUTOINCREMENT, usuario TEXT, email TEXT, senha TEXT, pergunta TEXT, resposta TEXT)')
                self.cursor=self.db.cursor()      
                return self.sm
        

Considerando que já fizemos toda esta parte lógica do projeto de aplicativo mobile, agora precisamos adicionar os espaços onde se manipulará os dados do banco em SQLite3, para isso precisamos criar o arquivo gui.kv no mesmo diretório onde está o arquivo main.py, código principal do projeto em que estamos editando.

O arquivo gui.kv está escrito na linguagem interna do framework Kivy na Kv Language para a nossa gui: Graphic User Interface.kv que significa em português: Interface Gráfica de Usuário. É onde podemos adicionar os widgets do Kivy que são Rótulos, Botões, Campos de Textos, Imagens entre outros.


Código da gui para a tela de menu.

            # o arquivo gui.kv
            :
                txt_usr: txt_usr
                txt_pwd: txt_pwd
                lbl_saida: lbl_saida
                BoxLayout:
                    orientation: "vertical"  
                    Label:
                        text: "Login de Usuário"      
                    TextInput:
                        id: txt_usr
                        hint_text: "Usuário: "
                    TextInput:
                        id: txt_pwd
                        hint_text: "Senha: "
                        password: True
                        password_mask: "*"
                    Label:
                        id: lbl_saida
                        text: "Esperando interação."
                    Button:
                        text: "Entrar"
                        on_press: app.login_de_usuario()
                    Button:
                        text: "Esqueceu a Senha?"
                        on_press: root.manager.current = 'alterar'
                    Button:
                        text: "Criar Conta"            
                        on_press: root.manager.current = 'cadastrar'
                    Button:
                        text: 'Quit'
                        on_press: app.root_window.close()
        

Código da gui para a tela de Sucesso no Login de Usuário.

            # continuação do arquivo gui.kv
            :
                BoxLayout:
                    orientation: "vertical"
                    Label:
                        text: 'Login efetuado com sucesso. \nBem vindo Usuário.'
                        halign: 'center'
                    Button:
                        text: 'Back to menu'
                        size_hint_y: 0.2
                        on_press: root.manager.current = 'menu'
        

Código da gui para a tela de Alteração de Senha.

            # continuação do arquivo gui.kv
            :
                meu_usuario: meu_usuario
                minha_pergunta: minha_pergunta
                minha_resposta: minha_resposta
                minha_senha: minha_senha
                minha_csenha: minha_csenha
                minha_saida: minha_saida    
                BoxLayout:
                    orientation: "vertical"
                    Label:
                        text: 'Alterar Senha.'
                    TextInput:
                        id: meu_usuario
                        hint_text: "Nome de Usuário: "
                    Label:
                        id: minha_pergunta
                        text: "Pergunta secreta: "
                        text_size: self.size
                        halign: "left"            
                        valign: "middle"        
                    TextInput:
                        id: minha_resposta
                        hint_text: "Resposta secreta: "
                    
                    TextInput:
                        id: minha_senha
                        hint_text: "Nova Senha: "
                        password: True
                        password_mask: "*"
                    TextInput:
                        id: minha_csenha
                        hint_text: "Repita a Nova Senha: "
                        password: True
                        password_mask: "*"
                    Label:
                        id: minha_saida
                        text: "Esperando Interação."
                    Button:
                        text: 'Verificar Usuário'
                        on_press: app.exibir_pergunta_secreta()
                    Button:
                        text: 'Alterar Senha'
                        on_press: app.alterar_senha()
                    Button:
                        text: 'Back to menu'            
                        on_press: root.manager.current = 'menu'
        

Código da gui para a tela de Cadastro de Usuário.

            # continuação do arquivo gui.kv
            :
                txt_usuario: txt_usuario
                txt_email: txt_email
                txt_senha: txt_senha
                txt_csenha: txt_csenha
                txt_pergunta: txt_pergunta
                txt_resposta: txt_resposta
                lbl_saida: lbl_saida
                BoxLayout:
                    orientation: "vertical"
                    Label:
                        text: "Cadastrar Usuário"
                    TextInput:
                        id: txt_usuario
                        hint_text: "Usuário: "
                    TextInput:
                        id: txt_email
                        hint_text: "E-mail: "
                    TextInput:
                        id: txt_senha
                        hint_text: "Senha: "
                        password: True
                        password_mask: "*"
                    TextInput:
                        id: txt_csenha            
                        hint_text: "Repita a Senha: "
                        password: True
                        password_mask: "*"
                    TextInput:
                        id: txt_pergunta            
                        hint_text: "Pergunta secreta: "
                    TextInput:
                        id: txt_resposta            
                        hint_text: "Resposta secreta: "
                    Label:
                        id: lbl_saida
                        text: "Esperando Interação"
                    Button:
                        text: "Cadastrar Usuário"
                        on_press: app.cadastrar_usuario()
                    Button:
                        text: 'Back to menu'            
                        on_press: root.manager.current = 'menu'
        

A live Hora do Código completo deste projeto em Vídeo no Youtube

Por favor consulte também este link do canal para acesso ao material completo, separado em dois vídeos.

Parte 1: Início


Demonstração: O que proponho com este projeto?:


Parte 2: Complemento e Parte Final:


Portanto, caro leitor, neste projeto você pode observar vários elementos que compôem o aplicativo, são saberes específicos de funcionamento do framework Kivy, espero que com este projeto eu possa aguçar sua curiosidade sobre esta tecnologia, poupei linhas ao não comentar tudo pelo fato de que eu desejava disponibilizar o código fonte inteiro para sua consulta, e para que eu possa reler e revisar o projeto para quando eu mesmo for desenvolver outros projetos.

Este artigo serve tanto para você que está lendo agora como para mim mesmo autor, Josiel Soares, grato, se você é novo por aqui Seja Bem Vindo! se você já é chegado Fique à Vontade! Valeu e até em breve.