Aprendizado profundo prático baseado na Web e segurança por exemplo

DaisyFoto do perfil

Por Daisy

Aprendizado e segurança profundos e baseados na Web por exemplo Terceira edição Charlotte Harper 3 de julho de 2024 Prefácio: As considerações de segurança na criação de software para a Web são uma parte importante do plano e execução de qualquer desenvolvedor da Web, enquanto engenharia um protótipo confiável, estável e útil para fins práticos. O DOM (marcação de objeto de documentos), com sua implementação de HTML, JavaScript e CSS, bem como software de back -end que implementa Python, C/C ++, Java e Bash, oferece aos desenvolvedores da Web a liberdade e o poder para criar uma ampla variedade de projetos que expressam Criatividade, fornecer facilidade de uso e funcionalidade, retratar humildade e caráter e fornecer facilidade de uso, além de conveniência e serviços importantes que são todos atraentes para o Joe médio, o usuário final que procura Para matar o tempo ou fazer algo na internet, geralmente em um dispositivo de smartphone em tela sensível ao toque. A maioria das pessoas nem sabia por onde começar quando deseja construir um site a partir do zero,Eles tenderiam a começar no site de outra pessoa e construir algo limitado em funcionalidade, confiabilidade, facilidade de uso e especialmente criatividade quando eles poderiam ter todas as mais recentes ferramentas poderosas à sua disposição, a fim de construir algo útil sem desperdiçar o tempo pressionando botões, e Especialmente desperdiçando dinheiro pagando por assinaturas caras para software que poucas pessoas queriam usar de qualquer maneira, dadas as limitações em facilidade de uso e flexibilidade. Se você tem alguns minutos para ler este livro e aprender o que eu quero ensinar, ou até falar comigo pessoalmente sobre seus objetivos e obter alguma orientação na direção certa, e está motivado a aprender a codificar e escrever seu próprio software , leve este livro para casa e reserve um tempo para aprender a criar o próximo aplicativo da web influente, poderoso, simplificado e importante, um site que está tudo sobre você e faz exatamente o que você deseja e atende às necessidades do seu público. Sobre mim: Eu sou um desenvolvedor de software com um amploAnge of Experience em C/C ++, Java, Python, HTML, CSS e JavaScript. Construo sites que as pessoas querem usar, querem visitar e até me viciando em usar apenas para aprender, recriar e matar o tempo e, o mais importante, vendo software. Se você teve uma idéia de exatamente como queria que um site parecesse e funcione, estava disposto a me apoiar para que eu possa atender às minhas próprias necessidades enquanto atende às suas, e você está disposto a cobrir os custos de executar um site, você mesmo, Eu construiria para você o próximo YouTube, Tiktok, Twitter, Google, ou mesmo um aplicativo de segurança de alta tecnologia, apenas você pode acessar. Em vez de tentar vender meu tempo para você, estou tentando comprar o seu: quero convencer você a criar um aplicativo (site) com as informações que já existem e ensinar o que você precisa para ser um desenvolvedor de software independente, Empreendedor, liderando uma carreira de sucesso em qualquer campo que você desejar. E deixe -me esclarecer, a educação que lhe dou será informal. Você pode ir para a escola e aprender tudo isso com umRMAL EDUCAÇÃO, ou até leia este livro na escola, complete suas tarefas e tire muito a sua educação, mas não vou colocá -lo formalmente no assento quente e pedir para você concluir tarefas. Não sou seu professor, você pode pensar em mim como um amigo que deseja guiá -lo a uma carreira impulsionada por seu próprio sucesso pessoal. E também não estou vendendo sucesso para você, você precisará comprá -lo com seu tempo. Aprender a codificar tem uma curva de aprendizado acentuada e nunca foi fácil, ou mesmo deveria ser. Você precisa trabalhar o máximo que puder e continuar tentando falhar e tentar novamente, mesmo quando estiver frustrado para aprender e criar aplicativos. Isso é da natureza do próprio código. O código é executado por um compilador projetado para fornecer as mensagens de erro do programador, e elas ensinarão como codificar, mesmo que você esteja simplesmente copiando o erro no seu mecanismo de pesquisa e lendo os exemplos de outras pessoas. E devo dizer, você não precisa ser extremamente rico, inteligente, bem -sucedido,De detalhes ou organizados para criar um aplicativo. O computador cuida dessa organização para você. Você só precisa perseverar através do teste e erro, manter o foco e trabalhar duro no que faz, e terá uma carreira muito bem -sucedida na totalidade do que faz. Quem eu sou: Sei que a última seção foi mais sobre aprender e você se destaca deste livro. Quem sou eu exatamente? Essa é uma pergunta complicada. Não estou claro sobre isso, pois sofro de condições médicas que possam dificultar a codificação ou a escrita deste livro às vezes, enquanto apresentava desafios com questões de socialização e identidade que tornam minha vida mais difícil quando se trata de me apresentar . Em suma, se você está lendo este livro, trouxe -o para casa porque passou por ele e pensou que era útil, ou mesmo se você acabou de ler tão longe, para você, eu sou um indivíduo que quer querer vê -lo ter sucesso tudo o que você faz. Eu sou um engenheiro, um softwareDesenvolvedor, e um aluno, e estou escrevendo este livro para outros alunos que desejam facilitar suas vidas ao ter um manual do software que eles precisam facilitar suas vidas, dando exemplos para copiar que se encaixam como um grande quebra -cabeça em um trabalho de trabalho , aplicativo útil, grande, funcional, coesivo e envolvente que pode gerar sucesso, independentemente da linha de negócios. Em grande parte, é isso que faço: construo aplicativos para ajudar a mim e outras pessoas a ter sucesso. Também sou um autor, embora esta seja minha primeira publicação que pretendo concluir para montar meu portfólio em um documento útil, e também sou artista. Admito isso para você, sou uma pessoa estranha. Eu não sou perfeito, eu já tive inserimentos com a lei até me levando a deixar faculdades e universidades e deixar estados para tentar fazer um nome para mim mesmo com mais sucesso. Eu sou uma mulher de nascimento, uso maquiagem, tiro fotos minhas, uso vestidos e outras roupas femininas, e fico consciente de mim mesmo como ummasculino por natureza. Eu tive problemas com outras pessoas no passado que levaram a lutas com a escrita e a construção da webApps, e peço desculpas por não ter conseguido colocar este livro em suas mãos mais cedo: você precisava disso. Você vai querer ler e escrever código que se parece com o meu e funciona como o meu e faz a mesma coisa, mas ainda melhor, porque se você puder comprar este livro em vez de esmagar seu teclado como eu fizer apenas para criar um livro pedindo dinheiro Para isso, você tem os recursos necessários para ter sucesso em sua vida. Eu tive todos os tipos de problemas com a família crescendo, condições de saúde, médicos, mídia e lei e meu código reflete profundamente a luta que é o feminismo e a natureza feminina em um mundo dividido e frustrado. No entanto, este livro é algo com o qual me preocupo profundamente, meu bebê, meu portfólio e meu sustento, por isso aprecio sua consideração quando você leva a mensagem para casa e examina cuidadosamente sobre ele para aprender comigo. Por favor, lembre -se de que não sou perfeito,O livro terá erros, revisões e novas edições, e você precisará pensar com seu cérebro lógico da melhor maneira possível para ter uma experiência bem -sucedida com a minha escrita. Além disso, entenda que quero dizer bem para você, mesmo quando você enfrenta desafios ao escrever. Pense assim: quando você pode alugar um sistema de computador para fazer qualquer coisa que possa imaginar no espaço digital, armazenar todas as informações que encontrar, #$%! Yze e organizá -lo e entender, você vai Inevitavelmente encontra dificuldades com as informações que você está ingerindo e até publicando. Eu te digo isso porque encontro as mesmas dificuldades. Use este livro por sua conta e risco, trabalhe com sua comunidade e comunidades disponíveis para construir software em um ambiente seguro e não leve as coisas para o pessoal quando você falha ou até é bem -sucedido da maneira errada: foi assim que cheguei tão longe , e por que posso trazer este texto para você e ajudá -lo a ter sucesso sem desviar um caminho de loucura que saiEu arruinou, rasgado e desgastado enquanto encontro os problemas comuns que todos têm em escala global, graças à escala global paralelista da rede em que trabalharemos, a Internet. Você pode não estar muito familiarizado com quem eu sou com apenas algumas palavras, mas eu encorajo você a ler, você me conhecerá enquanto continua a me ler e me entender ao criar seus próprios projetos para concluir seu trabalho. Não haverá lição de casa com este livro, desde que seus professores ou professores não atribuam nada a você, mas eu o encorajo a construir um portfólio de projetos enquanto você lê junto, bem como um projeto Capstone mostrando como você pode Aplique o que você aprendeu. Meu projeto Capstone é a base para a maior parte do que você lerá neste livro, pois incorpora código dos meus projetos anteriores, código que criei e aprendi a escrever metodicamente manualmente, e uma ampla gama de idéias e dicas que me ajudaram ter sucesso no ponto em que posso aumentar um aplicativo simples que éUlly destacou e parece e se comporta como um aplicativo popular que você pode ver seu amigo ou família usando, na Internet, anunciado para você ou nas notícias. O que é este livro: Este livro é um tutorial pelo exemplo. Você pode encontrar código aqui, instruções de como aprender a codificar, informações sobre depuração de código e corrigir erros, solucionar etapas, instruções sobre como fazer backup e salvar seu código, re-implantar se alguém quebrar seu código, proteger seu código, implantar Seu código, construa sites interativos divertidos, envolventes e viciantes, e você terá uma noção de quem...
Aprendizado profundo prático baseado na Web e segurança por exemplo

Aprendizado e segurança profundos e baseados na Web por exemplo Terceira edição Charlotte Harper 3 de julho de 2024 Prefácio: As considerações de segurança na criação de software para a Web são uma parte importante do plano e execução de qualquer desenvolvedor da Web, enquanto engenharia um protótipo confiável, estável e útil para fins práticos. O DOM (marcação de objeto de documentos), com sua implementação de HTML, JavaScript e CSS, bem como software de back -end que implementa Python, C/C ++, Java e Bash, oferece aos desenvolvedores da Web a liberdade e o poder para criar uma ampla variedade de projetos que expressam Criatividade, fornecer facilidade de uso e funcionalidade, retratar humildade e caráter e fornecer facilidade de uso, além de conveniência e serviços importantes que são todos atraentes para o Joe médio, o usuário final que procura Para matar o tempo ou fazer algo na internet, geralmente em um dispositivo de smartphone em tela sensível ao toque. A maioria das pessoas nem sabia por onde começar quando deseja construir um site a partir deScratch, eles tenderiam a começar no site de outra pessoa e construir algo limitado em funcionalidade, confiabilidade, facilidade de uso e especialmente criatividade quando eles poderiam ter todas as mais recentes ferramentas poderosas à sua disposição, a fim de construir algo útil sem desperdiçar tempo pressionando botões e, especialmente, desperdiçar dinheiro pagando por assinaturas caras para software que poucas pessoas queriam usar de qualquer maneira, dadas as limitações em facilidade de uso e flexibilidade. Se você tem alguns minutos para ler este livro e aprender o que eu quero ensinar, ou até falar comigo pessoalmente sobre seus objetivos e obter alguma orientação na direção certa, e está motivado a aprender a codificar e escrever seu próprio software , leve este livro para casa e reserve um tempo para aprender a criar o próximo aplicativo da web influente, poderoso, simplificado e importante, um site que está tudo sobre você e faz exatamente o que você deseja e atende às necessidades do seu público. Sobre mim: Eu sou um desenvolvedor de software comGama de experiência em C/C ++, Java, Python, HTML, CSS e JavaScript. Construo sites que as pessoas querem usar, querem visitar e até me viciando em usar apenas para aprender, recriar e matar o tempo e, o mais importante, vendo software. Se você teve uma idéia de exatamente como queria que um site parecesse e funcione, estava disposto a me apoiar para que eu possa atender às minhas próprias necessidades enquanto atende às suas, e você está disposto a cobrir os custos de executar um site, você mesmo, Eu construiria para você o próximo YouTube, Tiktok, Twitter, Google, ou mesmo um aplicativo de segurança de alta tecnologia, apenas você pode acessar. Em vez de tentar vender meu tempo para você, estou tentando comprar o seu: quero convencer você a criar um aplicativo (site) com as informações que já existem e ensinar o que você precisa para ser um desenvolvedor de software independente, Empreendedor, liderando uma carreira de sucesso em qualquer campo que você desejar. E deixe -me esclarecer, a educação que lhe dou será informal. Você pode ir para a escola e aprender tudo isso com umEducação formal, ou mesmo leia este livro na escola, complete suas tarefas e tire muito a sua educação, mas não vou colocá -lo formalmente no assento quente e pedir para que você conclua as tarefas. Não sou seu professor, você pode pensar em mim como um amigo que deseja guiá -lo a uma carreira impulsionada por seu próprio sucesso pessoal. E também não estou vendendo sucesso para você, você precisará comprá -lo com seu tempo. Aprender a codificar tem uma curva de aprendizado acentuada e nunca foi fácil, ou mesmo deveria ser. Você precisa trabalhar o máximo que puder e continuar tentando falhar e tentar novamente, mesmo quando estiver frustrado para aprender e criar aplicativos. Isso é da natureza do próprio código. O código é executado por um compilador projetado para fornecer as mensagens de erro do programador, e elas ensinarão como codificar, mesmo que você esteja simplesmente copiando o erro no seu mecanismo de pesquisa e lendo os exemplos de outras pessoas. E devo dizer, você não precisa ser extremamente rico, inteligente,Essoso, ou mesmo detalhado, orientado ou organizado para criar um aplicativo. O computador cuida dessa organização para você. Você só precisa perseverar através do teste e erro, manter o foco e trabalhar duro no que faz, e terá uma carreira muito bem -sucedida na totalidade do que faz. Quem eu sou: Sei que a última seção foi mais sobre aprender e você se destaca deste livro. Quem sou eu exatamente? Essa é uma pergunta complicada. Não estou claro sobre isso, pois sofro de condições médicas que possam dificultar a codificação ou a escrita deste livro às vezes, enquanto apresentava desafios com questões de socialização e identidade que dificultam minha vida quando se trata de me apresentar . Em suma, se você está lendo este livro, trouxe -o para casa porque passou por ele e pensou que era útil, ou mesmo se você acabou de ler tão longe, para você, eu sou um indivíduo que quer querer vê -lo ter sucesso tudo o que você faz. Eu mesmo sou engenheiro,Desenvolvedor, e um aluno, e estou escrevendo este livro para outros alunos que desejam facilitar suas vidas ao ter um manual do software que eles precisam facilitar suas vidas, dando exemplos para copiar que se encaixam como um grande quebra -cabeça em um trabalho de trabalho , aplicativo útil, grande, funcional, coesivo e envolvente que pode gerar sucesso, independentemente da linha de negócios. Em grande parte, é isso que faço: construo aplicativos para ajudar a mim e outras pessoas a ter sucesso. Também sou um autor, embora esta seja minha primeira publicação que pretendo concluir para montar meu portfólio em um documento útil, e também sou artista. Admito isso para você, sou uma pessoa estranha. Eu não sou perfeito, eu já tive inserimentos com a lei até me levando a deixar faculdades e universidades e deixar estados para tentar fazer um nome para mim mesmo com mais sucesso. Eu sou uma mulher de nascimento, uso maquiagem, tiro fotos minhas, uso vestidos e outras roupas femininas, e fico consciente de mim mesmo como ummulher por natureza. Eu tive problemas com outras pessoas no passado que levaram a lutas com a escrita e a construção da webApps, e peço desculpas por não ter conseguido colocar este livro em suas mãos mais cedo: você precisava disso. Você vai querer ler e escrever código que se parece com o meu e funciona como o meu e faz a mesma coisa, mas ainda melhor, porque se você puder comprar este livro em vez de esmagar seu teclado como eu fizer apenas para criar um livro pedindo dinheiro Para isso, você tem os recursos necessários para ter sucesso em sua vida. Eu tive todos os tipos de problemas com a família crescendo, condições de saúde, médicos, mídia e lei e meu código reflete profundamente a luta que é o feminismo e a natureza feminina em um mundo dividido e frustrado. No entanto, este livro é algo com o qual me preocupo profundamente, meu bebê, meu portfólio e meu sustento, por isso aprecio sua consideração quando você leva a mensagem para casa e examina cuidadosamente sobre ele para aprender comigo. Por favor, lembre -se de que não souECT, este livro terá erros, revisões e novas edições, e você precisará pensar com seu cérebro lógico da melhor maneira possível para ter uma experiência bem -sucedida com a minha escrita. Além disso, entenda que quero dizer bem para você, mesmo quando você enfrenta desafios ao escrever. Pense assim: quando você pode alugar um sistema de computador para fazer qualquer coisa que possa imaginar no espaço digital, armazenar todas as informações que encontrar, #$%! Yze e organizá -lo e entender, você vai Inevitavelmente encontra dificuldades com as informações que você está ingerindo e até publicando. Eu te digo isso porque encontro as mesmas dificuldades. Use este livro por sua conta e risco, trabalhe com sua comunidade e comunidades disponíveis para criar software em um ambiente seguro e não leve as coisas para o pessoal quando você falhar ou até ter sucesso da maneira errada: foi assim que cheguei tão longe , e por que posso trazer este texto para você e ajudá -lo a ter sucesso sem desviar um caminho de loucuraOs Aves me arruinaram, rasgados e desgastados enquanto encontro os problemas comuns que todos fazem em escala global, graças à escala global paralelista da rede em que trabalharemos, a Internet. Você pode não estar muito familiarizado com quem eu sou com apenas algumas palavras, mas eu encorajo você a ler, você me conhecerá enquanto continua a me ler e me entender ao criar seus próprios projetos para concluir seu trabalho. Não haverá lição de casa com este livro, desde que seus professores ou professores não atribuam nada a você, mas eu o encorajo a construir um portfólio de projetos enquanto você lê junto, bem como um projeto Capstone mostrando como você pode Aplique o que você aprendeu. Meu projeto Capstone é a base para a maior parte do que você lerá neste livro, pois incorpora código dos meus projetos anteriores, código que criei e aprendi a escrever metodicamente manualmente, e uma ampla gama de idéias e dicas que me ajudaram ter sucesso no ponto em que posso aumentar um aplicativo simples queTotalmente destaque e parece e se comporta como um aplicativo popular que você pode ver seu amigo ou família usando, na Internet, anunciado para você ou nas notícias. O que é este livro: Este livro é um tutorial pelo exemplo. Você pode encontrar código aqui, instruções de como aprender a codificar, informações sobre depuração de código e corrigir erros, solucionar etapas, instruções sobre como fazer backup e salvar seu código, re-implantar se alguém quebrar seu código, proteger seu código, implantar Seu código, construa sites interativos divertidos, envolventes e viciantes, e você terá uma noção de quem eu sou, por que isso é importante e como se retratar, seu aplicativo e imagem da empresa, bem como o software Você constrói a melhor luz absoluta para ser a mais atraente possível para os usuários finais, os visitantes do seu site. Neste livro, demonstrarei vários exemplos de design de software com foco na Web como uma plataforma e na segurança. Iniciaremos a experiência de aprendizado construindo um básicoOjetar usando o shell Unix, com recursos de backup e script. Em seguida, examinaremos um site básico do blog, atualizaremos nosso blog com recursos de fotos e vídeos, além de usar esses recursos para empregar soluções de segurança usando software livre e proteger nosso servidor usando um módulo de autenticação (PAM) em tragada. Em seguida, revisaremos o manuseio e o processamento de arquivos, explorando a edição de vídeo, doação de voz, digitalização de código de barras e reconhecimento de caracteres ópticos, entre outros conceitos. Ao longo do caminho, examinaremos as APIs, o que nos ajudará a tornar nosso software mais útil e seguro, com opções gratuitas e pagas. Ao longo do caminho, exploraremos as ferramentas de segurança física e militantes, como armas de fogo e munições, design e fabricação, incluindo design de barril e repetidores, design de torre e drones e outros diretores que integraremos ao nosso software na rede existente para proteger nosso software e demonstrar defesa e rescisão. Vamos fazer pausas ao longo do caminho para construir jogos, 2D e 3DMotores de encerramento e trabalho com hardware incorporado em exemplos de estudo de caso de software básico de renderização dimensional e um massageador eletrônico elegante fundido em borracha de silicone, respectivamente. Ao longo do caminho, também empregaremos soluções de aprendizado de máquina já disponíveis para proteger melhor nosso software. Também empregaremos ferramentas de estoque disponíveis para a Web para otimizar e proteger o processo. Este livro é um guia para o seu sucesso na criação de um aplicativo da Web e integra -o com uma rede profissional de sistemas mecânicos incorporados e incorporados, e em geral um guia para criar software e hardware incorporado, sem conhecimento de fundo ou experiência anterior. O que este livro não é: Se você realmente deseja ter um site, pode simplesmente configurar uma loja simples e vender o que precisa, postar um blog, postar fotos ou vídeos ou de outra forma sem nunca escrever uma única linha de código. Este livro não é isso. Este livro ensinará como criar software que é mais útil, totalmenteEm destaque, funcional e seguro do que qualquer software que você já possa encontrar, porque implanta o software mais recente que ainda é protótipos, pode ser caro para executar em uma escala que empresas mais antigas operam e não apela para as empresas complicadas e complicadas configuradas para Ganhe dinheiro para pessoas que realmente não estão fazendo nada. Se você seguir este livro de perto, desejará escrever código, pesquisar código, criar seus próprios aplicativos e ganhará dinheiro com o que faz. Vou ganhar dinheiro com este livro, mesmo nos estágios iniciais, porque ele contém informações que as pessoas precisam e querem ler, e já estão comprando quando compram ou usam meus aplicativos. Este livro não criará um aplicativo para você, mas o apontará na direção certa e armará você com as ferramentas necessárias e as habilidades e dicas que facilitarão seu próprio sucesso na criação de software para a web, com todas as linhas de Código, você precisará escrever como exemplo, pronto para ser reunido em software que você e seus apoiadores, convidados, clientela,Riends, família, visitantes, contratados e as pessoas da Internet desejam usar e apoiar. O que você aprenderá: Este livro ensinará como construir e vender software, software realmente funcional, útil, gravação de mídia, recursos de segurança como reconhecimento facial, digitalização de código de zona legível por máquina, APIs da web para autenticar, gravar e renderizar vídeos e fotos e trocar mensagens como Bluetooth e comunicação próxima (NFC). Este livro ensinará como usar um computador em rede, concentrando -se no Debian Linux, como criar código Bash para tornar a instalação e o backup de seu software uma brisa automática e perfeita, como criar código Python como um back -end para servir mensagens dinâmicas, estilo coisas bem usando estilos CSS com bootstrap, permitem logins de usuários e interatividade por meio de dispositivos em rede, criar mídia interativa e rede com outros sites para oferecer recursos de segurança como mensagens de texto para verificação ou outro propósitos, digitalização de ID, moderação de imagem e vídeo, dadosRansações para manter seu software seguro, processamento de pagamentos, negociação de criptomoeda, tarefas assíncronas e muito mais. Você aprenderá a construir seus próprios dispositivos Bluetooth, com baterias, carregadores, microcontroladores, circuitos, motores e sensores, usando solda, arame e 3D impressos e materiais fundidos. Demonstrarei os diretores de design 3D aplicados à fabricação e fabricação de ferramentas aditivas, para que você possa fabricar seus próprios dispositivos incorporados e de hardware com baterias integradas, carregadores, circuitos eletrônicos e saídas funcionais. e conecte -os com Bluetooth e a Web. Especificamente, examinaremos dois estudos de caso, um massageador vibratório e uma arma de fogo caseira, ambos programados no OpenSCAD, que está disponível como uma interface gráfica ou utilitário de linha de comando e pode ser integrado a uma Web para obter resultados mais rápidos. Você aprenderá a construir e implantar um site desde o início, sem experiência anterior, torná -lo funcional, seguro, bonito, útil e maismPorravelmente prático. Você aprenderá como usar o aprendizado de máquina e a visão computacional para tornar um site seguro e mais prático, gravar vídeo e áudio do seu site, doar sua voz, fazer música e modular áudio para criar amostras úteis e como romper o barulho por meio Aproveitando outros sites para criar a melhor rede possível de sites que você pode vincular diretamente ao seu para compartilhar todas as informações úteis que você tem a oferecer e ainda mais importante levar as pessoas ao seu software e negócios. Este livro será focado mais fortemente na mídia, segurança e aprendizado de máquina, que são os três componentes principais que ajudarão você a criar software útil para a Web, envolvendo os usuários certos e desmembrando os errados de uma maneira realista, prática, prática, Mãos e envolventes enquanto também são automáticos e resistentes. Este livro ensina Unix, especificamente Debian (Ubuntu), Bash Shell, Python, HTML, CSS, JavaScript e vários pacotes de software úteis paran As solicitações semelhantes, bem como software de bash útil como Git e FFMPEG. Também ensinarei como negociar a criptomoeda automaticamente e receberei pagamentos em criptomoeda ou de cartões de débito regulares, ao mesmo tempo em que pagam aos visitantes uma parte da sua receita, se você optar por fazê -lo. Vou te ensinar como ganhar dinheiro com seu site através da publicidade também, como preparar seu aplicativo para mecanismos de pesquisa e torná -lo rápido, classificado na primeira classificação do que seus clientes pesquisarão para encontrá -lo e classificar o maior número de Pesquisa possível. Ensinarei como vender seu software, anunciá -lo, apelar para os clientes que procuram seus serviços e fazer um nome para si mesmo na Internet através de avenidas que já existem, são baratas e funcionam bem. Vou te ensinar como salvar seus dados em computadores em nuvem que funcionam para você e salvar seus dados baratos, como planejar e construir um site que faça o que seus usuários desejam e o que você deseja e como manter seus usuários envolvidos porEm seu site, toque em seus telefones com notificações, email, mensagens de texto, telefonemas e mais avenidas para trazer seus usuários de volta ao seu site à sua disposição por trás do clique de um botão apenas garantido para você. Este livro se concentrará na praticidade de publicar e distribuir mídia em grandes quantidades, de texto a fotos e vídeos e áudio, causando uma boa impressão nos usuários finais (sua clientela) e vendendo -se de qualquer maneira que você faça para criar Um site, um aplicativo que é representativo de você e você apenas, e faz de você, seu software e sua empresa ficam bem da melhor maneira possível. Você também aprenderá algumas dicas e truques comigo, desde dicas de codificação, vaidade prática como maquiagem e fotografia, modelagem e atuação e muito mais, o que será importante para retratar a si mesmo e sua empresa da melhor maneira possível usando todas as ferramentas disponíveis para você enquanto distribui o máximo de conteúdo necessário em um equilíbrio saudável de plataformas para trazer seue concretizar sem mais esforço, trabalho ou dinheiro do que o necessário. Este livro é chamado de “aprendizado e segurança práticos baseados na Web, por exemplo” por um motivo: lida com o aprendizado de codificar, especificamente para a Web, especificamente com foco na segurança, do ponto de vista prático, com exemplos de código de trabalho que serve Os propósitos práticos descritos no texto. O componente de aprendizado deste texto também abrange o aprendizado de máquina, o código que mostrarei como executar a Web que lidará com a visão computacional, reconhecimento facial, moderação de imagem e vídeo, aprimoramento de imagem, aprimoramento da resolução, legenda de imagem e outras tarefas como As métricas de previsão provenientes de imagens, como a natureza da imagem como uma imagem autêntica transferida por computador ou uma cópia óptica (uma foto de uma imagem ou foto impressa). O aprendizado de máquina é muito importante quando se trata de segurança da Web e segurança de software, porque pode pré -formar tarefas que, de outra forma, eram impossíveis. Seu computadorFaça login você com uma senha, mas pode ser mais seguro usá -lo se ele registrar você com o rosto. Você pode fazer com que um computador servidor seja seguro, um computador que normalmente solicitaria um nome de usuário e uma senha e efetuaria login, talvez com um token de confirmação para cada novo login ou novo endereço IP, mas se estiver construindo em larga escala, fácil de Uso, software fundamentalmente seguro e poderoso, isso pode ser suficiente. Amarrar seu software muito de perto ao software de outra pessoa, como um serviço de e -mail ou serviço de mensagens de texto, não é suficiente para tornar seu software seguro ou de qualquer um (qualquer site que você use). Qualquer pessoa que constrói software que seja impecavelmente seguro tem alguma noção do que isso implica. O software é inerentemente inseguro porque os dispositivos e contas que usamos para acessá -lo nem sempre estão à nossa disposição, eles podem estar nas mãos de qualquer pessoa com má intenção do software e, portanto, podem representar um risco para o próprio software. Isso é algo do foco deste livro. Um computador em rede é por padrãoprotegido com um token de chaves longos, chamado e shell shell, e é melhor protegido com um servidor da web, porque o servidor da web fornece o acesso aberto e as ferramentas de segurança de ponta em execução no próprio servidor. O servidor da Web tem acesso ao navegador da Web do usuário, que é sem dúvida a parte mais poderosa do dispositivo do usuário, porque é o local onde o usuário pode acessar o software em rede. Este kit de ferramentas pode renderizar texto, as páginas da web que você vê e também pode gravar imagens, áudio e vídeo (como uma foto de um rosto ou um ID de estado), pode ler e escrever em dispositivos de rádio Bluetooth e pode ler e escrever para o campo próximo Tags transponder, cartões -chave baratos, fobs, adesivos, anéis e até implantes de chip com números de série exclusivos que podem ser lidos e gravados com dados gerados e validados por um servidor da Web vinculado ao site. Usando todas as ferramentas à sua disposição, com este livro você se equipará com o conhecimento para construir um site seguro e em geral umO sistema de computador em rede URE que funciona para você, faz sua oferta e parece e parece certo. Por onde começar: Você pode passar pela seção com quem inicio este livro, ou qualquer seção, para o código exato de que você precisa, especialmente se você tiver experiência com codificação antes ou qualquer uma das ferramentas acima mencionadas que descreverei em detalhes neste livro como bem como documentar casos de uso e exemplos práticos dos mesmos. Se você não tem experiência em escrever código, eu recomendo que você leia todo este livro e, especialmente, recomendo ler as seções anteriores, para garantir que este livro seja adequado para você. Se este livro não for adequado para você, considere presenteá -lo a um amigo ou parente que possa estar interessado em aprender sobre o desenvolvimento da web e até mesmo considere emprestá -lo de volta e aprender com eles para preencher as lacunas em que eu falhei em você como um Professor ou outros professores fizeram antes de mim. Comece onde você quiser, todas as partes deste livro serão úteis se você pretender construir um útilPP, e considere que os melhores aplicativos são criados com o usuário final em mente: conheça seu cliente. Agora você me conhece, conhece este livro e está pronto para começar. Para começar, pegue um computador (até o laptop mais barato de uma loja de caixas, Amazon ou uma área de trabalho antiga e configure de uma maneira que funcione para você. Como ler este livro: O texto destacado indica que o texto pertence a um prompt de comando, onde você escreverá o código que você executa. O prompt de comando é fortemente focado no teclado e requer pouco ou nenhum clique, acelerando seu fluxo de trabalho e facilitando as coisas. Começando: Vamos mergulhar. Começaremos construindo código em uma máquina local e começamos sem criar um site conectado à Internet. É mais seguro começar, não custa nada e é fácil para você. Dependendo do seu sistema operacional, entrar em um shell bash será um pouco diferente. Para o Mac OS, eu recomendo instalar uma máquina virtual neste momento, pois você obterá a maior compatibilidade commáquina virtual. Vários provedores, como VirtualBox e Paralells, podem executar uma máquina virtual para você, embora também seja possível instalar o Ubuntu diretamente na máquina, se você preferir usar um ambiente nativo que seja recomendado para criar uma experiência rápida e simplificada. Se você estiver usando o Linux ou o Windows, o que eu recomendo, deve ser muito fácil criar um projeto. Abra seu terminal, ajuste o dimensionamento como achar melhor e comece a seguir a etapa 2. Se você estiver usando o Windows, siga a Etapa 1. Etapa 1: - Somente usuários do Windows No Windows, abre o prompt de comando como administrador e tipo WSL - Instalação Etapa 2: - Continue aqui ou pule a Etapa 1 para aqui se você não estiver usando o Windows Em um terminal aberto (dependendo do seu sistema operacional, chamado Ubuntu no Windows, terminal no Mac ou Linux ou um nome semelhante), comece criando um projeto. Fazemos isso com o comando mkdir, que cria um diretório. Se você precisar criar um diretório para armazenar seu projeto, que é recomendado, use ocomando do CD para mudar para o diretório e e CD/PATH/TO/Diretório - O caminho são as pastas (arquivos) que precedem seu diretório de destino, seu caminho padrão é ~ ou/home/nome de usuário (onde o nome de usuário é seu nome de usuário). Para mudar para o diretório padrão, digite CD ou CD ~ Exemplo de Mkdir - Substitua "Exemplo" pelo nome do diretório Agora você tem um diretório de trabalho para o seu projeto. Sendo como é tão importante economizar esse diretório, caso você precise mudar para uma máquina diferente ou implantar o código que você escreve para que esteja pronto para a Web, criaremos um script para fazer backup de seu diretório nas próximas etapas. Mas a construção de um script leva um pouco de código e o código precisa ser automatizado para ser o mais útil possível. Então, vamos criar um script para criar scripts primeiro. Vamos começar criando o script e tornando -o executável. Usaremos sudo, chmod e toque para isso, e chamar o script


sudo touch /usr/bin/ascript
sudo chmod a+x /usr/bin/ascript
sudo nano /usr/bin/ascript
Agora criamos o script, o fizemos executável e estamos prontos para editá -lo. Nano é um editor de texto que permitirá editar o texto sem clicar, o que é muito mais fácil do que usar uma interface gráfica do usuário. Para editar um arquivo com Nano, use o Nano e, em seguida, o caminho para o arquivo. Para fazer um script que faça um script, é bastante semelhante a fazer nosso script em primeiro lugar. Usaremos o mesmo código acima, substituindo o nome do script, "ASCRIPT" por um parâmetro de argumento, US $ 1. Isso nos permite chamar o script digitando simplesmente o jaccript do sudo, quando podemos criar qualquer novo script substituindo o "JEXCRIPT" pelo nome do seu script. O código em Nano deve parecer:

sudo touch /usr/bin/$1
sudo chmod a+x /usr/bin/$1
sudo nano /usr/bin/$1
E para fechar o Nano, podemos manter a tecla de controle e pressionar X, então y para denotar que estamos salvando o arquivo e pressionar o retorno. Agora, em vez de digitar esses três comandos para editar um script, poderemos digitar o ASCRIPT SUDO ASCRIRT para editar o script novamente. Isso funciona! E qualquer novo script pode ser executado facilmente chamando -o no shell. Vamos salvar nosso trabalho agora: vamos escrever um script de backup para salvar nosso novo script e, em seguida, faça o backup em nosso diretório de projetos, enquanto também backupam do script de backup.

sudo ascript backup
Agora, em Nano:

sudo cp /usr/bin/backup /path/to/directory/
sudo cp /usr/bin/ascript /path/to/directory/
Onde/Path/to/diretório é o caminho para o projeto que você criou com o MKDIR. Mais tarde, aprenderemos a copiar caminhos repetidos como esse com um loop e uma lista, que é menos código, mas por enquanto vamos simplificar e ter algumas linhas. Para executar este script e fazer backup de seu código, salve o arquivo em nano com controle+x, y e retorne e digite o abaixo no seu shell

backup
Se você for solicitado por uma senha enquanto lê este livro e acompanha o shell, digite a senha do usuário corretamente, você terá três tentativas antes de precisar executar novamente o comando. Você pode usar as setas para cima e para baixo para executar os comandos e editá -los, se precisar executar qualquer coisa duas vezes. Pressione simples para cima e para baixo intermitentemente para selecionar um comando, antes de editar o comando com as setas direita, esquerda e excluir a tecla, bem como o teclado e executá -la com devolução. Parabéns! Você conseguiu criar um script de backup incrível que faça backup de dois scripts de shell importantes em seu diretório de trabalho. Podemos mover as coisas mais tarde, à medida que o projeto aumenta, mas isso funciona por enquanto. Vamos fazer o backup da nuvem, usaremos o Github para isso (embora existam inúmeras outras soluções Git para backup, elas são as mesmas.) O Git é um software de controle da Verision que permite fazer backup de edições para o seu software como você os chega a um servidor, enquantoTambém permitindo baixar cópias inteiras do seu software por trás de uma senha ou chave. É fundamental para salvar seu software, especialmente porque migramos para instâncias garantidas do Linux que às vezes quebram quando uma única linha de código falha, deixando você bloqueado enquanto seu código pode não ser backup se você não tiver a chance de apoiar Aumente automaticamente, que abordaremos. Se você ainda não está usando uma máquina virtual do Ubuntu neste momento, recomendo o uso de uma máquina virtual do Ubuntu neste momento, pois facilitará sua vida ao instalar todos os pacotes necessários para construir um site de trabalho e pré -formar o aprendizado profundo operações no seu computador. Vamos mover o código para um servidor da web em um futuro próximo, mas queremos garantir que haja pelo menos algumas camadas de segurança por trás do nosso servidor da web que são resistentes ao phishing e empregar vários pacotes Linux para fazer esse. Se você ainda deseja usar o Mac OS, poderá procurar e instalare pacotes necessários on -line, mas pode não haver alternativas para cada pacote que este livro ou série abordará. Vamos adicionar alguns comandos para cometer nosso trabalho com o script de backup executando o comando sudo ascript

# ...
git add –all
git commit -m “backup”
git push -u origin master
Mais uma vez, controle x para salvar. Agora precisamos fazer uma configuração única para este projeto. Como em breve será um projeto Git, não precisamos digitar todos os comandos toda vez que implantarmos de um repositório Git, mas obteremos o jeito disso quando escrevermos nossos scripts de implantação. Para começar, certifique -se de que estamos no diretório certo e inicialize o repositório Git e gerar teclas SSH.

cd /path/to/directory
git init
git branch -m master
ssh-keygen
Depois de digitar SSH-keygen, a nova chave deve ser salva na pasta doméstico sob uma pasta chamada .ssh. É chamado de id_rsa.pub. Vamos encontrar essa chave e copiá -la. Para ver,

cd ~
cat .ssh/id_rsa.pub
Copie o texto que é retornado pelo último comando e crie uma conta com seu provedor Git (idealmente Github), antes de adicionar a chave SSH à sua conta. Depois de ter uma conta, clique no menu superior direito e insira as configurações, antes de adicionar sua tecla SSH nas teclas SSH e GPG em acesso no menu. Selecione Adicionar uma tecla SSH e adicione a sua, colando -a e fornecendo um título, antes de salvar e retornar ao Github para criar um novo repositório. Isso é semelhante para outros provedores do Git, você precisará ler a documentação deles. Na nova configuração do repositório, dê ao seu repositório um nome descritivo e decida se deseja publicá -lo e não se esqueça de configurar nenhum arquivo para inclusão ainda. Depois que o repositório for criado, copie o clone com o URL SSH e cole -o no comando a seguir.

git remote add git://… (your remote URL)
Agora você pode voltar ao seu repositório com CD, estará familiarizado com isso. Experimente seu script de backup agora com backup Ótimo! Agora podemos realmente obter codificação. Vamos instalar o Django agora que temos uma boa compreensão de Bash e Git. O Django nos permitirá automaticamente fazer backup de nosso software, o Bash também pode fazer isso, mas o Django deve ter uma implementação mais simples mais simples (pode ser desativado e configurado com mais facilidade). Para instalar o software no Ubuntu, usaremos o comando sudo apt-get. Primeiro, vamos atualizar e atualizar o software que já tivemos. Isso pode ser feito com a atualização sudo apt-get e sudo apt-get upgrade -y. Em seguida, vamos instalar o Python e nosso ambiente virtual, a casa do nosso código, com o seguinte comando: sudo apt-get install python-is-python3 python3-venv Isso é tudo o que você precisa para continuar com o Django em termos de instalações de software na instância do Ubuntu. Para Windows e Linux, isso deve ser bastante direto, mas para Mac você pode querer instalar uma máquina virtual eO Linux usando um ambiente virtual gratuito ou pago, como o VirtualBox ou a Paralells Desktop, e recrie as etapas acima para configurar um ambiente do Ubuntu. O Ubuntu é crítico neste caso, porque é o software que os sites executam e permite que eles hospedem sites com todo o software mencionado acima. Vamos cavar no Django. Em nosso diretório novamente, com

python -m venv venv # Cria o ambiente virtual onde o código é armazenado
source venv/bin/activate # Ativa o ambiente virtual
pip install Django
django-admin startproject mysite . # Onde o Mysite é o projeto que estou começando no meu diretório atual.
O Django está apenas nos iniciando, porque o Django está hospedando o servidor da web e está fazendo tudo o que precisamos para obter um site local básico em funcionamento. Agora que temos o Django instalado, vamos editar um pouco as configurações para fazê -lo funcionar como precisamos. Primeiro, vamos criar um novo aplicativo

python manage.py startapp feed
Você notará que o primeiro aplicativo é chamado Feed. O aplicativo deve ser chamado do que você quiser, e criaremos novos aplicativos, mas o nome de cada aplicativo deve ser consistente sempre que o aplicativo for referenciado no código. Para adicionar um novo aplicativo, sempre editaremos o Settings.py no outro diretório que o aplicativo criou, nomeado no StartProject, a seguir. Usando Nano,

nano app/settings.py
Nas configurações, encontre instalado_apps e separe o [] em 3 linhas. Usando quatro espaços na linha central vazia, adicione 'feed' ou o nome do seu aplicativo. Esta seção do Settings.py deve parecer:

INSTALLED_APPS = [
    'feed',
]
Antes de esquecermos, vamos testar que o Django está funcionando. Usando o comando python gerencia.py runServer 0.0.0.0:8000, podemos executar o servidor e navegar em um navegador da web no computador executando o código para http: // localhost: 8000 e ver um exemplo da web página (ele funciona!) Saia do servidor com controle C, o mesmo que qualquer outro comando. Agora, vamos escrever um código Python. O Django tem três componentes principais, todos executados por código inteiramente. Os componentes são chamados de modelo, visualização e modelo, e cada um está em um nível mais alto e mais baixo, respectivamente, antes que a página da web seja entregue ao usuário. O modelo é o código que armazena informações no banco de dados para recuperação, classificação e renderização. A visão decide como o modelo é renderizado, manipulado e modificado, quase todas as visualizações usarão um modelo diretamente. O modelo é o código HTML com alguns sinos e assobios extras chamados de linguagem de modelo. O modelo é renderizado pela visão onde está preenchido com código python eContexto como modelos e informações (Strings e números de USOLL) da visualização. Django também tem outros componentes, incluindo, entre outros,: Configurações, que configuram o aplicativo como discutimos. URLs, que são padrões que o usuário segue para obter acesso a partes específicas do aplicativo da web. Formulários, que definem como as informações enviadas ao servidor são tratadas e renderizadas no banco de dados e também ao usuário. Essas são a base do processamento de informações do lado do servidor e podem aceitar qualquer tipo de informação que as lojas de computadores, principalmente seqüências de texto, números e booleanos verdadeiros/falsos (geralmente caixas de seleção). Modelos, que são o código HTML e a linguagem de modelo e preenche a lacuna entre Python e HTML, o que significa que as informações do Python podem ser servidas como código HTML que qualquer pessoa pode acessar e proteger um site com acesso restrito, ao mesmo tempo em que tornar o código Python acessível à Web e útil para uma variedade de propósitos em um dispositivo remoto que nãopara estar perto do servidor. Arquivos estáticos, que geralmente são JavaScript e suas bibliotecas que o servidor serve e estão vinculadas ao modelo. Os arquivos de mídia, que o servidor serve ou são hospedados externamente, ou apenas gravados no servidor antes de serem processados ​​e publicados em outro servidor (um balde) para hospedagem. O middleware, que é executado ao mesmo tempo que todas as vistas e são consideradas "incluídas" na visualização. Processadores de contexto, que processam o contexto de cada visão e são usados ​​para adicionar contexto extra. Os testes, que validam que o usuário ou solicitação passa certos requisitos antes da renderização da exibição. Os consumidores, que ditam como os websockets lidam e respondem à comunicação. Admin, que é usado para registrar modelos para que eles possam ser manipulados em detalhes na página de administração do Django, onde o banco de dados pode ser administrado através de uma interface gráfica. Aipo, que define tarefas assíncronas que partes do código do django podem começarAntes de prosseguir imediatamente para a próxima tarefa ou linha de código. O Django pode ter muitos outros componentes, que discutiremos em detalhes aqui. Existem muitas maneiras de tornar o Django mais funcional, adicionando websockets, que são canais de comunicação rápidos e simplificados, aipo, que executa tarefas assíncronas e uma infinidade de outros softwares para estender o django, especialmente nas funções de exibição, onde a maioria dos o código é executado. As funções de visualização são fundamentais porque geralmente declaram todos os códigos específicos de um padrão de URL específico ou de uma seção do servidor. Primeiro, vamos explorar funções de exibição. As funções de visualização começam com as importações que denotam o código que será usado na visualização e é definido usando definições ou classes de funções regulares. As visualizações mais simples são definidas pela definição da função definidas e retornam uma resposta HTTPRPRESS com um modelo básico. Vamos começar definindo uma visão básica para retornar o texto "Hello World". Lembre -se de que cada vez que você adicionaFter uma declaração como def, se, enquanto, para, etc, você precisará adicionar 4 espaços para cada uma das definições anteriores que você gostaria de aplicar à sua função. Entraremos no que cada um desses meios em breve. No diretório do nosso site, edite o arquivo Feed/Views.py usando Nano e adicione as seguintes linhas ao final do

from django.http import HttpResponse

def hello(request):
    return HttpResponse('hello world')
O httproponse de Django responde com uma sequência de texto, indicada com a abertura e o fechamento '. Toda vez que você passa informações para uma função ou classe, como solicitação ou string, você precisará usar parênteses (, abrindo e fechamento). Isso não é tudo o que precisamos para ver nossa visão ainda. Obviamente, não dissemos ao servidor onde está exatamente a visualização, ainda precisamos definir um caminho pelo qual a visualização deve renderizar. Vamos começar definindo um caminho básico no app/urls.py, e entraremos em grupos de caminho posteriormente. No app/urls.py, adicione uma linha após as instruções de importação após o início da importação da visualização que acabamos de criar.

from feed import views as feed_views
Agora, vamos definir o padrão de visualização. Os padrões de visualização têm três componentes, o componente do caminho, que informa ao servidor onde a exibição existe dentro do servidor (o caminho da URL que o usuário digita na barra de navegação para entrar na página da web), o componente de exibição em que a visualização é especificada e a a Nome amigável para a visualização para que seja fácil recuperar seu padrão ao trabalhar com um modelo, especialmente para que seu nome possa ser alterado e atualizado, se necessário, para abrir espaço para outra visão ou assumir um nome mais lógico. Faz sentido fazer as coisas dessa maneira e ser flexível, porque sua base de código será um ambiente em constante mudança que precisa de flexibilidade e improvisação para serem valiosas e fáceis de trabalhar. Aqui está a aparência da sua opinião, você pode adicioná -lo aos urlpatterns = [Seção do app/urls.py. O padrão de visualização é definido com os três componentes descritos acima e uma função chamada caminho. Seus padrões de URL são uma lista, portanto, sempre termine cada item nelescom uma vírgula, porque isso separa cada um. Cada item também deve ir em uma nova linha, mais uma vez com quatro espaços antes dele, assim como o aplicativo em Settings.py. Definiremos o primeiro componente da visualização com uma função de string vazia, a fim de criar uma visualização executada no diretório raiz do servidor da Web. Seu urls.py agora deve parecer

from feed import views as feed_views

urlpatterns = [
    path('', feed_views.hello, name='hello'),
]
Esta é a base para criar um site com Django que é completamente estático. Para criar um site mais dinâmico, onde podemos iniciar informações sobre armazenamento em cache, como imagens, vídeos, áudio e muito mais, precisaremos usar modelos, que exploraremos a seguir. Por enquanto, vamos verificar nosso código e executar o servidor. Para verificar o código quanto a erros, execute:

python manage.py check
Se houver alguma mensagem de erro, você deve revisar cuidadosamente as alterações que fez no seu aplicativo e ver se há algo que precisa ser corrigido, como um espaço estranho ou carente, um personagem extra, uma corda não -clínica, qualquer erro de digitação, qualquer outro acidentalmente Caráter excluído, ou qualquer outra coisa. Lendo a mensagem de erro (se você tiver uma), você poderá ver o caminho para um arquivo que você criou ou editado junto com um número de linha; portanto, observe esse arquivo e linha e veja se pode corrigir qualquer coisa que esteja lá . Se você corrigiu o problema, execute o comando acima novamente. Quando seu software estiver pronto para executar e estiver funcionando, você verá a saída "Verificação do sistema identificada sem problemas". Agora você está pronto para ir. Execute o servidor com:

python manage.py runserver 0.0.0.0:8000
Agora abra um navegador da web e navegue para http: // localhost: 8000. Você deve ver o texto retornado nos parênteses e citações da função HTTPRESPONHE em sua opinião. Este é apenas um exemplo básico, mas se você chegou até aqui, entende o básico de como o Linux, Bash, Python e Django trabalham. Vamos nos aprofundar em alguma modelagem de banco de dados e explorar o poder de uma classe Python no armazenamento de informações. Em seguida, começaremos a controlar o HTML e o CSS antes de tornarmos nosso site totalmente em destaque, flexível e seguro usando JavaScript e Machine Learning. As aulas são armazenadas nos modelos.py do seu aplicativo. Usando Nano, edite aplicativo/models.py e adicione uma nova classe. Uma classe é definida com a definição de classe e é aprovada em uma superclasse que herda, neste caso models.model. O nome da classe ocorre após a definição da classe e, após a definição da classe A: (cólon), antes que os atributos e definições de função vinculados à classe sejam denotados abaixo. Nossa aulaPrecisa de um ID que possamos usar para recuperá -lo e mantê -lo único, e também precisa de um campo de texto para armazenar algumas informações. Mais tarde, podemos adicionar um registro de data e hora, booleanos (definições verdadeiras ou falsas que podem ajudar nosso código a tomar decisões sobre o que fazer com o modelo e pode ser usado para classificá -lo), uma instância para vincular o modelo a um usuário registrado no servidor e muito mais. Vamos descompactar o código

from django.db import models # A importação usada para definir nossa classe e seus atributos

class Post(models.Model): # A definição de nossa classe em si
    id = models.AutoField(primary_key=True) # O ID do nosso modelo, uma chave gerada automaticamente que nos permite consultar o modelo, mantê -lo único e é útil quando precisamos interagir com o modelo depois de criar.
    text = models.TextField(default='') # O atributo nossas lojas de classe, neste caso, algum texto, inadimplente para uma string vazia.
Feche e salve o arquivo como fizemos antes para terminar. Existem muitos outros campos e opções que exploraremos quando atualizarmos essa classe à medida que nosso aplicativo evolui, mas essas são as necessidades básicas de criar um aplicativo para postar algum texto. No entanto, esse modelo não funcionará sozinho. Conforme descrito anteriormente, precisaremos de uma visualização personalizada e padrão de URL personalizado para fazer com que esse modelo funcione, e também precisaremos de um formulário junto com um modelo. Vamos explorar o formulário primeiro. Para definir um formulário, edite app/form.py com nano e adicione as seguintes linhas. Precisamos de duas importações, nossa classe de formulários, bem como o modelo que criamos (feed.models.post), uma definição de classe semelhante ao modelo e um campo junto com uma subclasse chamada meta que definirá o modelo que o formulário interage com. O formulário também pode ter uma função de inicialização que a configura com base nas informações na solicitação, modelo ou de outra forma, exploraremos isso posteriormente. Os formulários de modelo são muito úteis porque podem criar um modelo ou também editar um modelo,Então, nós os usaremos para ambos. Vamos definir um em form.py

from django import forms
from feed.models import Post

class PostForm(forms.ModelForm):
    text = forms.CharField(widget=forms.Textarea)
    class Meta:
        model = Post
        fields = ('text',)
Este é o básico de como é uma forma e modelo. Este formulário de modelo pode ser usado para instanciar ou editar uma postagem, alterando o texto que ele contém. Veremos a integração deste formulário em uma visão a seguir. Primeiro, vamos fazer as migrações e migrar o banco de dados para que nosso código possa interagir com o modelo quando ele for executado. Para fazer isso, execute os seguintes comandos:

python manage.py makemigrations
python manage.py migrate
Isso levará um minuto para ser executado, mas, uma vez que isso acontecer, permitirá que você acesse o modelo nas visualizações, middleware ou em qualquer outro lugar do software. Vamos continuar fazendo uma visão de onde podemos ver nosso modelo. Edite feed/views.py e adicione o seguinte código, conforme observado. Você não precisará adicionar nada após o sinal #, esse código são comentários usados ​​para denotar informações sobre o código. Começaremos importando nosso modelo nas visualizações e adicionando -o a um contexto em que podemos renderizá -lo em um modelo como uma lista para exibição. Em seguida, adicionaremos um modelo em que podemos renderizar o formulário e o modelo com um botão para criar um novo objeto com base no modelo e publicá -lo no servidor. Isso parece complicado, então vamos dar um passo a passo. Antes de terminarmos a visualização, vamos criar um modelo que apenas renderize o modelo e verifique se podemos vê -lo criando uma nova postagem no shell. Veja como essa visão deve parecer:

from feed.models import Post
from django.shortcuts import render, redirect
from django.urls import reverse

def feed(request):
    posts = Post.objects.all() # Consulte todas as postagens no banco de dados até agora
    return render(request, 'feed/feed.html', {
        'posts': posts,
    })
Tudo isso parece bem simples até chegarmos ao fundo. Renderizar, o valor retornado pela função, em vez de em uma resposta HTTP como o exemplo anterior, sempre recebe uma solicitação como sua primeira entrada, aceita um contexto (neste caso as postagens no banco de dados), que agora podem ser renderizadas no modelo e retorna o modelo definido na função. O modelo será um documento HTML com um pouco de um idioma chamado Jinja2, que renderiza as informações do Python no HTML. Para começar a criar modelos, faça dois diretórios no feed.

mkdir feed/templates
mkdir feed/templates/feed
Em seguida, edite um modelo no diretório acima, Feed/Modelos/Feed e adicione o código para este exemplo. Vejamos o modelo para este exemplo.
 
<!doctype HTML>
<html>
<body>
<legend>Feed</legend>
<hr>
{% for post in posts %}
<p>{{ post.text }}</p>
{% endfor %}
</body>
</html>
 
Este é um modelo muito simples. Ele define as tags HTML de abertura e fechamento, uma etiqueta de tipo de documento, uma etiqueta corporal com um título de legenda, uma tag de quebra que adiciona uma pequena linha na tela e um loop que renderiza cada post na lista de postagens como um parágrafo em o modelo. Isso é tudo o que é necessário para renderizar postagens, mas ainda não há no banco de dados. Vamos criar alguns com a concha. Podemos executar o shell com gerencia.py

python manage.py shell
Agora, vamos importar nosso modelo de postagem

from feed.models import Post
Em seguida, criaremos uma postagem simples com uma corda e sairemos do shell. A string pode ser qualquer coisa, desde que seja um texto válido.

Post.objects.create(text='hello world')
exit()
Por fim, precisaremos adicionar um padrão de URL ao nosso feed. Como nosso aplicativo de feeds usará vários URLs e queremos manter os tamanhos de arquivo pequenos, vamos criar um URLs.py local em nosso aplicativo de feeds que se parece com o seguinte:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.feed, name='feed'),
]
Também precisaremos editar os URLs.py no aplicativo base, como decidimos chamá -lo, este foi o primeiro diretório que criamos. Editar app/app.py e adicione o seguinte aos padrões de URL

from django.urls import include # no topo

urlpatterns = [
    # ... código anterior aqui
    path('feed/', include(('feed.urls'), namespace='feed')),
]
Agora, quando executamos o servidor com Python Manage.py RunServer, veremos a página que criamos porque temos o modelo, a visualização e o modelo, bem como o padrão de URL, juntamente com os itens no banco de dados. Em seguida, vamos implementar o formulário que criamos e começamos a criar nossas próprias postagens. Mas antes de escrevermos muito código, vamos fazer um backup usando o script que escrevemos anteriormente, backup. Execute este script no shell, aguarde alguns momentos e todo o código será backup do nosso repositório Git.

backup
Implementar o formulário é relativamente simples. Vamos importar nosso formulário, adicionar um manipulador de solicitação de postagem à visualização e salvaremos a postagem no banco de dados antes de redirecionar para a mesma visualização. Podemos usar a função de redirecionamento que já importamos e outra função chamada reverso para obter o URL para o padrão de visualização. Vamos consultar isso com a corda 'Feed: Feed', porque o espaço para nome do padrão incluído é a alimentação e a visualização também é chamada de feed.

from feed.forms import PostForm

def feed(request):
    posts = Post.objects.all() # Consulte todas as postagens no banco de dados até agora
    if request.method == 'POST': # Lidar com o pedido de postagem
        form = PostForm(request.POST) # Crie uma instância do formulário e salve os dados
        if form.is_valid(): # Validar o formulário
            form.save() # Salve o novo objeto
        return redirect(reverse('feed:feed')) # Redirecionar para o mesmo URL com um pedido GET
    return render(request, 'feed/feed.html', {
        'form': PostForm(), # Certifique -se de passar o formulário para o contexto para que possamos renderizá -lo.
        'posts': posts,
    })
Agora, precisamos atualizar o modelo para explicar o novo formulário. Podemos fazer isso usando o
tag no HTML e renderizando o formulário no modelo HTML com um botão Enviar. Também precisaremos de um token CSRF, um token que impede que sites externos postem para o formulário sem primeiro carregar uma página.
 
<!doctype HTML>
<html>
<body>
<legend>Feed</legend>
<form method=”POST”>
{% csrf_token %}
{{ form }}
<button type=”submit”>New Post</button>
</form>
<hr>
{% for post in posts %}
<p>{{ post.text }}</p>
{% endfor %}
</body>
</html>
 
Vamos quebrar isso. Há uma nova classe de formulário, um token, o próprio formulário e um botão de envio. Muito simples, mas quando olhamos para ele, podemos querer fazer com que pareça melhor. Funciona, podemos postar novas postagens com o formulário e elas agora são salvas no banco de dados. Há algumas coisas acontecendo aqui. Usamos as tags HTML para declarar que o documento é um documento HTML, usamos uma tag de modelo ({ %… %}) para renderizar o token para o formulário e outro, {{…}} para renderizar o formulário. Também temos um loop para renderizar o texto usando tags de bloco e uma tag de modelo. As tags de bloco são realmente importantes porque podemos definir como as seções do modelo são renderizadas com elas, e as tags de modelo são a base de como colocamos variáveis ​​em nosso código. Agora precisamos fazer com que nosso aplicativo pareça melhor, porque por enquanto parece realmente básico. Podemos fazer isso usando CSS, embutido ou em classes vinculadas a cada objeto no documento. CSS é muito bom porque diz tudo na página como deve parecer,e pode fazer com que pareça muito bom. Existem algumas bibliotecas que podem fazer isso, mas minha entrada pessoal é o bootstrap. Bootstrap pode ser baixado de seu site,Getbootstrap.com/. Uma vez lá, pressione o botão para ler os documentos de instalação e copie o código da seção Incluir via CDN. Você precisará desse código na parte superior do seu documento HTML, em uma tag chamada Head. Além disso, vamos em frente e criar um modelo de base para que não precisemos recriar esses links em cada modelo. Faça um novo diretório chamado modelos com modelos MKDIR e, em seguida, edite modelos/base.html. Deve ser assim:
 
<!doctype HTML>
<html>
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
</head>
<body>
{% block body %}
{% endblock %}
</body>
</html>
 
Certifique -se de copiar o CSS e o JavaScript, os arquivos .css e .js, porque precisaremos do JavaScript para tornar nosso site mais funcional no futuro. Agora, vamos retornar ao shell do Bash e executar um comando rápido. Lembre -se, se você precisar acessar o ambiente virtual, digite a fonte VENV/BIN/ativar. Isso permitirá que você instale pacotes Python localmente de uma maneira que permita que o Django os acesse. Para fornecer nossos formulários gerados pelas classes de bootstrap de Django, usaremos um pacote Python chamado Formulário Crispy. Podemos baixar isso com o seguinte comando

pip install django-crispy-forms
Depois de instalado, adicione -o ao Settings.py

INSTALLED_APPS = [
    # … Código anterior aqui
    'crispy_forms',
]
Agora, de volta ao nosso modelo de alimentação, podemos remover algumas coisas. Vamos remover o início e o final do documento e substituí -lo por herança do nosso modelo de base, usando estendências e a definição de bloco. Além disso, adicionaremos uma importação de filtro de modelo com carga e um filtro de modelo ao formulário. Por fim, vamos adicionar uma classe de bootstrap ao botão no formulário para fazer com que pareça mais um botão. Isso deve ser assim:
 
{% extends 'base.html' %}
{% block body %}
{% load crispy_forms_tags %}
<form method=”POST”>
{% csrf_token %}
{{ form|crispy }}
<button type=”submit” class=”btn btn-outline-primary”>New Post</button>
</form>
<hr>
{% for post in posts %}
<p>{{ post.text }}</p>
{% endfor %}
{% endblock %}
 
Lindo! Isso já é um pouco de código. Em seguida, devemos testá -lo e garantir que possamos ver que tudo parece bom e também verifique se tudo está funcionando corretamente. Execute o servidor conforme as instruções anteriores e verifique se o site parece e funciona bem. Ótimo trabalho! Você está pronto para passar para a próxima etapa, na qual adicionaremos a funcionalidade de login do usuário usando URLs, formulários, visualizações e modelos semelhantes. O modelo base é importante, e continuaremos a modificá -lo e fazer alterações conforme necessário, mas por enquanto vamos nos concentrar em tornar nosso site mais seguro, permitindo que os usuários façam login com um nome de usuário e senha e, eventualmente, informações ainda mais importantes que ajudará a manter seu aplicativo seguro e sua própria conta acessível apenas por você. Para fazer isso, precisaremos usar o modelo de usuário incorporado em Django. O modelo de usuário é um modelo de banco de dados, como a nossa postagem, que pode ser renderizada para registrar um usuário no site. No futuro, antes de implantarmos o site na Internet, iremosEstenda este modelo com outros modelos atribuídos a ele e crie medidas de segurança adicionais para o login resistente ao phishing. Começaremos usando alguns formulários de login embutidos que o Django fornece. Primeiro, vamos criar um novo aplicativo que usaremos para renderizar os modelos e visualizações para a página de login básica. Também criaremos outros aplicativos para representar os desafios contínuos de login, a fim de proteger o aplicativo, incluindo um pincodo, reconhecimento facial, comunicação de campo próximo, dispositivos externos, autenticação de vários fatores e reconhecimento de impressão digital. Já conversamos sobre iniciar um aplicativo. No nosso diretório, dentro do ambiente virtual, passe gerencia.py estes

python manage.py startapp users
Agora, devemos ter um diretório para o novo aplicativo. Vamos começar criando uma visualização nesse diretório que corresponde ao login do usuário. O Django construiu vistas para logins de usuários, mas estes não serão adequados para nós, porque precisamos de uma visualização personalizada, o que é preferencialmente feito com uma definição. Nesta visualização, começaremos verificando uma solicitação de postagem, aprovar a solicitação.Post para um Loginform importado do Django, autenticar a conta de usuário e fazer login no usuário antes de redirecioná -los para o aplicativo Feed. Em usuários/visualizações.py, adicione o seguinte código

from django.shortcuts import render, redirect
from django.urls import reverse
from django.contrib.auth.forms import AuthenticationForm, SetPasswordForm
from django.contrib.auth import authenticate, logout
from django.contrib.auth import login as auth_login
from django.contrib import messages

def login(request):
    if request.method == “POST”:
        username = request.POST['username'] # Obtenha o nome de usuário e a senha da solicitação de postagem
        password = request.POST['password'] # Autentique o usuário
        user = authenticate(username=username, password=password)
        if user:
            auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
            messages.success(request, 'Your password was accepted. Please continue')
            return redirect(reverse('feed:feed'))
        else: messages.warning(request, 'Username or password incorrect. Please try again')
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
Isso é tudo o que você precisa para uma visualização básica de login. Agora, vamos criar um formulário para a visualização, estendendo o modelo base. Começaremos criando um novo diretório para modelos na pasta Usuários.

mkdir users/templates
mkdir users/templates/users
Agora, devemos ser capazes de editar usuários/modelos/usuários/login.html. Enquanto estamos nisso, criaremos um modelo para permitir que o usuário se inscreva também.

nano users/templates/users/login.html
Agora, no modelo,
 
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<form method="POST">
    {% csrf_token %}
    <fieldset class="form-group">
        <legend class="border-bottom mb-4 break">Log In</legend>
        {{ form|crispy }}
    </fieldset>
    <div class="form-group">
        <button class="btn btn-outline-info" type="submit">Login</button>
    </div>
</form>
{% endblock %}
 
Este é o básico de um modelo de login. É realmente como o outro modelo da estrutura, mas parece um pouco diferente quando é renderizado. Podemos copiar esse código para criar outro modelo muito semelhante chamado Register.html, onde alteraremos a redação e usaremos um novo formulário que construímos. Vamos fazer o modelo primeiro. Editar usuários/modelos/usuários/register.html e adicionar o seguinte código:
 
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<form method="POST">
    {% csrf_token %}
    <fieldset class="form-group">
        <legend class="border-bottom mb-4 break">Create an account</legend>
        {{ form|crispy }}
    </fieldset>
    <div class="form-group">
        <button class="btn btn-outline-info" type="submit">Register</button>
    </div>
</form>
{% endblock %}
 
Agora, vamos criar um formulário para o registro do usuário e circular de volta às visualizações antes de atualizarmos nossos logins de usuário com um modelo. Vamos fazer esse formulário básico para começar, mas incorporamos mais detalhes e recursos de segurança, como acordos e captcha no futuro. Edite os formulários com usuários nano/forms.py e adicione o código a seguir.

from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm

class UserRegisterForm(UserCreationForm):
    email = forms.EmailField()

    class Meta:
        model = User
        fields = ['username', 'email', 'password1', 'password2']
Então, temos outra forma aqui, que funciona de maneira justa. É um formulário de registro de usuário com um nome de usuário, email e senha, bem como um campo de senha de confirmar. Observe que este formulário não estende os formulários regulares. Um campo é definido da mesma forma e a meta de classe define o modelo que o formulário corresponde ao restante das informações que serão gravadas no formulário. A maior parte disso já existe no Django's Build In UserCeationForm, por isso usaremos isso como base para a classe (aprovada nos parênteses). Em seguida, examinaremos a visualização para registrar um usuário, agora que temos um formulário e um modelo. Este é um modelform, assim como o da nova visualização do post. Edite usuários/visualizações.py e adicione o seguinte código:

# ... valores
from .forms import UserRegisterForm

def register(request):
    if request.method == “POST”:
        form = UserRegisterForm(request.POST)
        if form.is_valid():
            user = form.save()
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
Isso é tudo o que precisamos para registrar um usuário, mas devemos ter mais informações. Queremos saber o momento em que o usuário se registrou, a que horas eles foram pela última vez no site, algumas informações sobre eles, como uma biografia, fuso horário etc. Além disso, precisamos atualizar nosso modelo de feed, postar, para explicar o usuário Modelo e atributo postagens a cada usuário. Para fazer isso, atualizaremos os modelos.py nos dois aplicativos. Vamos começar editando o modelo de feed. Deve ficar assim agora:

from django.db import models # ... valores
from django.contrib.auth.models import User

class Post(models.Model):
    id = models.AutoField(primary_key=True)
    author = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name='posts') # Adicionar nesta linha
    text = models.TextField(default='')
Preste atenção à segunda linha que foi adicionada ao arquivo. Essa é uma chave estrangeira, que atribuirá cada postagem a um único usuário por postagem, para que possamos garantir que salvemos as postagens em uma base de usuário por usuário e nenhuma postagem possa ser feita sem atribuí-la a um usuário. Definimos essa chave estrangeira com a classe que ela representa, um argumento de exclusão para garantir que as postagens sejam excluídas com usuários, argumentos nulos e em branco para garantir que possamos remover o usuário, se necessário, e para acomodar a falta de um usuário nas postagens que já Criado, e um nome relacionado, que podemos usar para referir aos objetos de postagem que o usuário cria. Este nome relacionado, diferentemente do Post.Author, o autor do Post, nos dá um usuário que postou a própria postagem. Agora podemos obter as postagens que um usuário é feito executando o user.poss.all () ou autor.posts.all (). Agora, vamos tornar nossos logins mais resilientes. Já podemos tornar nosso site muito menos vulnerável ao phishing, simplesmente avaliando o número de vezes que permitiremos um login para oSite, isso é muito fácil. Vamos também começar a armazenar algumas informações sobre cada usuário antes, enquanto continuamos desenvolvendo nosso aplicativo. Editando usuários/modelos.py, adicione o seguinte

from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True, related_name='profile')
    account_created = models.DateTimeField(default=timezone.now)
    last_seen = models.DateTimeField(default=timezone.now)
    can_login = models.DateTimeField(default=timezone.now)
    preferred_name = models.CharField(max_length=20,default='', null=True, blank=True)
    bio = models.TextField(blank=True, default='')
Observe que este modelo é bastante semelhante ao modelo de postagem. Temos uma importação adicional, fuso horário, que nos permitirá definir padrões nos campos DateTime, e também temos um característico e um campo de texto como a postagem. O uso de todos esses registros de data e hora nos ajuda a proteger o site e entender seu uso, e os campos de texto nos permitem renderizar informações sobre cada usuário ou autor no site. O OnetoOnefield deve ser a única consideração menor, ele se comporta exatamente o mesmo que um anterigo, mas com apenas um por modelo subsequente. Dessa forma, o usuário possui apenas um perfil, enquanto pode ter muitas postagens. Agora, vamos melhorar nossas visualizações de login e registro para explicar o perfil. Primeiro, edite usuários/visualizações.py e concentre -se na visualização do registro:

# ... valores
from .forms import UserRegisterForm

def register(request):
    if request.method == “POST”:
        form = UserRegisterForm(request.POST)
        if form.is_valid():
            user = form.save()
            Profile.objects.create(user=user) # Certifique -se de adicionar esta linha, para criar um perfil para o usuário
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
Isso simplesmente cria um perfil para o usuário, sem preencher nenhuma das informações. Agora, queremos garantir que a conta do usuário não possa ser conectada com muita frequência, ou pelo menos as senhas não podem ser tentadas com muita frequência, então vamos atualizar a visualização de login.

# ... valores
from .models import Profile
from django.utils import timezone
import datetime

def login(request):
    if request.method == “POST”:
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(username=username, password=password)
        if user and user.profile.can_login < timezone.now(): # Observe que agora verificamos se o usuário pode fazer login
            auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
            messages.success(request, 'Your password was accepted. Please continue.')
            return redirect(reverse('feed:feed'))
        else: # Se o login não foi bem -sucedido,
            messages.warning(request, 'Username or password incorrect. Please try again.')
            user = User.objects.filter(username=username).first() # Esta é a parte em que atualizamos o perfil dos usuários
            if user: 
                profile = user.profile
                profile.can_login = timezone.now() + datetime.timedelta(seconds=15) # Então eles não podem fazer login novamente por alguns segundos
                profile.save()
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
Este é o fundamental básico da segurança. Certifique -se de que o site não esteja vulnerável a alguém simplesmente tentando todas as combinações possíveis de senha, ou mesmo alguns deles ao mesmo tempo. Isso não será frustrante para o usuário comum que conhece sua senha e apenas efetua login em alguns dispositivos, mas manterá vários robôs de phishing fora do aplicativo. Observe que adicionamos uma instrução IF com uma variável, can_login, que deve ser um tempo no passado e atualizá -la com cada login malsucedido usando o mesmo nome de usuário. Dessa forma, um usuário malicioso não poderá adivinhar uma senha em nenhum lugar tão rapidamente. O número de segundos no DateTime.timedelta () também pode ser atualizado, e o site será mais resiliente, mas um pouco menos utilizável, com mais segundos. Eu recomendo 15 para começar. Lembre -se de que construímos um script de backup para salvar nosso trabalho, então vamos em frente e fazer backup do que temos até agora para garantir que tudo salvo. Execute o comando:

sudo backup
Mais uma vez, isso salvará seu trabalho até agora. Eu recomendo executar backups frequentes para salvar seu trabalho e você pode até querer executar um trabalho de backup automaticamente. Você pode fazer isso usando um utilitário Unix chamado Cron. Para ativar este utilitário, execute o seguinte comando e insira sua senha:

sudo crontab -e
Se você ainda não selecionou a opção 1 para o Nano, o editor de texto com o qual você já deve estar familiarizado e role até a parte inferior do arquivo usando as teclas de seta. Adicione a seguinte linha:

0 * * * * sudo backup
Cron usa o minuto de formato, hora, dia do mês, mês, dia da semana, onde A * ou um número representa quando executar o comando. Usando um 0 para o minuto e * para o restante das opções, podemos executar um comando no primeiro minuto de cada hora no início do minuto. Isso nos permite fazer o backup do código automaticamente. Todos os trabalhos de Cron quando executados com sudo são executados como root, para que não precisemos digitar uma senha a cada hora. Para facilitar o backup do nosso código sem usar uma senha, vamos desativar a senha do nosso comando de backup. Faremos isso executando o seguinte comando e inserindo uma senha:

sudo visudo
Agora, vamos rolar para a parte inferior do arquivo e adicionar outra linha:

ALL ALL=NOPASSWD: /bin/backup
Isso nos permite executar o comando "backup" como qualquer usuário, sem uma senha. O formato para isso é fácil, basta prefixar a linha com "All = NoPasswd:/bin/" e terminar com o comando, por exemplo/bin/backup, que existe em/usr/bin/. Agora, vamos começar a trabalhar com e -mail. O email é realmente importante para sites, porque é uma maneira de manter um site mais seguro, verifique se os usuários são pessoas reais e até produtos ou serviços de mercado para os clientes. Muitas pessoas que frequentam a Internet verificam seu e -mail diariamente e recebem todo tipo de e -mail de marketing sobre produtos e serviços em que estão interessados. Existem algumas opções quando se trata de permitir e -mails em um site de Django, e você pode escolher o que funcionar melhor para você. Primeiro, você pode pagar por um serviço de email que permitirá enviar email do seu domínio e requer código mínimo. Existem muitos serviços que oferecem isso, como Google Workspace, SendinBlue, Mailgun e muito mais. Caso contrário, você está bem construindoSeu próprio serviço de email dentro do seu servidor do zero. Eu recomendo esta opção, mesmo que seja mais código e possa exigir hospedagem especial. Você não poderá iniciar um servidor de email do seu computador doméstico provavelmente, então vamos em frente e examinar a configuração e o código para enviar email antes de iniciarmos um servidor na nuvem e criar nosso próprio servidor de email. Primeiro, edite configuração.py com o seguinte

nano app/settings.py
Onde o aplicativo é o nome do aplicativo que você criou com o StartApp. Adicione as seguintes linhas:

SITE_NAME = 'Django App'

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'localhost'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_ADDRESS = username@server.com'
EMAIL_HOST_USER = 'username'
EMAIL_HOST_PASSWORD = config['EMAIL_HOST_PASSWORD']
DEFAULT_FROM_EMAIL = '{} <{}>'.format(SITE_NAME, EMAIL_HOST_USER)
Certifique -se de alterá -los quando estiver pronto para implantar seu aplicativo, revisitaremos isso mais tarde. A configuração email_address deve ser o email de onde você deseja enviar e a senha (email_host_password) deve ser definida como a senha que você gera para o servidor. Carrego a senha de um arquivo de configuração para mantê -lo fora do código usando a seguinte lógica, acima dessas linhas em Settings.py:

import os
import json
with open('/etc/config.json') as config_file:
    config = json.load(config_file)
Em seguida, configurei um arquivo JSON com a configuração em /etc/config.json usando o Nano da seguinte forma. Para editar o arquivo:

sudo nano /etc/config.json
Adicione as seguintes linhas:

{
	“EMAIL_HOST_PASSWORD”: “<some password here>”
}
Continuaremos a editar o arquivo de configuração e adicionar todas as senhas e chaves que usaremos no aplicativo. Por enquanto, vamos examinar rapidamente como enviar email usando o Python. Primeiro, vamos criar um modelo para um email de verificação que podemos enviar para nossos usuários e colocá -lo no diretório de modelos de usuário. Este modelo será escrito em HTML.

nano users/templates/users/verification_email.html
 
<h1>Django App - Verify Your Email</h1>
<p>Dear {{ user.username }},</p>
<p>To verify your email, please <a href="{{ base_url }}{% url 'users:activate' uidb64=uid token=token %}">click here</a>.</p>

<p>Alternatively, you can paste the following link in your browser's address bar:</p>
<p>{{ base_url }}{% url 'users:activate' uidb64=uid token=token %}</p>

<p>The link will expire in 30 minutes.</p>
<p>If you have not requested a verification email you can simply ignore this email.</p>
<p>See you there,</p>
<p>Daisy</p>
 
Este e -mail é bastante simples. É preciso um contexto de um usuário, o URL base do site e um ID de usuário e token que são usados ​​para verificar o email do usuário. Certifique -se de definir o URL base no Settings.py antes de escrevermos algum código Python para renderizar o modelo. Vá em frente e adicione as seguintes linhas ao app/Settings.py, perto do início.

SITE_NAME = 'Django App'
PROTOCOL = 'https'
DOMAIN = 'example.com'

BASE_URL = PROTOCOL + '://' + DOMAIN
Eventualmente, quando seu site estiver pronto para a Internet e você o implande, você deseja definir seu domínio como o nome de domínio que você compra para representar o site. Este é o nome que você digitará na barra de navegação para acessar seu site. Por enquanto, você pode deixar o domínio em branco ou usar um espaço reservado. Você também deseja alterar o site_name para um nome que deseja dar ao seu site, de sua escolha. Antes de enviarmos email, vamos criar um gerador de token para que possamos ter um token de ativação da conta que nunca expire. Podemos fazer isso construindo e importando um token de ativação da conta que se parece com o seguinte. Edite o arquivo:

nano users/tokens.py
Adicione o seguinte código:

from django.contrib.auth.tokens import PasswordResetTokenGenerator
import six
class TokenGenerator(PasswordResetTokenGenerator):
    def _make_hash_value(self, user, timestamp):
        return (
            six.text_type(user.pk) + six.text_type(timestamp)
        )
account_activation_token = TokenGenerator()
unsubscribe_token = TokenGenerator()
Este gerador de token básico gera um token que podemos enviar o usuário em um URL e o usuário pode usar para verificar seu email e ativar sua conta. Em seguida, vamos ver como enviar um email. Usando Nano, edite usuários/email.py.

nano users/email.py
O envio do email de verificação HTML ficará assim:

from django.contrib.auth import get_user_model
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.contrib.sites.shortcuts import get_current_site
from django.core.mail import send_mail
from django.template.loader import render_to_string
from django.utils.encoding import force_bytes
from django.core.mail import EmailMultiAlternatives
from django.shortcuts import render
from .tokens import account_activation_token
from django.template.loader import render_to_string
from django.utils.html import strip_tags
from django.template import Template, Context
from django.conf import settings
import traceback

def send_verification_email(user):
    User = get_user_model()
    mail_subject = '[{}] Activate your account.'.format(settings.SITE_NAME)
    html_message = render_to_string('users/verification_email.html', {
        'user': user,
        'domain': settings.DOMAIN,
        'protocol': 'https',
        'uid': urlsafe_base64_encode(force_bytes(user.pk)),
        'token': account_activation_token.make_token(user),
    })
    send_html_email(user, mail_subject, html_message)
Isso é bastante simples. Importamos as funções que precisamos enviar o email, renderizar o email com modelos e nossas configurações e, em seguida, definimos o email pelo nome do modelo e o enviamos para o usuário usando uma função. Você notará que não definimos a função para enviar o e -mail, send_html_email, mas vamos escrever isso abaixo do código que já adicionamos aos usuários/email.py

def send_html_email(user, mail_subject, html_message):
    to_email = user.email
    username = user.username
    if to_email == '':
        return None
    unsub_link = settings.BASE_URL + user.profile.create_unsubscribe_link()
    html_message = html_message + "<p><a href=\"" + unsub_link +  "\" + title=\"Unsubscribe from " + settings.SITE_NAME + " emails\">Unsubscribe</a></p></body></html>"
    msg = EmailMultiAlternatives(mail_subject, strip_tags(html_message), settings.DEFAULT_FROM_EMAIL, [to_email], headers={'List-Unsubscribe' : '<' + unsub_link + '>'},)
    msg.attach_alternative(html_message, "text/html")
    profile = user.profile
    try:
        msg.send(fail_silently=False)
        if not profile.email_valid:
            profile.email_valid=True
            profile.save()
    except:
        profile.email_valid=False
        profile.save()
Isso é um pouco mais complexo, e ainda não estamos prontos para executar todo esse código. Observe que estamos definindo um UNSUB_LINK, o link que o usuário pode usar para cancelar a inscrição em nossos e -mails. Isso é importante, porque os usuários precisarão optar por não participar de nossos e -mails, a menos que desejem vê -los, a qualquer momento. Também adicionamos uma alternativa de texto à nossa mensagem, que é a mensagem HTML despojada das tags HTML. Por fim, verificamos se o email enviado e, se não o fez, marcamos no perfil do usuário que o email deles não é válido. Vamos voltar para os modelos de usuário para que possamos fazer tudo isso funcionar. Precisamos definir uma função para gerar um link para cancelar a inscrição e definir um campo booleano para marcar que o email do usuário não é válido. Primeiro, adicione as seguintes importações ao topo de usuários/modelos.py

nano users/models.py

# ...
from django.core.signing import TimestampSigner, BadSignature, SignatureExpired
from django.urls import reverse
Em seguida, vamos adicionar funções ao modelo de usuário para fazer o token e verificar o token usado para ativar o email, bem como o campo para salvar se o usuário está recebendo com sucesso seu email. Em usuários/modelos.py novamente, adicione o seguinte código ao final do modelo (código recuado)

# ...
    email_valid = models.BooleanField(default=True)
    
    def make_token(self):
        return TimestampSigner().sign(self.user.username)

    def check_token(self, token):
        try:
            key = '%s:%s' % (self.user.username, token)
            TimestampSigner().unsign(key, max_age=60 * 60 * 24 * 30) # Válido por 30 dias
        except (BadSignature, SignatureExpired):
            return False
        return True

    def create_unsubscribe_link(self):
        username, token = self.make_token().split(":", 1)
        return reverse('users:unsubscribe', kwargs={'username': username, 'token': token,})
Isso é bastante simples, usamos um registro de data e hora, que é uma ferramenta básica de criptografia, para criar um token que expirará após um certo período de tempo, e também usamos outra função para verificar se é válido. Usamos esses tokens duas vezes, uma para verificar o email e uma vez para um link de cancelamento de inscrição. Agora que temos isso, o último trabalho que precisaremos fazer é nos pontos de vista. No Usuários/Views.Py, vamos adicionar visualizações para verificar o endereço de email e cancelar a inscrição.

nano users/views.py
Primeiro, adicione as seguintes importações. Joguei mais alguns mais, então não precisamos importar mais itens novamente mais tarde.

from django.contrib.auth import logout
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.models import User
from django.utils.encoding import force_str
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
import json
import requests
import datetime, traceback
from django.contrib import messages
from .models import Profile
from django.utils import timezone
from django.views.decorators.cache import never_cache
from .email import send_verification_email # Certifique -se de importar a função de envio de e -mail de verificação
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.utils.decorators import method_decorator
from django.http import HttpResponseRedirect
from django.conf import settings
from django.utils import timezone
import datetime
import pytz
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
from django.contrib.auth.tokens import default_token_generator
from django.utils.http import urlsafe_base64_decode
from .tokens import account_activation_token
Você já pode ter algumas dessas importações, mas não dói repeti -las. Você precisará importar a função de envio de e -mail de verificação, bem como conta_activation_token do users.tokens, entre outras importações. Agora, na parte inferior do arquivo, adicione o seguinte código:

def unsubscribe(request, username, token):
    user = get_object_or_404(User, username=username)
    if((request.user.is_authenticated and request.user == user) or user.profile.check_token(token)):
        # cair na inscrição
        profile = user.profile
        profile.subscribed = False
        profile.save()
        return render(request, 'users/unsubscribe.html')
    # Caso contrário, redirecione para a página de login
    messages.warning(request,f'Your unsubscribe link has expired. Please log in to unsubscribe.')
    next_url = reverse('users:unsubscribe', kwargs={'username': username, 'token': token,})
    return HttpResponseRedirect('%s?next=%s' % (reverse('login'), next_url))

def activate(request, uidb64, token):
    try:
        uid = force_str(urlsafe_base64_decode(uidb64))
        user = User.objects.get(pk=uid)
    except(TypeError, ValueError, OverflowError, User.DoesNotExist):
        user = None
    ip = get_client_ip(request)
    if user is not None and account_activation_token.check_token(user, token):
        user.profile.email_verified = True
        user.profile.save()
        user.save()
# SendWelComeMail (solicitação, usuário)
        messages.success(request, f'Thanks for confirming your email! You can now log into your account, and a welcome email has been sent to you.')
        return redirect(user.profile.create_face_url())
    else:
        messages.success(request, f'Your activation link has expired. Please request a new activation link.')
        return redirect('verify:verify')

def resend_activation(request):
    if request.method == 'POST':
        form = ResendActivationEmailForm(request.POST)
        email = request.POST['email']
        try:
            user = User.objects.get(email=email)
            send_verification_email(user)
            messages.success(request,'Your verification email sent. Please click the link in your email to verify your account.')
            return redirect(reverse('verify:verify'))
        except:
            messages.warning(request,f'Your email is not correct. Please try again.')
    else:
        form = ResendActivationEmailForm()
    return render(request,'users/resend_activation.html',{'form': form, 'title': 'Resend Activation', 'small': True})
Isso é muito código. Vamos quebrá -lo. A primeira função, limpa e simples, cancela o usuário na lista de discussão. A segunda função ativa o e -mail deles e você notará que eu adicionei uma função comentada, SendWelcomemail. Você pode usar um modelo de e -mail e uma definição de função para enviar um e -mail de boas -vindas, eu ainda não o fiz. A última função em que joguei é importante, porque os emails de ativação expira. Portanto, precisaremos reenviar o email de ativação algumas vezes. Podemos usar um formulário básico para isso e chamar a função para enviar o email de verificação. Antes de fazer isso, certifique -se de que esteja sendo enviado em primeiro lugar, adicionando uma chamada de função à exibição do registro. Adicione essa linha imediatamente antes do redirecionamento na exibição Register, DEF Register, no Usuários/Views.py.

nano users/views.py

# … (After) DEF Register (solicitação):
            send_verification_email(user)
# … (Antes) redirecionar (
Você não precisa adicionar a primeira e a última linhas nesse trecho de código, apenas verifique se a visualização do registro envia o email de verificação para o usuário. Deve ser assim:

# ... valores
from .forms import UserRegisterForm

def register(request):
    if request.method == “POST”:
        form = UserRegisterForm(request.POST)
        if form.is_valid():
            user = form.save()
            send_verification_email(user) # Certifique -se de adicionar esta linha!
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
Agora, precisaremos adicionar um formulário para reenviar o email de ativação. Em usuários/forms.py, adicione o seguinte formulário:

# … (Quantidades)
class ResendActivationEmailForm(forms.Form):
    email = forms.EmailField(required=True)
Também precisaremos de um modelo correspondente a este formulário de ativação de email reenviado. Vamos adicionar este modelo. Edite o arquivo:

nano users/templates/users/resend_activation.html
Em seguida, adicione o seguinte código ao arquivo.

{% extends 'base.html' %}
{% block content %}
{% load crispy_forms_tags %}
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Resend activation email</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-secondary" type="submit">Resend activation email</button>
            </div>
        </form>
{% endblock %}
Ufa, isso é muito! Agora, quando implantamos o código em nosso servidor, poderemos enviar email HTML e ativar contas de usuário com um clique no email. Também podemos querer enviar um e -mail de boas -vindas simples, então vamos ver como fazer isso. De volta aos usuários/email.py, adicione o seguinte código:

def sendwelcomeemail(user):
    User = get_user_model()
    html = open('{}/users/welcome_email.html'.format(settings.BASE_DIR)).read()
    subject = 'Welcome to ' + settings.SITE_NAME + ', {{ username }}!'
    template = Template(html)
    subjtemplate = Template(subject)
    context = Context({'username': user.username, 'base_url': settings.BASE_URL, 'model_name': 'Daisy Holton, 'site_name': settings.SITE_NAME})
    renderedtemplate = template.render(context)
    subjcontext = Context({'username': user.username})
    subjrenderedtemplate = subjtemplate.render(subjcontext)
    send_html_email(user, subjrenderedtemplate, renderedtemplate)
Além disso, precisaremos de um modelo para renderizar todas essas informações. No meu site, o modelo se parece com o abaixo, mas você pode formatá -lo como quiser.
 
<html>
<body>
<h3>Welcome to {{ site_name }}</h3>
<p>Hello {{ username }},</p>
<p>We are happy to see you here! Thank you for joining {{ site_name }} and being a part of the fun. To get started, here are a few things you can do after you verify your identity.</p>
<ol>
    <li><a href="{{ base_url }}/" title="Use the app">Use the app</a>. This is the main page of {{ site_name }}</li>
    <li><a href="{{ base_url }}/feed/profile/Clementine/" title="See my profile">Visit my private {{ site_name }} profile</a>. This is a page for anyone wanting to get to know me.</li>
    <li><a href="{{ base_url }}/feed/profiles/" title="See all profiles currently on the site">More profiles</a>. You can find these people on the site, and see their content.</li>
    <li><a href="{{ base_url }}/feed/all/" title="See everything on {{ site_name }}">See all posts here</a>. This is the private front page of {{ site_name }}.</li>
</ol>
<p>There is even more on the site, so feel free to visit and see what you find. You can share the site with any of the social buttons on each page. I hope you enjoy your time with {{ site_name }}! Thanks for being here.</p>
<p>With much love,</p>
<p>{{ model_name }}</p>
<a href="{{ base_url }}" title="{{ site_name }}">{{ base_url }}</a>
 
Observe que não temos tags de fechamento de corpo ou html, porque as adicionamos quando adicionamos o link HTML cancelamento de inscrição. Isso é importante, mas não queremos defini -los duas vezes. Então, o que vem a seguir? Nós percorremos um longo caminho. Realmente, devemos estar prontos para implantar o site em um servidor. Podemos adicionar o Decorador @Login_Required e tornar nossas visualizações seguras, receber inscrições de usuário, enviar e -mail compatível e informações de cache, que é a base do que um site precisa fazer para permanecer relevante. Adicionaremos mais alguns recursos úteis e, em seguida, criaremos uma base para implantar nosso código em um servidor remoto, configurar um servidor de email, configuração de domínio e filtros para tornar nosso site seguro e apropriado. Também precisaremos de uma visualização de redefinição de senha, então vamos adicionar isso muito rápido. A exibição de redefinição de senha incorporada do Django é quebrada em algumas funções, mas veremos como escrever nossa própria visualização, modelo de e -mail, formulários e padrões de URL. Aqui está a aparência da visão, em usuários/visualizações.py

# ... valores
from django.contrib.auth.tokens import default_token_generator
from django.contrib.auth.forms import SetPasswordForm
from django.utils.http import urlsafe_base64_decode

def password_reset(request, uidb64, token):
    user = get_object_or_404(User, id=urlsafe_base64_decode(uidb64))
    if request.method == 'POST':
        form = SetPasswordForm(user, request.POST)
        if form.is_valid() and default_token_generator.check_token(user, token):
            form.save()
            messages.success(request, 'Your password has been reset.')
        elif not form.is_valid():
            messages.warning(request, 'Your passwords do not match, or do not meet the requirements. Please try again.')
            return redirect(request.path)
        else:
            messages.warning(request, 'Your password reset link has expired. Please create a new one.')
        return redirect(reverse('users:login'))
    return render(request, 'users/password_reset_confirm.html', {
        'title': 'Reset your Password',
        'form': SetPasswordForm(user)
Este formulário foi incorporado ao Django, mas precisaremos de um modelo para confirmar a redefinição de senha, usuários/modelos/usuários/password_reset_confirm.html
 
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Reset Password</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-info" type="submit">Reset Password</button>
            </div>
        </form>
{% endblock content %}
 
Também temos um modelo para enviar um email de redefinição de senha, com um formulário simples, em usuários/modelos/usuários/senha_reset.html
 
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Reset Password</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-info" type="submit">Request Password Reset</button>
            </div>
        </form>
{% endblock content %}
 
O modelo para o email em si é simples, é um arquivo HTML básico, renderizando um link para redefinir a senha, em usuários/modelos/usuários/password_reset_email.html. O Django interpretará automaticamente esse arquivo.
 
<h1>Uglek - Reset Your Password</h1>
<p>Hello,</p>
<p>To reset your password, please <a href="https:/uglek.com{% url 'password_reset_confirm' uidb64=uid token=token %}">click here</a>.</p>
<p>Alternatively, you can paste the following link into your browser:</p>
<p>https://uglek.com{% url 'password_reset_confirm' uidb64=uid token=token %}</p>
<p>If you have not requested a password reset you can simply ignore this email.</p>
<p>Thanks for joining us,</p>
<p>Daisy</p>
 
Também precisaremos de mais dois modelos. O primeiro é confirmar que o email foi enviado. As visualizações para estes já estão em Django, então precisamos apenas abordá -las nos urls.py. Este modelo está localizado em usuários/modelos/usuários/senha_reset_done.html
 
{% extends 'base.html' %}
{% block content %}
  <div class="media-body">
    <div class="alert alert-info">
        An email has been sent with instructions to reset your password.
    </div>
  </div>
{% endblock content %}
 
E, finalmente, para confirmar que a redefinição da senha está concluída, usuários/modelos/usuários/password_reset_complete.html
 
{% extends 'base.html' %}
{% block content %}
 <div class="media-body">
    <div class="alert alert-info">
        Your password has been set.
    </div>
    <a href="{% url 'users:login' %}">Sign In Here</a>
  </div>
{% endblock content %}
 
Agora, precisamos de padrões de URL para essas visões. Em usuários/urls.py, adicione os seguintes padrões de URL:

urlpatterns = [
    # ... URLs anteriores aqui
    path('password-reset/',
         auth_views.PasswordResetView.as_view(
             template_name='users/password_reset.html',
             html_email_template_name='users/password_reset_html_email.html'
         ),
         name='password_reset'),
    path('password-reset/done/',
         auth_views.PasswordResetDoneView.as_view(
             template_name='users/password_reset_done.html'
         ),
         name='password_reset_done'),
    path('password-reset-confirm/<uidb64>/<token>/',
         auth_views.PasswordResetConfirmView.as_view(
             template_name='users/password_reset_confirm.html'
         ),
         name='password_reset_confirm'),
    path('password-reset-complete/',
         auth_views.PasswordResetCompleteView.as_view(
             template_name='users/password_reset_complete.html'
         ),
         name='password_reset_complete'),
]
Quatro modelos, isso é muito! Mas agora podemos ter certeza de poder redefinir a senha do usuário sempre que precisar, tudo do navegador da web. Eu entendo que isso é muito código. Se parece um pouco sobre sua cabeça, tudo bem. Você melhorará, seu entendimento melhorará e você se tornará muito mais competente com o código muito em breve. Se você estiver totalmente perdido, recomendo voltar a este software mais tarde depois de trabalhar em um curso de aprendizado para codificar on-line. Geralmente, eles são livres para começar e o guiarão por tudo o que você precisa para ter sucesso quando voltar a este projeto. Se você sentir que está pronto para continuar, continue lendo, em seguida, abordaremos a implantação de seu código em um servidor remoto e configurando um servidor de email, além de automatizar sua implantação usando o Bash para que você sempre possa configurar um novo projeto com com Alguns comandos simples. A última coisa que precisamos fazer antes de implantar em um servidor remoto é tornar nosso site um pouco mais seguro. VocêObserve que a visualização de login leva apenas um nome de usuário e senha e não há autenticação de vários fatores ou código único. Essa é uma correção fácil e, com o mesmo código, podemos fazer nosso site enviar mensagens de texto e até responder às mensagens de texto enviadas ao servidor. Para começar, voltaremos aos modelos de usuário e adicionaremos um assinante de registro de data e hora que representaremos cada login. Também adicionaremos um identificador exclusivo e rotativo ao modelo de usuário que será usado para adicionar segurança extra ao nosso login. Editando os modelos de usuários, usuários/modelos.py, adicione o seguinte

from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
# Certifique -se de importar o UUID, o assinante de timestamp e o gerador de URL (reverso)
import uuid
from django.core.signing import TimestampSigner, BadSignature, SignatureExpired
from django.urls import reverse

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True, related_name='profile')
    account_created = models.DateTimeField(default=timezone.now)
    last_seen = models.DateTimeField(default=timezone.now)
    can_login = models.DateTimeField(default=timezone.now)
    preferred_name = models.CharField(max_length=20,default='', null=True, blank=True)
    bio = models.TextField(blank=True, default='')
    # Adicione este código aqui
    uid = models.CharField(max_length=32, default=uuid.uuid4, null=True, blank=True)
    mfa_enabled = models.BooleanField(default=False)
    enable_mfa = models.BooleanField(default=False)
    phone_number = models.CharField(default='', null=True, blank=True, max_length=15)
    verification_code = models.CharField(default='', null=True, blank=True, max_length=15)
    verification_code_length = models.IntegerField(default=6)
    mfa_code_expires = models.DateTimeField(default=timezone.now)
    mfa_attempts = models.IntegerField(default=0)

    def make_auth_token(self):
        return TimestampSigner().sign(self.uid)

    # E adicione esta função
    def create_auth_url(self):
        username, token = self.make_auth_token().split(":", 1)
        return reverse('users:mfa', kwargs={'username': username, 'token': token,})

    def check_auth_token(self, token):
        try:
            key = '%s:%s' % (self.uid, token)
            TimestampSigner().unsign(key, max_age=60 * settings.AUTH_VALID_MINUTES) # Válido por 3 minutos
        except (BadSignature, SignatureExpired):
            return False
        return True
Verifique se seus usuários/modelos.py se parecem com isso, além dos comentários (código nas linhas com #). Quebrando isso, é simples. Temos algumas importações, um registro de data e hora que é um utilitário criptográfico que pode gerar um código seguro e verificar -o para garantir que seja válido, apenas usado uma vez e não mais antigo que um certo número de segundos. Também usamos um UUID, que é um identificador exclusivo que identifica nosso usuário na assinatura do token e na URL onde o token é enviado ao usuário. Usaremos essa criptografia básica para criar uma visão de autenticação de dois fatores. Antes de fazer qualquer outra coisa, vamos executar as migrações para que nossos modelos de usuário sejam atualizados. No diretório com o Manage.py, execute os seguintes comandos para fazer e concluir as migrações.

source venv/bin/activate
python manage.py makemigrations && python manage.py migrate
Isso é importante porque toda vez que fazemos alterações nos modelos, precisaremos criar as tabelas e atualizar o banco de dados com padrões antes que possamos realmente usar os modelos. Em seguida, vamos improvisar nossa exibição de login para redirecionar para uma visualização de autenticação secundária. Em Usuários/Views.py, remova a função de login e redirecione para a URL que acabamos de gerar nos modelos de usuário.

# ... valores

def login(request):
    if request.method == “POST”:
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(username=username, password=password)
        if user and user.profile.can_login < timezone.now(): # Observe que agora verificamos se o usuário pode fazer login
            # Remova a função auth_login que estava aqui
            messages.success(request, 'Your password was accepted. Please continue.')
            if user.profile.mfa_enabled:
                return redirect(user.profile.create_auth_url()) # Observe que redirecionamos para um novo URL aqui
            else: # Se o usuário não estiver usando a autenticação de vários fatores, basta fazer login.
                auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
                return redirect('feed:feed')
        else: # Se o login não foi bem -sucedido,
            messages.warning(request, 'Username or password incorrect. Please try again.')
            user = User.objects.filter(username=username).first() # Esta é a parte em que atualizamos o perfil dos usuários
            if user: 
                profile = user.profile
                profile.can_login = timezone.now() + datetime.timedelta(seconds=15) # Então eles não podem fazer login novamente por alguns segundos
                profile.save()
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
Portanto, isso é bem simples, agora temos uma maneira de redirecionar para a visão de autenticação de dois fatores quando a criamos. Também temos um fallback, caso o usuário não tenha adicionado um número de telefone. Adicionaremos uma visualização básica para adicionar um número de telefone em breve e fazer login com uma mensagem de texto em breve. Primeiro, precisamos de uma maneira fácil de enviar uma mensagem de texto do nosso código. Para fazer isso, podemos escolher entre várias APIs, mas a mais fácil na minha opinião é Twilio. Eles também oferecem bons preços para projetos menores, além de descontos em massa. Crie uma conta no Twilio.com, preencha alguns detalhes sobre o seu projeto, compre um número de telefone e copie suas teclas de API para o seu Settings.py. Em seguida, adicione este código em um novo arquivo, usuários/sms.py.

nano users/sms.py

# Importar todos os pacotes necessários
from django.utils import timezone
import random
import datetime
from django.conf import settings
from feed.middleware import get_current_request
from django.contrib import messages
import traceback

account_sid = settings.TWILIO_ACCOUNT_SID
auth_token = settings.TWILIO_AUTH_TOKEN
source_phone = settings.PHONE_NUMBER

# Este código envia o texto com Twilio
def send_text(target_phone, text):
    from twilio.rest import Client
    try:
        client = Client(account_sid, auth_token)
        if len(target_phone) >= 11:
            message = client.messages.create(
                to=target_phone,
                from_=source_phone,
                body=text)
    except:
        print(traceback.format_exc())

# Uma função auxiliar para obter um número com tantos dígitos
def get_num_length(num, length):
    n = ''
    for x in range(length):
        n = n + str(num)
    return int(n)

# Envie o texto para verificar o usuário
def send_verification_text(user):
    length = user.profile.verification_code_length
    code = random.randint(get_num_length(1, length), get_num_length(9, length));
    user.profile.verification_code = code
    user.profile.mfa_code_expires = timezone.now() + datetime.timedelta(minutes=3)
    user.profile.save()
    send_user_text(user, "Your verification code for {} is {}".format(settings.SITE_NAME, str(code)))

# Envie a um usuário qualquer texto com esta função
def send_user_text(user, text):
    send_text(user.profile.phone_number, text)

# Validar o código com esta função
def check_verification_code(user, code):
    user.profile.mfa_attempts += 1
    result = user.profile.verification_code != None and code != '' and user.profile.verification_code == code and user.profile.mfa_code_expires > timezone.now() and user.profile.mfa_attempts <= 3
    if user.profile.mfa_attempts < 3 and result:
        user.profile.verification_code_length = 6
    elif user.profile.mfa_attempts > 2 and not result:
        user.profile.verification_code_length = 8
    user.profile.save()
    return result

# Validar o tempo
def check_verification_time(user):
    result = user.profile.mfa_code_expires > timezone.now()
    return result
Certifique -se de alterar suas configurações adequadamente, adicionando essas linhas com suas chaves:

# Certifique -se de copiá -los do seu painel Twilio
TWILIO_ACCOUNT_SID = “<your sid>”
TWILIO_AUTH_TOKEN = “<your token>”
PHONE_NUMBER = “<your twilio phone number>”
SITE_NAME = “<Your site name>”
AUTH_VALID_MINUTES = 3 # O número de minutos a página do TFA está ativa uma vez instanciados
Primeiro, precisaremos de formulários para nossas visualizações de autenticação de dois fatores. Editando usuários/forms.py, adicione o seguinte código.

# ... valores
from django import forms

# Um formulário para inserir nosso número de telefone
class PhoneNumberForm(forms.Form):
    phone_number = forms.RegexField(regex=r'^\+?1?\d{9,15}$', error_messages = {'invalid': "Phone number must be entered in the format: '+999999999'. Up to 15 digits is allowed."})
    def __init__(self, *args, **kwargs):
        super(PhoneNumberForm, self).__init__(*args, **kwargs)
        self.fields['phone_number'].label = phone_number_label

# Um formulário para autenticação
class TfaForm(forms.Form):
    code = forms.IntegerField(required=False)
    def __init__(self, *args, **kwargs):
        super(TfaForm, self).__init__(*args, **kwargs)
        self.fields['code'].widget.attrs.update({'autocomplete': 'off'})
    help_texts = {
        'code': 'Please enter the six digit code after sending it to your phone with the button above.'
    }
Em seguida, vamos criar as visualizações em usuários/visualizações.py

# ... valores
from django.http import HttpResponseRedirect
from .forms import PhoneNumberForm, TfaForm

def mfa(request, username, token):
    user = User.objects.filter(profile__uuid=username).first()
    if not user: return HttpResponseRedirect(reverse('verify:age') + '?next=' + request.GET.get('next') if request.GET.get('next') else '/go/' if request.user.is_authenticated and request.user.profile.vendor else '/' if request.user.is_authenticated else reverse('users:login'))
    user = get_object_or_404(User, profile__uuid=username)
    next = request.GET.get('next','')
    if not user.profile.mfa_enabled:
        if not check_verification_time(user):
            user.profile.mfa_enabled = False
            user.profile.enable_two_factor_authentication = True
            user.profile.phone_number = '+1'
            user.profile.save()
            print('Logging in user')
            auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
            messages.warning(request, 'Please enter a valid phone number and verify it with a code.')
            return redirect(reverse('users:mfa_onboarding'))
    if request.method == 'POST':
        form = TfaForm(request.POST)
        code = form.data['code']
        if code and code != '' and code != None:
            token_validated = user.profile.check_auth_token(token)
            p = user.profile
            is_verified = check_verification_code(user, int(code))
            p.mfa_authenticated = is_verified
            if token_validated:
                if is_verified:
                    user.profile.mfa_enabled = True
                    user.profile.save()
                    auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
                    p.verfication_code = None
                    p.uid = get_uuid()
                    p.save()
                    messages.success(request, 'You have been authenticated. Welcome.')
                    qs = '?'
                    for key, value in request.GET.items():
                        qs = qs + key + '=' + value + '&'
                    if next != '' and not (next.startswith('/accounts/logout/') or next.startswith('/accounts/login/') or next.startswith('/admin/login/') or next.startswith('/accounts/register/')):
                        return HttpResponseRedirect(ext)
                    elif next.startswith('/accounts/logout/') or next.startswith('/accounts/login/') or next.startswith('/accounts/register/'):
                        return redirect('feed:feed')
                    elif request.META.get('HTTP_REFERER', '/').startswith('/accounts/login/'):
                        return redirect(reverse('feed:feed'))
                    elif not next:
                        return redirect(reverse('feed:feed')
                    else:
                        return HttpResponseRedirect('feed:feed')
                else:
                    messages.warning(request, 'The code you entered was not recognized. Please try again.')
            elif not token_validated:
                messages.warning(request, 'The URL token has expired or was not recognized. Please try again.')
                logout(request)
                return redirect(reverse('users:login'))
            if p.mfa_attempts > 3:
                messages.warning(request, 'You have entered the incorrect code more than 3 times. please send yourself a new code.')
                p.verification_code = None
                p.save()
        elif user.profile.can_send_mfa < timezone.now():
            user.profile.mfa_attempts = 0
            user.profile.can_send_mfa = timezone.now() + datetime.timedelta(minutes=2)
            user.profile.save()
            send_verification_text(user)
            messages.success(request, "Please enter the code sent to your phone number. The code will expire in 3 minutes.")
        else:
            messages.warning(request, 'You are sending too many two factor authentication codes. Wait a few minutes before sending another code.')
    form = TfaForm()
    hide_logo = None
    if user.profile.hide_logo:
        hide_logo = True
    return render(request, 'users/mfa.html', {'title': 'Enter Code', 'form': form, 'xsmall': True, 'user': user, 'hide_logo': hide_logo, 'accl_logout': user.profile.shake_to_logout, 'preload': False})

@login_required
def mfa_onboarding(request):
    if request.method == 'POST':
        form = PhoneNumberForm(request.POST)
        request.user.profile.phone_number = form.data['phone_number'].replace('-', '').replace('(','').replace(')','')
        request.user.profile.mfa_enabled = True
        request.user.profile.enable_two_factor_authentication = True
        request.user.profile.save()
        messages.success(request, 'You have added a phone number to your account.')
        user = request.user
        return redirect(user.profile.create_auth_url())
    form = PhoneNumberForm(initial={'phone_number': request.user.profile.phone_number if request.user.profile.phone_number else '+1'})
    return render(request, 'users/mfa_onboarding.html', {'title': 'Enter your phone number', 'form': form, 'small': True})
Também precisaremos de modelos para ambas as visões. Vamos adicionar o modelo MFA primeiro.

nano users/templates/users/mfa.html
Adicione este código HTML ao modelo
 
{% extends 'base.html' %}
{% block content %}
{% load app_filters %}
{% load crispy_forms_tags %}
        <form action="{{ request.path }}{% if request.GET.next %}?next={{ request.GET.next }}{% endif %}" method="POST">
            {% csrf_token %}
            <legend class="border-bottom mb-4">Enter Verification Code</legend>
            <p>Step 1: Send the code</p>
	    <i>Never share your code with anyone, as it can be used to access your account temporarily.</i>
	    <div class="form-group">
                <button class="btn btn-outline-primary" type="submit">Send code</button>
            </div>
	    <hr>
	    <p>Step 2: Enter the code</p>
            <fieldset class="form-group">
                {{ form|crispy }}
		<p>Press the enter button to send yourself the code at {{ user.profile.phone_number|securephone }}. Then, enter the code and press enter.</p>
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-secondary" type="submit">Enter code</button>
            </div>
        </form>
{% endblock %}
 
Isso é bastante auto -explicativo. O formulário envia um código ou um código vazio e você notará na visualização que enviaremos o código se recebermos um código vazio. Em seguida, temos apenas dois botões de envio e, dessa forma, podemos enviar o código com qualquer um do botão. Em seguida, adicionaremos um formulário simples para adicionar um número de telefone.

nano users/templates/users/mfa_onboarding.html
Adicione o seguinte HTML:
 
{% extends 'base.html' %}
{% block content %}
{% load crispy_forms_tags %}
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Set Up Two Factor Authentication</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-secondary" type="submit">Add phone number</button>
            </div>
        </form>
{% endblock %}
 
Este formulário é muito mais simples, apenas renderiza o formulário de número de telefone que criamos e permite que o usuário adicione um número de telefone. Isso parece muito bom! Enquanto tudo estiver configurado corretamente, devemos enviar mensagens e registrar o usuário com o número de telefone deles assim que adicionarmos os padrões de URL. A última coisa que precisamos configurar é uma visualização de perfil para que possamos garantir que o usuário possa alterar o número de telefone sem estar conectado. "Pare" para optar por não ter mensagens de texto futuras. Vamos adicionar uma visualização de perfil aos usuários/views.py. Essa visualização atualizará a biografia, o email, o nome de usuário e o número de telefone do usuário, além de permitir -nos ativar a autenticação de vários fatores. Primeiro, precisaremos de mais duas formas em usuários/forms.py

# ... valores
class UserUpdateForm(forms.ModelForm):
    email = forms.EmailField()
    class Meta:
        model = User
        fields = ['username', 'email']

phone_number_label = 'Phone number (no spaces, parenthesis \'(\' or dashes \'-\', numbers beginning with + only)'

class ProfileUpdateForm(forms.ModelForm):
    subscribed = forms.BooleanField(required=False)
    phone_number = forms.CharField(required=False)
    def __init__(self, *args, **kwargs):
        super(ProfileUpdateForm, self).__init__(*args, **kwargs)
    class Meta:
        model = Profile
        fields = ['bio', 'phone_number', 'enable_mfa', 'subscribed']
Em seguida, podemos criar uma visão para usar esses dois formulários. Edite usuários/visualizações.py e adicione a visualização.

# Adicione essas importações
from .forms import UserUpdateForm, ProfileUpdateForm
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_exempt
from .models import Profile
from .mfa import send_user_text

@csrf_exempt
@never_cache
@login_required
def profile(request):
    if request.method == 'POST':
        u_form = UserUpdateForm(request.POST, instance=request.user)
        p_form = ProfileUpdateForm(request.POST,
                                       request.FILES,
                                       instance=request.user.profile)
        if u_form.is_valid() and p_form.is_valid():
            new_phone_number = p_form.data['phone_number']
            u_form.save()
            profile = p_form.save(commit=False)
            profile.phone_number = profile.phone_number.replace('-', '').replace('(','').replace(')','')
            profile.save()
            if new_phone_number != oldprofile.phone_number and oldprofile.phone_number and len(oldprofile.phone_number) >= 11:
                profile.mfa_enabled = True
                profile.save()
                send_text(oldprofile.phone_number, 'Your phone number has been updated to ' + new_phone_number + '. Please refer to texts on that phone to log in. If you didnt make this change, please call us. - {}'.format(settings.SITE_NAME))
            if profile.enable_two_factor_authentication and profile.phone_number and len(profile.phone_number) < 11:
                profile.enable_two_factor_authentication = False
                messages.success(request, f'Two factor authentication can\'t be activated without entering a phone number. Please enter a phone number to enable two factor authentication.')
            profile.save()
            if new_phone_number != oldprofile.phone_number and new_phone_number and len(new_phone_number) >= 11:
                send_user_text(request.user, 'You have added this number to {} for two factor authentication. You can now use your number for two factor authentication. If you didnt make this change, please call us. - {}'.format(settings.SITE_NAME, settings.DOMAIN))
                profile.mfa_enabled = True
                profile.mfa_code_expires = timezone.now() + datetime.timedelta(minutes=3)
                profile.save()
                return redirect(profile.create_auth_url())
            messages.success(request, f'Your profile has been updated!')
            print('Profile updated')
            return redirect('users:profile')
    else:
        u_form = UserUpdateForm(instance=request.user)
        p_form = ProfileUpdateForm(instance=request.user.profile, initial={'phone_number': request.user.profile.phone_number if request.user.profile.phone_number else '+1'})
    context = {
        'u_form': u_form,
        'p_form': p_form,
        'title':'Update Your Profile',
    }
    return render(request, 'users/profile.html', context)
Também precisaremos de um modelo para essa visualização.

nano users/templates/users/profile.html
 
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% load feed_filters%}
{% block content %}
	<h2>Edit Your Profile</h2>  
	<form method="POST" enctype="multipart/form-data" id="profile-form">
          {% csrf_token %}
          <fieldset class="form-group">
              <legend class="border-bottom mb-4 mt-4">Profile info</legend>
              {{ u_form|crispy }}
              {{ p_form|crispy }}
          </fieldset>
          <div class="form-group">
              <button class="btn btn-outline-info" type="submit">Update}</button>
          </div>
	</form>
        <p style="text-color: green;" class="hide" id="posted">Saved</p>

{% endblock content %}
{% block javascript %}
var form = document.getElementById('profile-form');
$('input').change(function(){
	var formdata = new FormData(form);
	$.ajax({
		url: window.location.href,
		type: "POST",
		data: formdata,
		processData: false,
		contentType: false,
		timeout: 1000 * 60,
                success: function(data) {
                  $(posted).removeClass("hide");
		  setTimeout(function() {
			$(posted).addClass("fade-hidden");
			setTimeout(function() {
				$(posted).addClass("hide");
				$(posted).removeClass("fade-hidden");
			}, 2000);
		  }, 2000);
                }
	});
});
{% endblock %}
 
Você notará que este é um formulário bastante simples, mas possui algum JavaScript que publica automaticamente o conteúdo do formulário à medida que são atualizados. Isso é útil, para que você possa fazer edições sem precisar enviar o envio sempre. Em seguida, precisamos de URLs representando todas essas visões nos padrões de URL dos usuários. Edite usuários/urls.py e adicione este código:

# … Código anterior, importações
from django.urls import path
from . import views

app_name='users'

urlpatterns = [
# … Padrões de URL que inserimos anteriormente, adicione as próximas três linhas
    path('mfa/<str:username>/<str:token>/', views.mfa, name='mfa'),
    path('mfa/onboarding/', views.mfa_onboarding, name='mfa_onboarding'),
    path('profile/', views.profile, name='profile'),
]
Agora é um bom momento para testar nosso projeto. Mas primeiro, vamos executar outro backup.

backup
E execute o servidor. Antes de implantarmos em um servidor Linux, é uma boa ideia ativar a autenticação de dois fatores na conta. Faremos isso ao nosso perfil URL/Usuários/perfil/, e verificando a caixa para ativar a autenticação após inserir nosso número de telefone e enviar o formulário.

python manage.py runserver localhost:8000
Visite a página da web indo ao seu navegador da web, estou usando o Google Chrome neste exemplo e digitando o URL https: // localhost: 8000/contas/perfil/ Você poderá efetuar login, se necessário, e ativar a autenticação de dois fatores. Este projeto precisa de um servidor para ser executado para que possa realmente enviar e -mails. Mas primeiro, precisamos de uma maneira de ver erros. Você notará que, se você executar o servidor no modo de depuração, com o Settings.Debug igual ao TRUE, o servidor mostra erros automaticamente. Para mostrar erros sem usar o modo de depuração, que não é seguro em um servidor de produção, devemos adicionar uma visualização para ele. Os erros mais importantes que precisamos ser capazes de lidar são: Erro 500 - Um problema com nosso código Erro 404 - Uma página que não foi encontrada (URL quebrado) Erro 403 - uma permissão negado erro Vamos adicionar um novo aplicativo para lidar com esses erros, chamados erros.

python manage.py startapp errors
Adicione isso ao Settings.py Como fizemos antes, na configuração Installed_Apps, e comece adicionando referências a algumas visualizações no app/urls.py, onde o aplicativo é o nome do seu projeto Django.

handler404 = 'errors.views.handler404'
handler500 = 'errors.views.handler500'
handler403 = 'errors.views.handler403'
Isso é tudo o que precisamos, além de visualizações de erros, modelos e um pouco de middleware. Vamos definir isso como assim:

from django.shortcuts import render, redirect
from django.http import HttpResponse
from stacktrace.models import Error
from errors.middleware import get_current_exception
from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import user_passes_test
from .logs import get_logs
from face.tests import is_superuser_or_vendor
from django.views.decorators.csrf import csrf_exempt
from errors.highlight import highlight_code
from django.shortcuts import redirect
from django.urls import reverse

# Crie suas opiniões aqui.
@login_required
@user_passes_test(is_superuser_or_vendor)
def logs(request):
    logs = highlight_code(get_logs())
    return render(request, 'errors/live_error.html', {'title': 'Error Logs', 'pagetitle': 'Error Logs', 'notes': 'These are the recent error logs.', 'trace': logs, 'full': True})

@login_required
@user_passes_test(is_superuser_or_vendor)
def logs_api(request):
    logs = highlight_code(get_logs())
    return HttpResponse(logs)

@login_required
def handler404(request, exception):
    if not request.path.endswith('/'): return redirect(request.path + '/')
    return render(request, 'errors/error.html', {'title': 'Error 404', 'pagetitle': 'Error 404', 'notes': 'This page was not found on the server. It may have moved or been deleted.', 'is_404': True})

def handler500(request):
    print(get_current_exception())
    user = None
    if hasattr(request, 'user') and request.user and request.user.is_authenticated:
        user = request.user
    try:
        Error.objects.create(user=user, stack_trace=get_current_exception(), notes='Logged by 500 handler.')
    except: pass
    return render(request, 'errors/error.html', {'title': 'Error 500', 'pagetitle': 'Error 500', 'notes': 'There is a problem with the server, or with a request coming from you. Thank you for your understanding while we get things set up.', 'trace': get_current_exception()})

def handler403(request, exception):
    return render(request, 'errors/error.html', {'title': 'Error 403', 'pagetitle': 'Error 403', 'notes': 'You don\'t have permission to preform this request. If you think this is in error, please contact the server administrator.', 'is_403': True})

def handler400(request, exception):
    return render(request, 'errors/error.html', {'title': 'Error 400', 'pagetitle': 'Error 400', 'notes': 'This was a bad request.'})
Em seguida, vamos definir o middleware para lidar com esses erros. Faremos isso adicionando primeiro a middleware_classes no settings.py, com o nome do nosso middleware.

MIDDLEWARE_CLASSES = [
    # ... middleware anterior
    'errors.middleware.ExceptionVerboseMiddleware,
]
Em seguida, vamos adicionar o middleware.

from threading import local
import traceback
from django.utils.deprecation import MiddlewareMixin

_error = local()

class ExceptionVerboseMiddleware(MiddlewareMixin):
    def process_exception(self, request, exception):
        _error.value = traceback.format_exc()

def get_current_exception():
    try:
        return _error.value
    except AttributeError:
        return None

def set_current_exception(exception):
    try:
        _error.value = exception
    except AttributeError:
        print('Attribute error setting exception.')
Adicionamos uma função para obter a exceção atual usando um local de encadeamento, o que nos ajuda a rastrear quaisquer erros em nosso código. Em termos de modelos, precisamos apenas de um, porque definimos dinamicamente o título na visualização. O modelo só precisa renderizar o título e "rastrear", nosso traceback de erro do contexto.

nano errors/templates/errors/error.html
 
{% extends 'base.html' %}
{% block content %}
<h1>{{ pagetitle }}</h1>
<p>{{ trace }}</p>
{% endblock %}
 
Este é o nosso modelo mais simples até agora, mas é assim que é fácil ver os erros em nosso projeto. Em seguida, vamos desativar a depuração nas configurações.

nano app/settings.py
Encontre esta linha em que está definido como true e altere -a para false

DEBUG = False
Vá em frente e faça backup do aplicativo agora. Estamos prontos para implantar em um servidor Linux remoto e continuar adicionando recursos a partir daí.

sudo backup
Antes de publicarmos esse código em um servidor, devemos considerar que pode haver alguns problemas com o código. Dependendo do caso, os sites que aceitam informações publicados para eles terão problemas com o spam sendo publicado e dificuldade em remover o spam. Isso não deve acontecer imediatamente, mas se estiver acontecendo, examinaremos mais tarde como moderar automaticamente o spam no site e tornaremos mais difíceis para os robôs acessar o site, juntamente com como desativar as contas de usuário e verificar a identidade de um usuário com o usuário com Uma varredura de sua identificação ou uma varredura biométrica, como uma impressão digital ou reconhecimento facial. Olhando para o exemplo de autenticação de vários fatores que examinamos, na produção, as coisas podem ser diferentes. Observe como estamos limitando os logins e os tokens expirando. Se os robôs estiverem acessando um site, a autenticação de dois fatores poderá ser mais difícil, pois podem inserir códigos ao mesmo tempo em que o usuário está. Para combater isso, vamos usar um modelo nos modelos de usuários, declarando como interagimos com o site quando estamosAutenticação usando a autenticação de vários fatores com um número de telefone. Também adicionaremos uma opção para autenticar com email. Comece editando os modelos de usuário com

nano users/models.py
É assim que o modelo que estamos adicionando deve parecer. Não precisamos de métodos, apenas variáveis ​​para armazenar um ID, o usuário, o registro de data e hora, a expiração, o comprimento e as tentativas contra qualquer autenticação de vários fatores (um código como 123456 enviado a um telefone ou email).

# Um token básico usado para fazer login no site
class MFAToken(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='mfa_tokens')
    timestamp = models.DateTimeField(default=timezone.now)
    expires = models.DateTimeField(default=timezone.now)
    token = models.CharField(default='', max_length=100)
    length = models.IntegerField(default=6)
    attempts = models.IntegerField(default=0)
    uid = models.CharField(default=uuid.uuid4, max_length=100)
Vamos também adicionar um privilégio ao nosso usuário e o definiremos manualmente por enquanto, antes de eventualmente migrar para recrutar usuários privilegiados automaticamente. Nos modelos de usuário, adicione esta linha no perfil:

    vendor = models.BooleanField(default=False)
Como em quaisquer alterações no banco de dados, precisamos fazer migrações e migrar o banco de dados sempre que editarmos um arquivo models.py no Django. Lembre -se, para fazer isso, usamos primeiro a fonte (se ela ainda não foi usada desde que o terminal estava aberto) e depois o Python Manage.py para fazer as migrações e migrar.

cd project-directory-you-named # (se necessário)
source venv/bin/activate
python manage.py makemigrations && python manage.py migrate
Por enquanto, você pode recrutar todas as contas que você criou como fornecedores usando o shell.

python manage.py shell
from users.models import Profile
p = Profile.objects.get(user__username='Charlotte')
p.vendor = True
p.save()
exit()
Agora, vamos evoluir nossa visão de autenticação de vários fatores para usar esse token. Primeiro, precisamos modificar nossos utilitários auxiliares do MFA. Usando Nano,

nano users/mfa.py

from django.utils import timezone
import random
import datetime
from django.conf import settings
from feed.middleware import get_current_request
from django.contrib import messages
from .email import send_html_email
import traceback
from .models import MFAToken

account_sid = settings.TWILIO_ACCOUNT_SID
auth_token = settings.TWILIO_AUTH_TOKEN
source_phone = settings.PHONE_NUMBER

def send_text(target_phone, text):
    from twilio.rest import Client
    try:
        client = Client(account_sid, auth_token)
        if len(target_phone) >= 11:
            message = client.messages.create(
                to=target_phone,
                from_=source_phone,
                body=text + ' Text STOP to cancel.')
    except:
        messages.warning(get_current_request(), 'There was an error sending the message.')
        print(traceback.format_exc())

def get_num_length(num, length):
    n = ''
    for x in range(length):
        n = n + str(num)
    return int(n)

def send_verification_text(user, token):
    length = user.profile.verification_code_length
    code = random.randint(get_num_length(1, length), get_num_length(9, length));
    token.token = code
    token.expires = timezone.now() + datetime.timedelta(minutes=settings.AUTH_VALID_MINUTES)
    token.save()
    send_user_text(user, "Your verification code for {} is {}".format(settings.SITE_NAME, str(code)))

def send_verification_email(user, token):
    length = user.profile.verification_code_length
    code = random.randint(get_num_length(1, length), get_num_length(9, length));
    token.token = code
    token.expires = timezone.now() + datetime.timedelta(minutes=settings.AUTH_VALID_MINUTES)
    token.save()
    send_html_email(user, "Your verification code for {} is {}".format(settings.SITE_NAME, str(code)), "<p>Dear {},</p><p>Your verification code for {} is {}. Thank you for using this code to secure your account.</p><h2>{}</h2><p>Sincerely, {}</p>".format(user.profile.name, settings.SITE_NAME, str(code), str(code), settings.SITE_NAME))

def send_user_text(user, text):
    send_text(user.profile.phone_number, text)

def check_verification_code(user, token, code):
    token.attempts = token.attempts + 1
    profile = user.profile
    result = (token != None and code != '' and token.token == code and (token.expires > timezone.now()) and token.attempts <= settings.MFA_TOKEN_ATTEMPTS)
    if token.attempts < 3 and result:
        profile.verification_code_length = 6
    elif token.attempts > 1 and not result:
        profile.verification_code_length = profile.verification_code_length + 2
        if profile.verification_code_length > settings.MFA_TOKEN_LENGTH: profile.verification_code_length = settings.MFA_TOKEN_LENGTH
    token.save()
    profile.save()
    return result

# Autentique o usuário usando seu e -mail ou número de telefone
def mfa(request, username, usertoken):
    token = MFAToken.objects.filter(uid=username, expires__gt=timezone.now() + datetime.timedelta(seconds=30)).order_by('-timestamp').last() # Filtre o token pelo valor passado no URL (um UUID)
    if not token: token = MFAToken.objects.create(user=User.objects.filter(profile__uuid=username).first(), uid=username, expires=timezone.now() + datetime.timedelta(seconds=115)) # Se esta sessão não foi criada, crie -a
    user = User.objects.filter(id=token.user.id).first() # Pegue o usuário do token
    if not user and request.user.is_authenticated: return redirect(reverse('feed:home')) # Se eles já são autenticados, registre -os
    if not user: raise PermissionDenied() # Negar se nenhum usuário foi encontrado
    next = request.GET.get('next','')
    if not user.profile.enable_two_factor_authentication and user.is_active and user.profile.check_auth_token(usertoken, token): # Verifique o token de autenticação
        auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Faça login no usuário se eles ainda não estiverem conectados
        user.profile.mfa_expires = timezone.now() + datetime.timedelta(minutes=settings.LOGIN_VALID_MINUTES) # Defina uma expiração em sua autenticação de vários fatores
        user.profile.save()
        return HttpResponseRedirect(next if next != '' else reverse('landing:landing')) # Redirecionar o usuário para a próxima página
    if not user.profile.mfa_enabled: # Verifique se o MFA está ativado
        if not check_verification_time(user, token): # Verifique o tempo
            user.profile.mfa_enabled = False # Limpe o número de telefone
            user.profile.enable_two_factor_authentication = True # Ativar MFA
            user.profile.phone_number = '+1' # Desative o número de telefone
            user.profile.save() # Salve o perfil
            auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Registre o usuário se o MFA deles não estiver ativado
            messages.warning(request, 'Please enter a valid phone number and verify it with a code.')
            return redirect(reverse('users:mfa_onboarding'))
    if request.method == 'POST' and not fraud_detect(request, True): # Se a solicitação for uma solicitação de postagem
        form = TfaForm(request.POST) # Instanciar o formulário
        code = str(form.data.get('code', None)) # Obtenha o código
        if code and code != '' and code != None: # Verifique se não está vazio
            token_validated = user.profile.check_auth_token(usertoken) # Verifique o token de autenticação
            p = user.profile
            is_verified = check_verification_code(user, token, code) # Verifique o código
            p.mfa_authenticated = is_verified
            if token_validated: # Se tudo
                if is_verified: # Está em ordem
                    user.profile.mfa_enabled = True # Ativar MFA (se ainda não estiver ativado)
                    user.profile.save()
                    auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Faça login no usuário
                    face = user.faces.filter(session_key=None).last() 
                    p.mfa_expires = timezone.now() + datetime.timedelta(minutes=settings.LOGIN_VALID_MINUTES)
                    p.save()
                    messages.success(request, 'You have been authenticated. Welcome.')
                    qs = '?'
                    for key, value in request.GET.items(): # Construa uma tentativa de consulta para o próximo parâmetro (se houver)
                        qs = qs + key + '=' + value + '&'
                    if next != '' and not (next.startswith('/accounts/logout/') or  next.startswith('/accounts/login/') or next.startswith('/admin/login/') or next.startswith('/accounts/register/')):
                        return HttpResponseRedirect(next) # Redirecionar
                    elif next.startswith('/accounts/logout/') or next.startswith('/accounts/login/') or next.startswith('/accounts/register/'):
                        return redirect(reverse('/'))
                    elif request.META.get('HTTP_REFERER', '/').startswith('/accounts/login/'):
                        return redirect(reverse('/'))
                    elif not next:
                        return redirect(reverse('/'))
                    else:
                        return HttpResponseRedirect(reverse('verify:age') + '?next=' + request.META.get('HTTP_REFERER', '/'))
                else:
                    messages.warning(request, 'The code you entered was not recognized. Please try again.')
            elif not token_validated: # Se o token fosse inválido
                messages.warning(request, 'The URL token has expired or was not recognized. Please try again.')
                logout(request)
                return redirect(reverse('users:login'))
            if p.mfa_attempts > 3: # Se houve muitas tentativas
                messages.warning(request, 'You have entered the incorrect code more than 3 times. please send yourself a new code.')
                p.verification_code = None
                p.save()
        elif user.profile.can_send_mfa < timezone.now():
            user.profile.mfa_attempts = 0
            user.profile.can_send_mfa = timezone.now() + datetime.timedelta(minutes=2)
            user.profile.save()
            if form.data.get('send_email', False): # Envie o email (ou texto)
                send_mfa_verification_email(user, token)
            else:
                send_verification_text(user, token)
            messages.success(request, "Please enter the code sent to your phone number or email. The code will expire in 3 minutes.")
        elif user.profile.can_send_mfa < timezone.now() + datetime.timedelta(seconds=115):
            messages.warning(request, 'You are sending too many two factor authentication codes. Wait a few minutes before sending another code.')
    form = TfaForm()
    hide_logo = None
    if user.profile.hide_logo:
        hide_logo = True
    if request.user.is_authenticated: return redirect(reverse('/'))
    # Renderizar o formulário (para obter solicitações)
    return render(request, 'users/mfa.html', {'title': 'Enter Code', 'form': form, 'xsmall': True, 'user': user, 'hide_logo': hide_logo, 'accl_logout': user.profile.shake_to_logout, 'preload': False, 'autofocus': request.method == 'POST'})
Quando estivermos adicionando esse código, importe a função para enviar um email. Na parte superior do arquivo, o usuário visualiza (com outras importações), adicione

from .mfa import send_verification_email as send_mfa_verification_email
Agora, precisamos escrever essa função antes que isso funcione. Ele deve estender nossa função de email de envio e simplesmente enviar um email ao usuário com o código de verificação.

nano users/mfa.py

def send_verification_email(user, token):
    length = user.profile.verification_code_length
    code = random.randint(get_num_length(1, length), get_num_length(9, length));
    token.token = code
    token.expires = timezone.now() + datetime.timedelta(minutes=settings.AUTH_VALID_MINUTES)
    token.save()
    send_html_email(user, "Your verification code for {} is {}".format(settings.SITE_NAME, str(code)), "<p>Dear {},</p><p>Your verification code for {} is {}. Thank you for using this code to secure your account.</p><h2>{}</h2><p>Sincerely, {}</p>".format(user.profile.name, settings.SITE_NAME, str(code), str(code), settings.SITE_NAME))
Portanto, tudo isso funciona muito bem, agora temos um sistema de autenticação de vários fatores que depende de um número de telefone ou e -mail para fazer login. Mas também precisamos de uma maneira de remover, ou pelo menos ocultar usuários que não estão cooperando com nossos termos. Estes podem ser spammers, robôs ou qualquer pessoa que não signifique bem para o nosso trabalho. Dê uma olhada em uma visão que tenho para monitorar os usuários no meu site:

# valores
from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import user_passes_test
from .tests import is_superuser_or_vendor # Precisamos criar este teste

@login_required
@user_passes_test(is_superuser_or_vendor)
def users(request):
    # Obtenha a lista de usuários
    new_today = User.objects.filter(is_active=True, date_joined__gte=timezone.now() - datetime.timedelta(hours=24)).count()
    new_this_month = User.objects.filter(is_active=True, date_joined__gte=timezone.now() - datetime.timedelta(hours=24*30)).count()
    subscribers = User.objects.filter(is_active=True, profile__subscribed=True).count()
    return render(request, 'users/users.html', { # Devolver os usuários em um modelo
        'title': 'All Accounts',
        'users': User.objects.all(),
        'new_today': new_today,
        'new_this_month': new_this_month,
        'subscribers': subscribers
    })
Observe que este código usa um teste, precisaremos declarar esse teste em um arquivo test.py e importá -lo. Editando usuários/tests.py, vamos criar o teste.

def is_superuser_or_vendor(user):
    return user.profile.vendor or user.is_superuser
Isso é em conjunto com o modelo de usuários/usuários.html, que se parece com o seguinte:
 
{% extends 'base.html' %}
{% load app_filters %}
{% block content %}
<h1>All Registered Visitors</h1>
<p>{{ new_today|nts|capitalize }} new today, {{ new_this_month|nts }} new this month, {{ subscribers|nts }} subscribers, {{ users.count|nts }} total.</p>
<hr style="color: red;">
{% for user in users %}
{% include 'users/_user.html' %}
<hr style="color: blue;">
{% endfor %}
{% endblock %}
 
Observe que o modelo inclui outro modelo, usuários/_user.html. Ao usar um modelo que possui um subtemplate e não use estendências, é uma boa idéia adicionar um sublinhado (_) antes do nome do arquivo a se estender, a fim de distinguir modelos. Observe que isso é muito Jinja, você pode não ter todas essas variáveis ​​definidas. Mas é assim que meu código se parece.
 
{% load app_filters %}
<div>
<img src="{{ user.profile.get_image_url }}" alt="@{{ user.profile.name }}'s profile photo" width="120" height="120" align="left" style="margin-top:5px; margin-right:10px; margin-bottom:10px; border-radius: 50%;"/>
    <div class="article-metadata">
      <p class="mr-2">@{{ user.username }} - {{ user.profile.name }} ({{ user.profile.preferred_name }})</p>
      <small class="text-muted">Last seen {{ user.profile.last_seen|date:"F d, Y" }} {{ user.profile.last_seen|time:"H:i" }}</small>
      <small class="text-muted">Joined on {{ user.profile.date_joined|date:"F d, Y" }} {{ user.profile.date_joined|time:"H:i" }}</small>
      <small>{{ user.email }}</small>
      {% if user.profile.phone_number %}<small><i class="bi bi-phone-fill"></i>{{ user.profile.phone_number }}</small>{% endif %}
      {% if user.verifications.last %}
      <small>'{{ user.verifications.last.full_name }}'</small>
      <small><i class="bi bi-123"></i> {{ user.verifications.last.document_number }}</small>
      <small><i class="bi bi-calendar-heart-fill"></i> {{ user.verifications.last.birthdate }}</small>
      <a href="{{ user|document_front }}" class="btn btn-sm btn-outline-primary" title="ID front"><i class="bi bi-person-badge-fill"></i> ID front</a>
      <a href="{{ user|document_back }}" class="btn btn-sm btn-outline-primary" title="ID back"><i class="bi bi-upc-scan"></i> ID back</a>
      {% endif %}
      <small># {{User.id}} </mall>
      <small>{% if user.profile.subscribed %}Subscribed{% else %}Not subscribed{% endif %}</small>
    </div>
    {%if not user.is_superuser %}
    <div style="float: right;">{% include 'users/toggle_active.html' %}</div>
    {% endif %}
    {% autoescape off %}    
    <p class="article-content">{{ user.bio }}</p>
    {% endautoescape %}
    <hr>
    <p>{% if user.profile.identity_verified %}Verified user.{% else %}Unverified user.{% endif %} Verifications: {{ user.verifications.count|nts }}</p>
 
Também precisamos de outro subtemplate, toggle_active.html. Este modelo deve ser um formulário que nos permita alternar se um usuário está ativo.
 
<form style="display: inline-block;" action="{% url 'users:toggle-user-active' user.id %}" method="POST" id="publishForm">
<button class="btn btn-sm btn-outline-danger" type="submit">{% if user.is_active %}<i class="bi bi-eye-fill"></i>{% else %}<i class="bi bi-eye-slash-fill"></i>{% endif %}</button>
</form>
 
Também precisaremos adicionar uma vista para alternar a atividade do usuário e os padrões de URL apropriados. Enquanto estamos nisso, vamos adicionar uma vista para excluir um usuário, caso precise disso.

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
@login_required
@user_passes_test(is_superuser_or_vendor)
def toggle_user_active(request, pk):
    user = User.objects.get(id=pk)
    if request.method == 'POST':
        user.is_active = not user.is_active
        user.save()
    return HttpResponse('<i class="bi bi-eye-fill"></i>' if user.is_active else '<i class="bi bi-eye-slash-fill"></i>')


# Valores
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.views.generic import DeleteView

class UserDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    model = User
    success_url = '/' # O redirecionamento no URL de sucesso
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        return context

    def test_func(self): # Teste se o usuário é superusuário e tem permissão para excluir
        user = self.get_object()
        if self.request.user != user and self.request.user.is_superuser:
            return True
        return False
Embora isso seja prático quando necessário, a exclusão de um usuário não deve ser necessária na maioria das vezes, podemos simplesmente alternar a visibilidade dos usuários que visitam o site se precisarmos descartá -los. Os padrões de URL que adicionamos são assim. Com o Nano, edite usuários/urls.py e adicione estas linhas:

nano users/urls.py
As linhas devem ir na lista de caminhos nas visualizações do usuário, antes do final "]", mas após o início "[".

# ...
    path('user/<int:pk>/delete/', UserDeleteView.as_view(template_name='blog/user_confirm_delete.html'), name='delete-user'),
    path('user/<int:pk>/active/', views.toggle_user_active, name='toggle-user-active'),
# ...
Agora, certifique -se de fazer backup do site para que você possa baixá -lo no servidor da web em que continuaremos trabalhando. Da linha de comando,

sudo backup
Agora nosso site está backup. Então agora temos mais alguns recursos úteis. Mas e o quadro geral aqui? Esse código ainda não é acessível na Internet, ainda não temos servidor de correio e precisamos expandir nosso aplicativo para incluir um processo de verificação abrangente, bem como layouts suaves para nos ajudar a explorar o site, juntamente com protocolos seguros para autenticar usuários privilegiados . Vamos chegar a tudo isso. A coisa mais importante por enquanto estará apenas obtendo esse código on -line, o que podemos fazer com apenas algumas linhas de batida em um servidor Ubuntu. Você precisará alugar um servidor para isso, a menos que tenha um servidor em casa e uma assinatura de internet comercial que permita abrir portas. Pessoalmente, corro meu site em um HP Z440 instalado no meu apartamento, mas geralmente é muito mais barato para as necessidades básicas de alugar um servidor privado virtual (VPS). Lembre -se de que o código que estamos executando agora é relativamente fino, ele precisará ser mantido e melhorado antes de seremPronto para usar o que temos para construir um produto. Certifique -se de ter cuidado com o que você faz com a Internet, certifique -se de implantar publicamente este site na Web em um servidor Linux, você terá um plano para bloquear interações indesejadas com seu site. Provavelmente, isso não será um problema no início, mas procuraremos uma variedade de soluções para combater isso, incluindo aprendizado de máquina, inteligência artificial e visão computacional. Quando isso se tornar um problema, procure mais neste texto uma solução. Em termos de aluguel de um VPS, há muitos lugares que você pode ir. O Google Cloud possui servidores VPS, IONOS, Kamatera, Amazon AWS e mais fornecedores oferecem soluções de servidor em nuvem que atenderão às nossas necessidades. Você precisará clicar em seus formulários e selecionar um plano para começar. Você pode ir com um plano básico com qualquer provedor, mas verifique se o provedor permite abrir as portas do servidor de correio port para enviar email (isso deve ser a porta 587 e a porta 25), alguns fornecedores bloqueiam essas portas. Até agora eu tive oA IST Experience com Iionos e Kamatera, ambos me permitirão enviar e -mails ilimitados e seus preços são muito baratos. Você se conectará ao seu novo servidor sobre um protocolo chamado ssh ou shell seguro, que permite que você interaja remotamente com o servidor exatamente como o seu computador pessoal, do seu computador pessoal. Quando você configura o servidor, o provedor de hospedagem provavelmente solicitará que você adicione uma tecla SSH, ou eles fornecerão um nome de usuário e senha. A chave SSH é como você efetuará login no servidor na linha de comando para editar o código. Use as opções abaixo do ssh-keygen para gerar um ssh

ssh-keygen
Salve o arquivo e substitua -o, se necessário, é bom girar suas teclas SSH, se você ainda não o fizer. Agora, você pode usar o seguinte comando para ver sua tecla SSH. Você deseja copiá -lo para o seu servidor remoto para que você possa usá -lo para autenticar.

cat ~/.ssh/id_rsa.pub
Se você não conseguiu ver uma chave SSH ao digitar esse comando (uma longa sequência de dígitos e cartas começando com “SSH-RSA AAA”), tente gerar uma chave RSA (eles são mais seguros, então eu aconselho a usá-los .) O código a seguir gerará uma chave SSH de 4096 bits RSA.

ssh-keygen -t rsa -b 4096
Crie um VPS executando o Ubuntu, mas você planeja fazer isso. Depois de criar um VPS clicando nos formulários no site dos provedores (kamatera.com, ionos.com ou similar), você deseja fazer login. Para fazer isso, use o comando ssh com seu endereço IP (o endereço Parece xx.xx.xx.xx). Você também precisará ser sensível ao nome de usuário padrão no servidor que criamos, por exemplo, Ubuntu.

ssh ubuntu@XX.XX.XX.XX
Você pode ser solicitado uma senha, se solicitar uma senha, insira -a. Não usaremos o nome de usuário padrão, então vamos começar criando um novo usuário e adicionando uma chave SSH à sua conta. Vamos começar adicionando um novo arquivo SSHD_CONFIG, que informa ao servidor como usar o SSH.

nano sshd_config

# Este é o arquivo de configuração em todo o SSHD Server System.  Ver
# sshd_config (5) para obter mais informações.

# Este sshd foi compilado com caminho =/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

# A estratégia usada para opções no SSHD_CONFIG padrão enviado com
# OpenSsh é especificar opções com seu valor padrão onde
# possível, mas deixe -os comentados.  As opções não declaradas substituem o
# Valor padrão.

# Port 22
# Endereço Family qualquer
# Endereço da lista 0.0.0.0
# Ouça o endereço ::

# Hostkey/etc/ssh/ssh_host_rsa_key
# Hostkey/etc/ssh/ssh_host_ecdsa_key
# Hostkey/etc/ssh/ssh_host_ed25519_key

# Cifras e digitação
# RekeyLimit Padrão Nenhum

# Log
# Syslogfacility Auth
# Informações de Loglevel

# Autenticação:

# LogringRacetime 2M
# Permitrootlogina Proibit-Password
# Strictmodes sim
# Maxauthtries 6
# Maxessions 10

PubkeyAuthentication yes

# Espere .SSH/Authorized_Keys2 a ser desconsiderado por padrão no futuro.
AuthorizedKeysFile	.ssh/authorized_keys .ssh/authorized_keys2

# AutorizadoPrincipalsFile Nenhum

# Autorizado KeysCommand Nenhum
# Autorizado KeysCommanduser ninguém

# Para que isso funcione, você também precisará de teclas de host em/etc/ssh/ssh_known_hosts
# HostBaseDauthentication no
# Mude para sim se você não confia ~/.ssh/conhecido_hosts para
# HostBaseDauthentication
# IgnoreUser conhecida no não
# Não leia os arquivos ~/.rhosts e ~/.shosts do usuário
# Ignorerhosts Sim

# Para desativar as senhas de texto transparente túnel, altere não aqui!
PasswordAuthentication no
# PermitEmptyPasswords no

# Alterar para sim para ativar as senhas de resposta do desafio (cuidado com os problemas com
# alguns módulos e tópicos PAM)
KbdInteractiveAuthentication no

# Opções de Kerberos
# Kerberosauthentication no
# Kerberosorlocalpasswd sim
# Kerberosticketcleanup sim
# Haste kerberoscada no

# Opções GSSAPI
# GSsapiauthentication no
# GSSAPICLEANUPCREDENTS SIM
# GSSAPISTRICTACECCETOCHECK SIM
# GSSAPIKEYEXCHANGE NO

# Defina isso como 'sim' para ativar a autenticação PAM, processamento de contas,
# e processamento de sessão. Se isso estiver ativado, a autenticação do PAM irá
# ser permitido através da KBDInterActiveAuthentication e
# PasswordAuthentication.  Dependendo da sua configuração de PAM,
# A autenticação PAM via KBDInterActiveAuthentication pode ignorar
# a configuração de "Permitrootlogina sem passanha".
# Se você apenas deseja que a conta do PAM e as verificações de sessão sejam executadas sem
# Autenticação PAM, então ative isso, mas defina a senha da autenticação
# e kbdinteractiveAuthentication para 'não'.
UsePAM yes

# Permitir que simbolizar sim
# AllowTcpforwarding Sim
# Gatewayports não
X11Forwarding yes
# X11Displayoffset 10
# X11USELOCALHOST Sim
# Permite sim
PrintMotd no
# PrintLastLog Sim
# Tcpkeepalive Sim
# PermitUserEnvironment no
# Compressão atrasada
# Intervalo cliente 0
# ClienteCountMax 3
# UseDNS no
# Pidfile /run/sshd.pid
# MaxStartups 10: 30: 100
# Pemittunl não
# Chrootdirectory Nenhum
# Versão Adendo Nenhum

# Nenhum caminho de banner padrão
Banner /etc/banner

# Permitir que o cliente passe variáveis ​​locais variáveis
AcceptEnv LANG LC_*

# substituir a inadimplência de não subsistemas
Subsystem	sftp	/usr/lib/openssh/sftp-server

# Exemplo de configurações primordiais por um usuário
# Combine o usuário ANONCVS
# X11 para a direção do não
# Allowtcpforwarding no
# 	PermitTTY no
# ForceCommand CVS Server
PermitRootLogin no
Lembre -se, Ctrl+X e Y para salvar o arquivo. Em seguida, vamos escrever um script básico chamado Initialize (tudo no diretório inicial padrão do nosso usuário).

nano initialize
Adicione essas linhas ao arquivo, substituindoCom sua chave SSH que você encontrou usando o CAT. (.ssh/id_rsa.pub)

# !
sudo apt install -y nano git openssh-server
sudo cp sshd_config /etc/ssh/sshd_config
sudo service ssh restart
sudo service sshd restart
echo "/root/.ssh/id_rsa" | sudo su root -c "ssh-keygen -t rsa -N ''"
echo "root ssh key:"
sudo su root -c "cat /root/.ssh/id_rsa.pub"
sudo adduser --disabled-password --gecos "" team
sudo passwd -d team
sudo usermod -aG sudo team
echo "/home/team/.ssh/id_rsa" | su team -c "ssh-keygen -t rsa -N ''"
cat /home/team/.ssh/id_rsa.pub >> /home/team/.ssh/authorized_keys
echo '<key here>' >> /home/team/.ssh/authorized_keys
echo "team ssh key:"
cat /home/team/.ssh/id_rsa.pub
Para orientá -lo por esse arquivo, vamos iniciar linha por linha. A primeira linha diz ao compilador que este é um script bash. Em seguida, estamos instalando dependências, copiando sshd_config para o diretório correto, reiniciando o ssh, gerando chaves ssh para root, adicionando o usuário 'equipe' (você pode escolher um nome que gosta para isso, use o comando adduser com o nome e a senha desativada para agora). Também adicionamos equipe ao grupo sudo, geramos sua chave SSH, adicionamos nossa chave para as chaves autorizadas e as deles também e imprimimos sua chave. Este novo usuário será como fazemos login no site. Em um novo terminal, vá em frente e abra o servidor novamente.

ssh team@XX.XX.XX.XX
Desta vez, você não deve precisar de uma senha, pois tem uma chave SSH. Também desativamos o login com senha para manter o site mais seguro. Agora, este servidor inicia completamente em branco sem informações sobre ele. Vamos começar clonando nosso projeto do Git para que possamos baixar e executá -lo na máquina remota. No servidor remoto conectado sobre SSH, primeiro imprima sua chave SSH:

cat ~/.ssh/id_rsa.pub
Em seguida, cole essa chave nas configurações do Git, como fizemos antes para configurar nosso repositório Git. Agora podemos clonar nosso projeto diretamente para o servidor. Certifique -se de fazer backup do projeto localmente primeiro, para que esteja no servidor Git para baixar.

git clone git://github.com/you/yourproject.git
Perfeito. Agora todos os arquivos estão aqui. Podemos vê -los com LS

ls
Agora, vamos começar a configurar o servidor. Primeiro, copie seu diretório de projeto em um nome simples e memorável que usaremos para o projeto.

cp -r yourproject whatyoucalledit
Onde "WhatyouCalledit" é o novo nome do seu projeto. Em seguida, precisaremos criar um utilitário básico para configurar o servidor. Salvaremos esse utilitário e o usaremos no futuro. Para construir esse utilitário, vamos criar um binário de usuário para definir como editamos um script. Usando Bash, Edit/usr/bin/ASCRIpt

sudo nano /usr/bin/ascript
Certifique -se de usar o sudo lá para ter permissões para editar o arquivo. No arquivo, adicione estas linhas:

# !
if [ ! -f /usr/bin/$1 ]; then
    sudo touch /usr/bin/$1
    echo "# !
    sudo chmod a+x /usr/bin/$1
    sudo nano /usr/bin/$1
    echo $1 | sudo tee -a /etc/ascripts
else
    sudo chmod a+x /usr/bin/$1
    sudo nano /usr/bin/$1
fi
Lembre -se de que este script leva um argumento, o nome do script, como US $ 1. Primeiro, ele verifica se o arquivo existe ou o cria, adiciona a primeira linha a declarar que o script é bash, altera suas permissões, edita -o e adiciona seu nome a /etc /ANDRACTS que nos permite armazenar os nomes dos scripts que nós estão criando. Se o arquivo já existir, basta alterar as permissões e editá -lo. Salve o arquivo e, em seguida, alteraremos suas permissões. Enquanto usamos esse script, não teremos que fazer isso novamente.

sudo chmod a+x /usr/bin/ascript
Perfeito. Agora vamos criar um script chamado Configuração. Primeiro, para não sobrecarregá -lo, mas dê uma olhada na aparência do meu script de configuração. Vamos percorrer como esse script deve ser em seu projeto, você não precisará de tudo no meu script para começar.

# !
SECONDS=0
PYTHON_VERSION=3.12
echo "femmebabe installer initialized."
# sudo chmod a+x scripts/usertupup
# ./scripts/usersetup
# SSH-Keyen
# Diretório do projeto
DIR="/home/team/femmebabe"
USER="team"
# Comandos de log
echo "Logging commands"
sudo cp log/commands.log /var/log/commands.log
sudo chmod -R a+w /var/log
sudo chown -R :syslog /var/log
echo $'alias venv="source /home/team/femmebabe/venv/bin/activate"' | sudo tee -a /home/team/.profile
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a /etc/bashrc
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a "/home/team/.bashrc"
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a /root/.bashrc
echo "source /etc/bashrc" | sudo tee -a /home/team/.profile
echo "/var/log/commands.log" | sudo tee -a /etc/logrotate.d/syslog
echo "local6.*    /var/log/commands.log" | sudo tee -a "/etc/rsyslog.d/bash.conf"
sudo service rsyslog restart
# Nano Config
echo "set tabsize 4" >> .nanorc
echo "set tabstospaces" >> .nanorc
# Config Git
echo "Git configuration"
sudo git config --global user.email "jasper.camber.holton@gmail.com" && sudo git config --global user.name "Jasper Holton"
git config --global user.email "jasper.camber.holton@gmail.com"
git config --global user.name "Jasper Holton"
git config --global --add safe.directory $"$DIR"
sudo ssh-keyscan -t rsa gitlab.com | sudo tee -a /root/.ssh/known_hosts
sudo ssh-keyscan -t rsa github.com | sudo tee -a /root/.ssh/known_hosts
echo "Mounting setup"
sudo mount -o remount,size=16G,exec /tmp
# Atualizar e instalar
echo "Update and install packages"
sudo apt update && sudo NEEDRESTART_MODE=a apt upgrade -y
sudo apt purge postgresql-client-14 postgresql-client-common postgresql-common postgresql-contrib postgresql -y
echo "postfix postfix/mailname string femmebabe.com" | sudo debconf-set-selections
echo "postfix postfix/main_mailer_type string 'Internet Site'" | sudo debconf-set-selections
sudo NEEDRESTART_MODE=a DEBIAN_FRONTEND=noninteractive apt install -y postfix
sudo NEEDRESTART_MODE=a apt install -y rkhunter clamav-daemon libx264-dev ffmpeg libapache2-mod-wsgi-py3 apache2 cmake python-is-python3 python3-venv python3-pip python3-django expect tesseract-ocr openjdk-8-jdk redis-server libopencv-dev python3-opencv python3-dev libsasl2-dev opendkim opendkim-tools dovecot-core dovecot-pop3d dovecot-imapd auditd procmail libpq-dev postgresql postgresql-contrib libheif-dev snapd git software-properties-common certbot python3-certbot-apache
echo "-a exit,always -F arch=b64 -F euid=0 -S execve" | sudo tee -a /etc/audit/audit.rules
echo "-a exit,always -F arch=b32 -F euid=0 -S execve" | sudo tee -a /etc/audit/audit.rules
# Ativar antivírus clamav
echo "Starting antivirus"
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Defina o nome do host
echo "127.0.0.1 femmebabe" | sudo tee -a /etc/hosts
sudo hostnamectl set-hostname localhost
# Configure o PostGres
echo "Postgres setup"
sudo -u postgres psql -U postgres -c "DROP DATABASE database;"
sudo -u postgres psql -U postgres -c "CREATE DATABASE database;"
sudo -u postgres psql -U postgres -c "CREATE USER django WITH PASSWORD 'password';"
sudo -u postgres psql -U postgres -c "ALTER ROLE django SET client_encoding TO 'utf8';"
sudo -u postgres psql -U postgres -c "ALTER ROLE django SET default_transaction_isolation TO 'read committed';"
sudo -u postgres psql -U postgres -c "ALTER ROLE django SET timezone TO 'UTC';"
sudo -u postgres psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE database TO django;"
# Configurar banco de dados de backup
echo "Building database from backup, this may take a while."
cat db.json.?? > db.json
echo "Configuring firewall"
sudo ufw default allow outgoing
sudo ufw default deny incoming
sudo ufw allow 22
sudo ufw allow http
sudo ufw allow https
sudo ufw allow 'Postfix'
sudo ufw allow 'Postfix SMTPS'
sudo ufw allow 'Postfix Submission'
sudo ufw allow 'Dovecot POP3'
sudo ufw allow 'Dovecot Secure POP3'
sudo ufw allow 110/tcp
sudo ufw allow 25/tcp
echo "y" | sudo ufw enable
# Ipatable desativado
echo "Configuring firewall"
sudo iptables -P INPUT ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -F
sudo iptables-save
# Instale o BitDefender
cd $DIR
echo "Runnning BitDefender antivirus installer"
wget https://cloud.gravityzone.bitdefender.com/Packages/NIX/0/7aTSsy/setup_downloader.tar
mkdir bitdefender
tar -xf setup_downloader.tar -C bitdefender
sudo rm setup_downloader.tar
sed -i -e 's/{LOGINPASSWD/z&A*3BPd_qBGUMs/g' bitdefender/installer
sudo chmod a+x bitdefender/installer
sudo ./bitdefender/installer
# Configurar postfix
cd $DIR
echo "Mail services configuration"
sudo cp /etc/postfix/main.cf /etc/postfix/main.cf.backup
sudo cp config/etc_postfix_main.cf /etc/postfix/main.cf
sudo cp config/etc_postfix_master.cf /etc/postfix/master.cf
sudo cp config/etc_default_opendkim /etc/default/opendkim
sudo cp config/etc_dovecot_conf.d_10-auth.conf /etc/dovecot/conf.d/10-auth.conf
sudo cp config/etc_dovecot_conf.d_10-master.conf /etc/dovecot/conf.d/10-master.conf
sudo cp config/etc_dovecot_dovecot.conf /etc/dovecot/dovecot.conf
sudo cp config/etc_dovecot_passwd /etc/dovecot/passwd
sudo cp config/etc_opendkim.conf /etc/opendkim.conf
sudo cp config/etc_default_opendkim /etc/default/opendkim
sudo adduser postfix opendkim
sudo mkdir /etc/opendkim
sudo mkdir /etc/opendkim/keys
sudo mkdir /etc/opendkim/keys/femmebabe.com
sudo mkdir /var/spool/postfix/opendkim
sudo echo "*@femmebabe.com     sendonly._domainkey.femmebabe.com" | sudo tee -a /etc/opendkim/signing.table
sudo echo "sendonly._domainkey.femmebabe.com    femmebabe.com:sendonly:/etc/opendkim/keys/femmebabe.com/sendonly.private" | sudo tee -a /etc/opendkim/key.table
sudo echo "127.0.0.1" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "localhost" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "*.femmebabe.com" | sudo tee -a /etc/opendkim/trusted.hosts
sudo chown -R opendkim:opendkim /etc/opendkim
sudo opendkim-genkey -b 2048 -d femmebabe.com -D /etc/opendkim/keys/femmebabe.com -s sendonly -v
sudo chmod go-rw /etc/opendkim/keys
sudo chown opendkim:opendkim /etc/opendkim/keys/femmebabe.com/sendonly.private
sudo chown opendkim:postfix /var/spool/postfix/opendkim
cd $DIR
sudo cp mailbox/* /var/mail/
sudo chown :users /var/mail/*
sudo chmod -R a+rwx /var/mail/*
sudo systemctl restart opendkim postfix dovecot
# Crie Dirs
cd $DIR
mkdir media/audio
mkdir media/audio/fingerprints
mkdir media/security
mkdir media/secure
mkdir media/secure/media
mkdir media/secure/video
mkdir media/secure/profile
mkdir media/secure/face
mkdir media/images
mkdir media/live
mkdir media/live/files
mkdir media/live/stills
mkdir media/files
mkdir temp
mkdir temp/data
mkdir temp/gfpgan
mkdir mail/inbox
mkdir mailbox
# Configure VirtueAnv
cd $DIR
echo "Creating virtual environment"
python -m venv venv
source venv/bin/activate
# Obtenha e construa dependências
echo "Getting and building dependencies, this may take a whike"
cd $DIR
git clone https://github.com/sukhitashvili/violence-detection.git
cp config/vd-requirements.txt violence-detection/requirements.txt
cp config/vd-model.py violence-detection/model.py
cd violence-detection
pip3 install -r requirements.txt
cd $DIR
wget https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.3.pth -P experiments/pretrained_models
git clone https://github.com/TencentARC/GFPGAN.git
git clone https://github.com/davisking/dlib.git
cd dlib
mkdir build; cd build; cmake ..; cmake --build .
cd ..
source venv/bin/activate
python setup.py install
cd $DIR
source venv/bin/activate
cd $DIR/GFPGAN/
echo "Installing python dependencies"
pip install basicsr
pip install facexlib
pip install -r requirements.txt
python setup.py develop
pip install realesrgan
cd $DIR
sudo chown -R team:users gfpgan
echo "Installing ta-lib"
wget https://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz
tar xvzf ta-lib-0.4.0-src.tar.gz
sudo rm ta-lib-*
cd ta-lib
sudo ./configure
sudo make
sudo make install
# Defina as regras do firewall
cd $DIR
# Instale as dependências do PYPI
echo "Installing remaining python dependencies (this may take a while)"
sudo systemctl mask tmp.mount
cd $DIR
source venv/bin/activate
pip3 install -U "celery[redis]"
pip3 install -r requirements.txt --use-deprecated=legacy-resolver --use-pep517
pip3 install --upgrade opencv-python # == 4.5.4.60
pip3 install --upgrade opencv-contrib-python # == 4.5.4.60
# PIP Instale opencv-python == 4.5.5.64
# Instalação do PIP OpenCV-Contrib-Python == 4.5.5.64
pip3 install --upgrade opencv-python-headless
pip3 uninstall channels
pip3 uninstall daphne
pip3 install channels["daphne"]
pip3 install Pillow==9.5.0
pip3 install librosa
pip3 install -U 'Twisted[tls,http2]'
pip3 install --upgrade certifi requests urllib3 numpy oauthlib twisted pyjwt sqlparse cryptography astral webauthn docbarcodes pdf417 deepface --no-cache-dir
pip3 install tensorflow==2.15.1
# Instale o certbot
echo "Installing certificates"
sudo snap install core; sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo snap install redis
sudo systemctl enable apache2
sudo systemctl start apache2
# Execute o certbot
sudo certbot --apache --non-interactive --agree-tos --domains femmebabe.com --email jasper.camber.holton@gmail.com
# Recarregue o servidor de correio
sudo systemctl restart opendkim postfix dovecot
# CHEPES DE COPY
# sudo cp /etc/letsecrypt/live/femmebabe.com/privkey.pem privkey.pem
# sudo cp /etc/lettesencrypt/live/femmebabe.com/cert.pem cert.pem
# Correção
cp scripts/content.py $"/home/team/femmebabe/venv/lib/python${PYTHON_VERSION}/site-packages/pyxb/binding/content.py"
cp scripts/pwa_webpush_forms.py $"/home/team/femmebabe/venv/lib/python${PYTHON_VERSION}/site-packages/pwa_webpush/forms.py"
cp scripts/webauth_views.py $"/home/team/femmebabe/venv/lib/python${PYTHON_VERSION}/site-packages/webauth/views.py"
cp scripts/json.py $"venv/lib/python${PYTHON_VERSION}/site-packages/django/core/serializers/json.py"
# Defina as configurações do usuário
sudo gpasswd -a www-data users
# Defina permissões
echo "Setting permissions"
sudo chown -R team:users cache/
sudo chmod a+rwx -R cache/
# SUDO CHOW
# Raiz CHOW
sudo chown -R redis:redis /var/lib/redis
sudo chown -R redis:redis /var/log/redis
sudo chmod -R u+rwX,g+rwX,u+rx /var/log/redis
sudo chmod +r /etc/redis/redis.conf
sudo chown -R team:users /var/log/
sudo chown -R :users .././
sudo chmod -R g+rwX ./
sudo chmod -R g+rX .././
sudo chmod -R g-rwX ../.ssh
sudo chmod 774 ./
# sudo chmod 664 db.sqlite3
# sudo chown www-data: usuários db.sqlite3
sudo chown -R www-data:www-data media/
sudo chown www-data:users ./
sudo chown -R team:users media/
sudo chown -R team:users ./
sudo chown -R team:users ./gfpgan/
sudo chown -R team:users ./temp/
sudo chmod a+r team /var/mail/$USER
# Copie a configuração e defina permissões
echo "Configuring remaining services"
sudo cp config/apis.json /etc/apis.json
sudo cp config/config.json /etc/config.json
sudo cp config/femmebabe-le-ssl.conf /etc/apache2/sites-available/femmebabe-le-ssl.conf
sudo cp config/etc_dovecot_passwd /etc/dovecot/passwd
sudo cp config/etc_init.d_celery /etc/init.d/celery
sudo cp config/etc_init.d_celerybeat /etc/init.d/celerybeat
sudo cp config/etc_default_celerybeat /etc/default/celerybeat
sudo cp config/etc_default_celery /etc/default/celery
sudo cp config/etc_systemd_system_daphne.service /etc/systemd/system/daphne.service
sudo cp config/etc_systemd_system_celery.service /etc/systemd/system/celery.service
sudo cp config/etc_systemd_system_celerybeat.service /etc/systemd/system/celerybeat.service
sudo chmod a+x /etc/init.d/celery
sudo chmod a+x /etc/init.d/celerybeat
# Configuração do banco de dados
echo "Running migrations, this should be quick"
python manage.py makemigrations
python manage.py migrate --run-syncdb
echo "Loading data, this may take a while"
python manage.py loaddata db.json
echo "Setup crontab/sudoers configuration"
sudo crontab -l -u root | cat - config/crontab | sudo crontab -u root -
sudo sh -c "cat config/sudoers >> /etc/sudoers"
# Injete Config Pam e remova a configuração SSH com defeito
# sudo sed -i '' -e '$ d' /tc/pam.d/sshd
# Sudo sed -i '' -e $ d ' /etc /perfil
echo "session required pam_exec.so seteuid /home/team/femmebabe/pam.sh" | sudo tee -a /etc/pam.d/sshd
echo "session required pam_exec.so seteuid /home/team/femmebabe/logout.sh" | sudo tee -a /etc/pam.d/sshd
sudo chmod a+x pam.sh
sudo rm /etc/ssh/sshd_config.d/50-cloud-init.conf
# Copiar scripts de bin e definir permissões
echo "Copying scripts"
sudo cp scripts/reload /usr/bin/
sudo cp scripts/check /usr/bin/
sudo cp scripts/enagpu /usr/bin/
sudo cp scripts/disgpu /usr/bin/
sudo cp scripts/activate /usr/bin/
sudo cp scripts/backup /usr/bin/
sudo cp scripts/ascript /usr/bin/
sudo cp scripts/setup /usr/bin/
sudo cp scripts/addsetup /usr/bin/
sudo cp scripts/watchlogs /usr/bin/
sudo cp scripts/logs /usr/bin/
sudo cp scripts/cmds /usr/bin/
sudo cp scripts/setup /usr/bin/
sudo cp scripts/pushweb /usr/bin/
sudo cp scripts/purgecache /usr/bin/
sudo cp config/banner /etc/banner
cd /usr/bin/
sudo chmod a+x activate
sudo chmod a+x backup
sudo chmod a+x ascript
# Recarregue e habilite os serviços
echo "Enabling services"
sudo systemctl daemon-reload
sudo systemctl enable daphne.service
sudo systemctl enable celery.service
sudo systemctl enable celerybeat.service
sudo systemctl enable clamav-daemon
sudo systemctl start daphne.service
sudo systemctl start celery.service
sudo systemctl start celerybeat.service
sudo systemctl start clamav-daemon
# Ativar módulos Apache
echo "Enabling apache2"
sudo a2enmod rewrite
sudo a2enmod wsgi
sudo a2enmod headers
sudo a2enmod ssl
sudo a2enmod proxy
sudo a2enmod proxy_balancer
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel
# sudo a2dismod mpm_event
# sudo a2dismod mpm_worker
# sudo a2enmod mpm_prefork
# Desative o site padrão
sudo a2dissite 000-default
sudo a2dissite 000-default-le-ssl
# Ativar para o site
sudo a2ensite femmebabe-le-ssl
# Recarregue o daemon e reinicie o Apache, Postfix e Opendkim
sudo systemctl daemon-reload
sudo systemctl restart apache2
sudo systemctl restart opendkim postfix
sudo systemctl start daphne
# Defina permissões
sudo chown -R :www-data /var/www/
sudo chown -R :www-data /var/www/.deepface
# Configuração de troca
echo "Allocating swap, this may take a while"
sudo swapoff /swapfile
sudo rm /swapfile
sudo fallocate -l 8G /swapfile
sudo dd if=/dev/zero of=/swapfile bs=1024 count=8388608
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo "/swapfile swap swap defaults 0 0" | sudo tee -a /etc/fstab
sudo swapon --show
# Motor de legenda init
echo "Initializing routine caption"
/home/team/femmebabe/venv/bin/python /home/team/femmebabe/routine_caption.py
/home/team/femmebabe/venv/bin/python /home/team/femmebabe/setup_mail.py
# Configuração git
echo "Setting up git"
cd $DIR
sudo rm -r .git
git init --initial-branch=main
echo "Setting user password"
sudo usermod --password $(echo team | openssl passwd -1 -stdin) team
# Mostre IPv6 e OpendKim para configuração de domínio
echo "COPY the below information to domain configuration."
hostname -I
ip a | grep inet
ip -6 addr | grep "scope link"
sudo cat /etc/opendkim/keys/femmebabe.com/sendonly.txt | tr -d '\n' | sed 's/\s//g' | sed 's/""//g' | awk -F'[)(]' '{print $2}'
# Configuração concluída
echo "Setup completed in"
wc -l scripts/setup
echo "lines of code."
echo "Total time:"
duration=$SECONDS
echo "$((duration / 60)) minutes and $((duration % 60)) seconds elapsed."
echo "TODO:"
echo "- COPY above IPv6 address to domain DNS configuration"
echo "- COPY domain key to domain DNS configuration"
echo "- ADD new git repository with git remote add originlab <repo>."
echo "- OPEN port 25"
echo "- INSTALL antivirus as per reccomendations"
echo "- TEST"
echo "If neccesary,"
echo "- DEBUG"
echo "- FIX setup and backup scripts"
echo "- Fix server"
echo ""
echo "Thank you for using the femmebabe installer. Have a great day!"
echo "Goodbye."
Isso é muita configuração! Em resumo, este código registra comandos, configura o nano e o git, copia os arquivos, downloads e instala pacotes ubuntu apt, dependências de python, configura o postfix, configura o PostGresql (o servidor de banco de dados) e carrega o banco de dados, configura o UFW (um Firewall não complicado), Desative iptables, baixar um antivírus, faz diretórios, clones dependências, instala certificados e configura o servidor, instala a configuração, inicia e permite o sever, aloca troca, define permissões e imprime o endereço IP, IPv6 e a tecla Opendkim. Bastante simples, mas parece muito código. Não precisaremos muito disso, porque não temos as dependências, não estamos usando aipo, aipo ou Daphne, mas instalaremos alguns deles de qualquer maneira para começar. Observe que este código tem um domínio declarado várias vezes. Também precisaremos comprar um nome de domínio (que é uma pequena taxa anual). Eu recomendo o Squarespace para comprar um domínio, o layout deles éintuitivo e fácil de usar. Você pode comprar qualquer domínio de sua escolha, mas estou usando o domínio femmebabe.com neste exemplo. Depois de comprar um domínio, acesse o painel de configuração DNS Squarespace e adicione um registro A apontando seu domínio ao servidor por endereço IP. Deve ser assim: @ A xx.xx.xx.xx Com o operador @ como o host, o que significa que todos os subdomínios neste domínio e o domínio raiz serão redirecionados para o servidor. Há mais registros a declarar, mas podemos passar para eles quando estivermos prontos para enviar e -mails. Lembre -se de que pode levar vários dias para que você possa enviar e -mails com sucesso do servidor. Os registros do DNS que estamos definindo levarão tempo para propagar. De qualquer forma, o único registro que precisamos começar é um registro. Então agora podemos preencher o script abaixo de acordo com o nosso projeto e executá -lo. Vamos começar com um script de configuração menor para instalar o que precisamos para um progresso básico. Ainda não usaremos tantas dependências ou pós -grausql, apenas nós apenas nósUp um servidor HTTP básico e se preocupe em certificá -lo quando for feito. Lembre -se, para obter um certificado HTTPS e executar o servidor com segurança, precisaremos comprar um domínio junto com o aluguel de um servidor. Por enquanto, substitua "equipe" neste arquivo pelo nome do seu usuário, "dir" pelo diretório do seu projeto e forneça seu email e domínio nas tags <>. Além disso, antes de executar esse código, precisamos alterar as configurações para o firewall que o provedor de hospedagem suporta, se houver. Normalmente, isso está na guia 'Redes' do seu provedor de hospedagem, ou se você estiver hospedado, está na seção 'encaminhamento de porta' do seu roteador. Você também deseja configurar um IP estático através do seu roteador com o endereço da sua máquina de servidor, se estiver usando a auto -hospedagem. Você precisará abrir as seguintes portas para acesso a leitura/gravação. 22 (SSH) 25 (correio) 587 (correio) 110 (cliente de correio) 80 (http) 443

# !
SECONDS=0
PYTHON_VERSION=3.12
echo "femmebabe installer initialized."
DIR="/home/team/<yourproject>"
USER="team"
# Comandos de log
echo "Logging commands"
sudo cp log/commands.log /var/log/commands.log
sudo chmod -R a+w /var/log
sudo chown -R :syslog /var/log
echo $'alias venv="source /home/team/femmebabe/venv/bin/activate"' | sudo tee -a /home/team/.profile
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a /etc/bashrc
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a "/home/team/.bashrc"
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a /root/.bashrc
echo "source /etc/bashrc" | sudo tee -a /home/team/.profile
echo "/var/log/commands.log" | sudo tee -a /etc/logrotate.d/syslog
echo "local6.*    /var/log/commands.log" | sudo tee -a "/etc/rsyslog.d/bash.conf"
sudo service rsyslog restart
# Nano Config
echo "set tabsize 4" >> .nanorc
echo "set tabstospaces" >> .nanorc
# Config Git
echo "Git configuration"
sudo git config --global user.email "<youremail>@gmail.com" && sudo git config --global user.name "<yourname>"
git config --global --add safe.directory $"$DIR"
sudo ssh-keyscan -t rsa gitlab.com | sudo tee -a /root/.ssh/known_hosts
sudo ssh-keyscan -t rsa github.com | sudo tee -a /root/.ssh/known_hosts
# Atualizar e instalar
echo "Update and install packages"
sudo apt update && sudo NEEDRESTART_MODE=a apt upgrade -y
sudo apt purge postgresql-client-14 postgresql-client-common postgresql-common postgresql-contrib postgresql -y
echo "postfix postfix/mailname string femmebabe.com" | sudo debconf-set-selections
echo "postfix postfix/main_mailer_type string 'Internet Site'" | sudo debconf-set-selections
sudo NEEDRESTART_MODE=a DEBIAN_FRONTEND=noninteractive apt install -y postfix
sudo NEEDRESTART_MODE=a apt install -y rkhunter clamav-daemon libx264-dev ffmpeg libapache2-mod-wsgi-py3 apache2 cmake python-is-python3 python3-venv python3-pip python3-django expect tesseract-ocr openjdk-8-jdk redis-server libopencv-dev python3-opencv python3-dev libsasl2-dev opendkim opendkim-tools dovecot-core dovecot-pop3d dovecot-imapd auditd procmail libpq-dev postgresql postgresql-contrib libheif-dev snapd git software-properties-common certbot python3-certbot-apache
# Ativar antivírus clamav
echo "Starting antivirus"
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Defina o nome do host
echo "127.0.0.1 femmebabe" | sudo tee -a /etc/hosts
sudo hostnamectl set-hostname femmebabe
# Configurar banco de dados de backup
echo "Building database from backup, this may take a while."
cat db.json.?? > db.json
echo "Configuring firewall"
sudo ufw default allow outgoing
sudo ufw default deny incoming
sudo ufw allow 22
sudo ufw allow http
sudo ufw allow https
sudo ufw allow 'Postfix'
sudo ufw allow 'Postfix SMTPS'
sudo ufw allow 'Postfix Submission'
sudo ufw allow 'Dovecot POP3'
sudo ufw allow 'Dovecot Secure POP3'
sudo ufw allow 110/tcp
sudo ufw allow 25/tcp
echo "y" | sudo ufw enable
# Ipatable desativado
echo "Configuring firewall"
sudo iptables -P INPUT ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -F
sudo iptables-save
# Configure VirtueAnv
cd $DIR
echo "Creating virtual environment"
python -m venv venv
source venv/bin/activate
pip3 install -r requirements.txt
# Instale o certbot
echo "Installing certificates"
sudo snap install core; sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo snap install redis
sudo systemctl enable apache2
sudo systemctl start apache2
# Execute o certbot
sudo certbot --apache --non-interactive --agree-tos --domains femmebabe.com --email <youremail>@gmail.com
# Defina as configurações do usuário
sudo gpasswd -a www-data users
# Defina permissões
echo "Setting permissions"
sudo chown -R team:users cache/
sudo chmod a+rwx -R cache/
# SUDO CHOW
# Raiz CHOW
sudo chown -R redis:redis /var/lib/redis
sudo chown -R redis:redis /var/log/redis
sudo chmod -R u+rwX,g+rwX,u+rx /var/log/redis
sudo chmod +r /etc/redis/redis.conf
sudo chown -R team:users /var/log/
sudo chown -R :users .././
sudo chmod -R g+rwX ./
sudo chmod -R g+rX .././
sudo chmod -R g-rwX ../.ssh
sudo chmod 774 ./
sudo chown -R www-data:www-data media/
sudo chown www-data:users ./
sudo chown -R team:users media/
sudo chown -R team:users ./
# Recarregue e habilite os serviços
echo "Enabling services"
sudo systemctl daemon-reload
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Ativar módulos Apache
echo "Enabling apache2"
sudo a2enmod rewrite
sudo a2enmod wsgi
sudo a2enmod headers
sudo a2enmod ssl
sudo a2enmod proxy
sudo a2enmod proxy_balancer
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel
# Recarregue o daemon e reinicie o Apache, Postfix e Opendkim
sudo systemctl daemon-reload
sudo systemctl restart apache2
sudo systemctl restart opendkim postfix
# Mostre IPv6 e OpendKim para configuração de domínio
echo "COPY the below information to domain configuration."
hostname -I
ip a | grep inet
ip -6 addr | grep "scope link"
Antes de executar esse código, verifique se o domínio que você comprou está conectado ao servidor. Para fazer isso, abra um terminal em sua máquina local e execute este comando com seu domínio:

ping femmebabe.com # Insira seu domínio aqui, depois de ping
Se tudo parecer bem e o servidor estiver enviando respostas, estamos prontos para executar o script e instalar pacotes, além de iniciar, ativar e certificar nosso servidor Apache. Esta não é toda a configuração necessária para configurar o Postfix, examinaremos essa configuração mais tarde. Por enquanto, execute este código de configuração e deve levar alguns minutos para instalar e certificar seu servidor. Mais uma vez, substitua o nome, o email e o nome de domínio no script de acordo com o nome que você comprou. Agora que o servidor está provisionado, você pode ir ao URL em qualquer navegador da Web e verificar para garantir que o servidor esteja executando o HTTPS. Caso contrário, tente esperar um pouco para os registros do DNS recuperar o atraso e execute o seguinte comando para repetir a certificação CertBot:

sudo certbot --apache --non-interactive --agree-tos --domains <domain>.com --email <youremail>@gmail.com
Desde que você tenha configurado tudo corretamente, poderá acessar a página padrão do Apache apenas para saber que seu código está funcionando e exibindo uma página da Web ao vivo. Em seguida, vamos editar o Settings.py para alterar nosso modo de depuração padrão para produção. Também configuraremos o domínio nas configurações, bem como os IPs internos.

nano yourproject/settings.py
Nas configurações, altere/adicione essas linhas.

DEBUG = False

# Config do site
SITE_NAME = 'Femme Babe'
PROTOCOL = 'https'
DOMAIN = 'femmebabe.com'
SITE_ID = 1
BASE_URL = PROTOCOL + '://' + DOMAIN
ALLOWED_HOSTS = [DOMAIN]

INTERNAL_IPS = [
    'XX.XX.XX.XX',
]
Agora, precisaremos configurar o Apache2. Vamos editar o arquivo de configuração que implantaremos com esta linha:

sudo nano /etc/apache2/sites-available/femmebabe-le-ssl.conf
Este arquivo de configuração deve ter nosso nome de domínio e o nome do usuário e do projeto. Estou usando o nome de domínio femmebabe.com, a equipe de nome de usuário e o nome do projeto FemMebabe.

ServerSignature Off
ServerTokens Prod
<IfModule mod_ssl.c>
<VirtualHost *:80> 
	Redirect permanent / https://femmebabe.com/
</VirtualHost>
<VirtualHost *:443>
	ServerName femmebabe.com
	ServerAdmin team@femmebabe.com
	DocumentRoot /var/www/html

	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined
	
	Alias /static /home/team/femmebabe/static
	<Directory /home/team/femmebabe/static>
		Require all granted
	</Directory>

Alias /media/icons /home/team/femmebabe/media/
<Directory /home/team/femmebabe/media>
Require all granted
</Directory>

	<Directory /home/team/femmebabe/femmebabe>
		<Files wsgi.py>
			Require all granted
		</Files>
	</Directory>

	WSGIScriptAlias / /home/team/femmebabe/femmebabe/wsgi.py
	WSGIDaemonProcess femmebabe python-path=/home/team/femmebabe/ python-home=/home/team/femmebabe/venv header-buffer-size=100000000000 user=team
	WSGIProcessGroup femmebabe
	WSGIApplicationGroup %{GLOBAL}
	
	<Directory /home/team/femmebabe/static>
                Options Indexes FollowSymLinks
                AllowOverride All
	</Directory>

	<IfModule mod_rewrite.c>
		RewriteEngine on
		RewriteCond %{REQUEST_URI} \.(css|webp|webm|gif|png|mp3|wav|jpeg|jpg|svg|webp)$ [NC]
		RewriteCond %{HTTP_REFERER} !^https://femmebabe.com/media/.*$ [NC]
		RewriteRule ^(.+?)/$ /media/$1 [F,L]
	</IfModule>

	Include /etc/letsencrypt/options-ssl-apache.conf
	SSLCertificateFile /etc/letsencrypt/live/femmebabe.com/fullchain.pem
	SSLCertificateKeyFile /etc/letsencrypt/live/femmebabe.com/privkey.pem

	Header set X-Frame-Options: "SAMEORIGIN"
	Header set Access-Control-Allow-Origin "https://femmebabe.com"

	TimeOut 60000
	LimitRequestBody 0

	<FilesMatch ".(ico|pdf|flv|jpg|jpeg|png|gif|webp|JPG|JPEG|wav|mp3|mp4|public|js|css|swf|webp|svg)$">
		Header set Cache-Control "max-age=30, public"
	</FilesMatch>
</VirtualHost>
</IfModule>
<IfModule mod_ssl.c>
<VirtualHost *:80>
	ServerName femmebabe.com
	ServerAdmin team@femmebabe.com
	DocumentRoot /var/www/html

	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined

	RewriteEngine on
	RewriteCond %{SERVER_NAME} =femmebabe.com
	RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
</IfModule>
Certifique -se de substituir o nome do projeto, diretórios e domínio neste código de exemplo ao configurar seu servidor. Agora, precisaremos desativar o site padrão. Isso pode ser feito usando Bash.

sudo a2dissite 000-default-le-ssl
sudo a2dissite 000-default
sudo a2dissite default-ssl
Em seguida, podemos ativar o site padrão e recarregar o Apache2, também usando o Bash. Lembre-se de substituir o FEMMEBABE pelo nome do arquivo que você declarou ao editar em/etc/apache2/sites que estão disponíveis/.

sudo a2ensite femmebabe-le-ssl
sudo systemctl reload apache2
Volte ao seu domínio na barra de navegação. Você deve ver o site que você configurou no seu navegador da web. Parabéns! Se você não vê, pode ser necessário fazer algumas alterações. Revise cuidadosamente as configurações do seu projeto, a configuração do Apache e verifique se não tem erros e execute os seguintes comandos para verificar o projeto quanto a erros.

cd projectname
source venv/bin/activate
python manage.py check
Se você tiver erros no seu projeto Python, rastreá -los até onde eles estão e consertá -los. Você pode não ser capaz de ver todos os seus erros, dependendo de onde eles estão; portanto, se você tiver um erro que simplesmente diz que "Popular não é reentrante", edite o seguinte arquivo no ambiente virtual, Registry.py, para expor o erro.

nano venv/lib/python3.12/site-packages/django/apps/registry.py
Role até a linha 83, onde esse erro de tempo de execução é levantado (Rostre o RuntimeError (“POPULE () não é reentrante”)), e adicione um comentário antes dessa linha e, em seguida, adicionando, com o mesmo recuo, self.app_configs = {}. Parece o seguinte:

            if self.loading:
                # Evite chamadas reentrantes para evitar a execução do appConfig.ready ()
                # Métodos duas vezes.
# Raise RuntimeError ("POPULE () não é reentrante")
                self.app_configs = {}
            self.loading = True
Você pode verificar o projeto novamente e expor o erro.

python manage.py check
Então você pode ver o erro e corrigi -lo. Quando você o tiver corrigido e o código compila sem erros, altere o arquivo de volta para que pareça assim:

            if self.loading:
                # Evite chamadas reentrantes para evitar a execução do appConfig.ready ()
                # Métodos duas vezes.
                raise RuntimeError("populate() isn't reentrant")
# self.app_configs = {}
            self.loading = True
Desde que o servidor esteja online, quando fizermos mais alterações, precisamos usar o seguinte comando para recarregar o servidor:

sudo systemctl reload apache2
Incrível! Mas que tal enviar e -mail? Para começar a enviar email, primeiro precisaremos atualizar a configuração do domínio. Isso deve estar no seu painel DNS no Squarespace, ou qualquer registrador de nome de domínio que você escolher. Também precisaremos instalar e adicionar configuração e executar alguns comandos. Primeiro, vamos obter o endereço IPv6 do servidor. Em seguida, abriremos seu DNS e adicionaremos os registros. Para obter o endereço IPv6 do servidor, use este comando:

ip -6 addr
Agora, podemos adicionar os seguintes registros às configurações do DNS. Meus registros são assim. No entanto, para seus registros, você deve substituir o endereço IP pelo seu IP (não 75.147.182.214, isso é meu). Adicione também seu domínio no lugar do femmebabe.com, bem como seu endereço IPv6 encontrado com o comando anterior (você não pode usar o meu, FE80 :: 725A: FFF: FE49: 3E02). Não se preocupe com o domainkey por enquanto, isso é criado quando configuramos o Postfix, o servidor de correio, com o Opendkim e imprimimos a chave. Vamos configurar este último. @ UM N / D 75.147.182.214 @ Mx 10 femmebabe.com @ Ptr N / D femmebabe.com @ TXT N / D Txt @ v = spf1 mx ip75.147.182.214ip6: fe80 :: 725a: fff: fe49: 3e02 ~ all default._bimi TXT N / D v = bimi1; l = https: //femmebabe.com/media/static/femmebabe.svg _dmarc TXT N / D v = dMarc1; P = Nenhum Sendonly._DomainKey TXT N / DAgora, precisaremos adicionar uma configuração persistente para o Postfix. Tudo o que precisamos fazer é garantir que substituamos o nome do domínio, femmebabe.com, com o nome de domínio que você está usando. Vejamos todos os arquivos de configuração um por um e instale -os em um diretório chamado Config em nosso projeto, para instalar no sistema operacional.

nano config/etc_postfix_main.cf
Adicione este texto ao arquivo

# Veja /usr/share/postfix/main.cf.dist para uma versão comentada e mais completa


# Debian específico: especificar um nome de arquivo causará o primeiro
# linha desse arquivo a ser usada como nome.  O padrão do Debian
# é /etc /mailname.
# Myorigin = /etc /MailName

smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
biff = no

# Anexando .Domain é o trabalho do MUA.
append_dot_mydomain = no

# Descomamento A próxima linha para gerar avisos de "e -mail atrasado"
# telto_warning_time = 4h

readme_directory = no

# Consulte http://www.postfix.org/compatibility_readme.html - padrão para 3.6 em
# instalações frescas.
compatibility_level = 3.6



# Parâmetros TLS
smtpd_tls_cert_file=/etc/letsencrypt/live/femmebabe.com/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/femmebabe.com/privkey.pem
smtpd_tls_security_level=may

smtp_tls_CApath=/etc/ssl/certs
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

smtpd_relay_restrictions = permit_sasl_authenticated, defer_unauth_destination
myhostname = femmebabe.com
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = /etc/mailname
mydestination = femmebabe.com, localhost, $myhostname
smtp_helo_name = femmebabe.com
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
inet_protocols = all

# Configuração Milter
milter_default_action = accept
milter_protocol = 6
smtpd_milters = local:/opendkim/opendkim.sock
non_smtpd_milters = $smtpd_milters

smtp_tls_security_level = encrypt
smtp_tls_loglevel = 1

virtual_transport=lmtp:unix:private/dovecot-lmtp

smtpd_sasl_path = private/auth
Próxima configuração!

nano config/etc_postfix_master.cf
Adicione estas linhas:

# 
# Arquivo de configuração do processo mestre pós -fix.  Para detalhes sobre o formato
# do arquivo, consulte a página manual mestre (5) (comando: "homem 5 mestre" ou
# On-line: http://www.postfix.org/master.5.html).
# 
# Não se esqueça de executar "Reload Postfix" após editar este arquivo.
# 
# =================================================== =========================
# Tipo de serviço privado Unn Unsriv chroot wakeup maxproc comando + args
# (sim) (sim) (não) (nunca) (100)
# =================================================== =========================
smtp      inet  n       -       y       -       -       smtpd
# SMTP INET N - Y - 1 Post -Screen
# SMTPD PASS - - Y - - SMTPD
# Dnsblog Unix - - y - 0 dnsblog
# Tlsproxy Unix - - y - 0 tlsproxy
# Escolha um: Ative o envio apenas para clientes de loopback ou para qualquer cliente.
# 127.0.0.1:Submission INET N - Y - - SMTPD
submission inet n       -       y       -       -       smtpd
  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_tls_wrappermode=no
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_sasl_type=dovecot
  -o smtpd_sasl_path=private/auth
# -o syslog_name = postfix/submissão
# -o smtpd_tls_security_level = Encrypt
# -o smtpd_sasl_auth_enable = sim
# -o smtpd_tls_auth_only = sim
# -o smtpd_reject_unlisted_recipient = não
# -O smtpd_client_restictions = $ mua_client_restictions
# -o smtpd_helo_restictions = $ mua_helo_restictions
# -o smtpd_sender_restictions = $ mua_sender_restictions
# -o smtpd_recipient_trival =
# -o smtpd_relay_restictions = permit_sasl_authenticated, rejeite
#   -o milter_macro_daemon_name=ORIGINATING
# Escolha um: Ative SMTPs apenas para clientes de loopback ou para qualquer cliente.
# 127.0.0.1:SMTPS INET N - Y - - SMTPD
# SMTPS INET N - Y - - SMTPD
# -o syslog_name = postfix/smtps
# -o smtpd_tls_wragermode = sim
# -o smtpd_sasl_auth_enable = sim
# -o smtpd_reject_unlisted_recipient = não
# -O smtpd_client_restictions = $ mua_client_restictions
# -o smtpd_helo_restictions = $ mua_helo_restictions
# -o smtpd_sender_restictions = $ mua_sender_restictions
# -o smtpd_recipient_restictions =
# -o smtpd_relay_restictions = permit_sasl_authenticated, rejeite
#   -o milter_macro_daemon_name=ORIGINATING
# 628 INET N - Y - - QMQPD
pickup    unix  n       -       y       60      1       pickup
cleanup   unix  n       -       y       -       0       cleanup
qmgr      unix  n       -       n       300     1       qmgr
# qmgr unix n - n 300 1 oqmg
tlsmgr    unix  -       -       y       1000?   1       tlsmgr
rewrite   unix  -       -       y       -       -       trivial-rewrite
bounce    unix  -       -       y       -       0       bounce
defer     unix  -       -       y       -       0       bounce
trace     unix  -       -       y       -       0       bounce
verify    unix  -       -       y       -       1       verify
flush     unix  n       -       y       1000?   0       flush
proxymap  unix  -       -       n       -       -       proxymap
proxywrite unix -       -       n       -       1       proxymap
smtp      unix  -       -       y       -       -       smtp
relay     unix  -       -       y       -       -       smtp
        -o syslog_name=postfix/$service_name
# -o smtp_helo_timeout = 5 -o smtp_connect_timeout = 5
showq     unix  n       -       y       -       -       showq
error     unix  -       -       y       -       -       error
retry     unix  -       -       y       -       -       error
discard   unix  -       -       y       -       -       discard
local     unix  -       n       n       -       -       local
virtual   unix  -       n       n       -       -       virtual
lmtp      unix  -       -       y       -       -       lmtp
anvil     unix  -       -       y       -       1       anvil
scache    unix  -       -       y       -       1       scache
postlog   unix-dgram n  -       n       -       1       postlogd
# 
# =================================================== ==================
# Interfaces no software não-postfix. Certifique -se de examinar o manual
# Páginas do software não-postfix para descobrir quais opções ele deseja.
# 
# Muitos dos seguintes serviços usam a entrega do Postfix Pipe (8)
# agente.  Veja o tubo (8) Página da mulher para obter informações sobre $ {destinatário}
# e outras opções de envelope de mensagens.
# =================================================== ==================
# 
# Maildrop. Consulte o arquivo postfix Maildrop_readme para obter detalhes.
# Especifique também em main.cf: MailDrop_Destination_recipient_limit = 1
# 
maildrop  unix  -       n       n       -       -       pipe
  flags=DRXhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
# 
# =================================================== ==================
# 
# As versões recentes do Cyrus podem usar a entrada "LMTP" Master.CF existente.
# 
# Especifique em cyrus.conf:
# lmtp cmd = "lmtpd -a" escuta = "localhost: lmtp" proto = tcp4
# 
# Especifique em main.cf um ou mais dos seguintes:
# Mailbox_transport = LMTP: INET: localhost
# Virtual_transport = lmtp: INET: localhost
# 
# =================================================== ==================
# 
# Cyrus 2.1.5 (Amos Gouaux)
# Especifique também em main.cf: cyrus_destination_recipient_limit = 1
# 
# Cyrus Unix - N N - - Pipe
# sinalizadores = drx user = cyrus arg =/cyrus/bin/entrega -e -r $ {sender} -m $ {extension} $ {user}
# 
# =================================================== ==================
# Exemplo antigo de entrega via Cyrus.
# 
# Old -cyrus unix - n n - - tubo
# Sinalizadores = r usuário = cyrus argv =/cyrus/bin/entrega -e -m $ {extension} $ {user}
# 
# =================================================== ==================
# 
# Consulte o arquivo pós -fix uucp_readme para obter detalhes de configuração.
# 
uucp      unix  -       n       n       -       -       pipe
  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
# 
# Outros métodos de entrega externa.
# 
ifmail    unix  -       n       n       -       -       pipe
  flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
bsmtp     unix  -       n       n       -       -       pipe
  flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
scalemail-backend unix -       n       n       -       2       pipe
  flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
mailman   unix  -       n       n       -       -       pipe
  flags=FRX user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py ${nexthop} ${user}
E a configuração do Opendkim. O Opendkim identifica servidores de email com teclas de domínio para torná -las mais seguras. Sem ele, o correio não é assinado e pode não chegar a uma caixa de entrada.

nano config/etc_default_opendkim
Adicione estas linhas:

# Nota: Este é um arquivo de configuração herdado. Não é usado pelo Opendkim
# Systemd Service. Por favor, use os parâmetros de configuração correspondentes em
# /etc/opendkim.conf em vez disso.
# 
# Anteriormente, alguém editaria as configurações padrão aqui e depois executou
# /lib/opendkim/opendkim.service.gereate para gerar arquivos de substituição do Systemd para
# /etc/systemd/system/opendkim.service.d/override.conf e
# /etc/tmpfiles.d/opendkim.conf. Embora isso ainda seja possível, agora é
# Recomendado para ajustar as configurações diretamente em /etc/opendkim.conf.
# 
# Daemon_Opts = ""
# Alterar para/var/spool/postfix/run/opendkim para usar um soquete UNIX com
# Postfix em um chroot:
# Rúndir =/was/spool/pósfix/run/opendkim
RUNDIR=/run/opendkim
# 
# Descomamento para especificar um soquete alternativo
# Observe que a definição disso substituirá qualquer valor de soquete em opendkim.conf
# padrão:
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
# Ouça em todas as interfaces na porta 54321:
# Socket = Inet: 54321
# Ouça no loopback na porta 12345:
# Socket = Inet: 12345@localhost
# Ouça é 192.0.2.1 é a porta 12345:
# Socket = Inet: 12345@192.0.2.1
USER=opendkim
GROUP=opendkim
PIDFILE=$RUNDIR/$NAME.pid
EXTRAAFTER=

nano config/etc_dovecot_conf.d_10-master.conf
Adicione estas linhas:

0-master.conf 
# default_process_limit = 100
# default_client_limit = 1000

# Limite padrão VSZ (tamanho da memória virtual) para processos de serviço. Isso é principalmente
# destinado a capturar e matar processos que vazam memória antes que eles consomem
# tudo.
# default_vsz_limit = 256m

# O usuário de login é usado internamente pelos processos de login. Este é o mais não confiável
# Usuário no sistema dovecot. Não deve ter acesso a nada.
# default_login_user = Dovenull

# O usuário interno é usado por processos não privilegiados. Deve ser separado de
# Login Usuário, para que os processos de login não possam perturbar outros processos.
# default_internal_user = Dovecot

service imap-login {
  inet_listener imap {
    # Porta = 143
  }
  inet_listener imaps {
    # Porta = 993
    # ssl = sim
  }

  # Número de conexões para lidar antes de iniciar um novo processo. Tipicamente
  # Os únicos valores úteis são 0 (ilimitado) ou 1. 1 é mais seguro, mas 0
  # é mais rápido. <doc/wiki/loginprocess.txt>
  # Service_Count = 1

  # Número de processos para sempre continuar esperando por mais conexões.
  # Process_min_avail = 0

  # Se você definir o serviço_count = 0, provavelmente precisará cultivar isso.
  # vsz_limit = $ default_vsz_limit
}

service pop3-login {
  inet_listener pop3 {
    # Porta = 110
  }
  inet_listener pop3s {
    # Porta = 995
    # ssl = sim
  }
}

service submission-login {
  inet_listener submission {
    # Porta = 587
  }
}

service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    group = postfix
    mode = 0666
    user = postfix
  }

  # Crie o ouvinte INET SOMENTE se você não puder usar o soquete UNIX acima
  # inet_lister lmtp {
    # Evite tornar o LMTP visível para toda a Internet
    # Endereço =
    # porta =
  # }
}

service imap {
  # A maior parte da memória vai para os arquivos mmap () ing. Você pode precisar aumentar isso
  # Limite se você tiver grandes caixas de correio.
  # vsz_limit = $ default_vsz_limit

  # Máx. Número de processos IMAP (conexões)
  # Process_limit = 1024
}

service pop3 {
  # Máx. Número de processos POP3 (conexões)
  # process_limit = 1024
}

service submission {
  # Máx. Número de processos de submissão SMTP (conexões)
  # process_limit = 1024
}

service auth {
  # auth_socket_path aponta para este soquete do userDB por padrão. É normalmente
  # usado por Dovecot-LDA, DoVeadm, Possivelmente Processo IMAP, etc. Usuários que têm
  # Permissões completas para este soquete podem obter uma lista de todos os nomes de usuário e
  # Obtenha os resultados das pesquisas do UserDB de todos.
  # 
  # O modo padrão 0666 permite que qualquer pessoa se conecte ao soquete, mas o
  # As pesquisas do userDB serão bem -sucedidas apenas se o UserDB retornar um campo "UID" que
  # corresponde ao UID do processo de chamadas. Também se o UID ou GID do chamador corresponder ao
  # UID ou GID da soquete, a pesquisa é bem -sucedida. Qualquer outra coisa causa uma falha.
  # 
  # Para dar ao chamador permissões completas para procurar todos os usuários, defina o modo como
  # outra coisa que 0666 e Dovecot permite que o kernel faça
  # Permissões (por exemplo, 0777 permite a todos as permissões completas).
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix
  }
}

service auth-worker {
  # O processo do trabalhador auth é executado como root por padrão, para que possa acessar
  # /etc/sombra. Se isso não for necessário, o usuário deve ser alterado para
  # $ default_interal_user.
  # Usuário = root
}

service dict {
  # Se o proxy do dicto for usado, os processos de email devem ter acesso ao seu soquete.
  # Por exemplo: modo
  unix_listener dict {
    # mode = 0600
    # Usuário =
    # grupo =
  }
}
Mais uma vez, substitua o domínio em todos esses arquivos, femmebabe.com, com o domínio que você selecionou. Edite o próximo arquivo, a configuração de Dovecot,

nano config/etc_dovecot_dovecot
E adicione essas linhas

## Arquivo de configuração Ovecot

# Se você estiver com pressa, consulte http://wiki2.dovecot.org/quickconfiguration

# O comando "DoveConf -n" fornece uma saída limpa das configurações alteradas. Use -o
# Em vez de copiar e colar arquivos ao postar na lista de discussão do Dovecot.

# '# O personagem e tudo depois de ser tratado como comentários. Espaços extras
# e as guias são ignoradas. Se você quiser usar qualquer um deles explicitamente, coloque o
# value inside quotes, eg.: key = "# Char e Whitespace de direita "

# A maioria das configurações (mas não todas) pode ser substituída por diferentes protocolos e/ou
# IPS de origem/destino colocando as configurações dentro das seções, por exemplo:
# Protocolo IMAP {}, local 127.0.0.1 {}, remoto 10.0.0.0/8 {}

# Os valores padrão são mostrados para cada configuração, não é necessário para o descomamento
# aqueles. Essas são exceções a isso: nenhuma seção (por exemplo, espaço para nome {})
# ou as configurações do plug -in são adicionadas por padrão, elas são listadas apenas como exemplos.
# Caminhos também são apenas exemplos, com os padrões reais sendo baseados na configuração
# opções. Os caminhos listados aqui são para configurar - -prefix =/usr
# --sysConfdir =/etc--LocalStatedir =/var

# Ativar protocolos instalados
!include_try /usr/share/dovecot/protocols.d/*.protocol

# Uma lista separada por vírgula de IPs ou hosts onde ouvir as conexões.
# "*" ouve todas as interfaces IPv4 "::" ouve todas as interfaces IPv6.
# Se você deseja especificar portas não padrão ou qualquer coisa mais complexa,
# Edit conf.d/master.conf.
# Ouça = *, ::

# Diretório base onde armazenar dados de tempo de execução.
# base_dir =/var/run/dovecot/

# Nome desta instância. Em configuração multi-instância DoVeadm e outros comandos
# pode usar -i <instância_name> para selecionar qual instância é usada (uma alternativa
# para -c <config_path>). O nome da instância também é adicionado aos processos dovecot
# na saída do PS.
# Instance_name = Dovecot

# Mensagem de cumprimento para clientes.
# login_greeting = Dovecot pronto.

# Lista separada do espaço de faixas de rede confiáveis. Conexões destes
# Os IPs podem substituir seus endereços e portas IP (para registro e
# para verificações de autenticação). desabille_plaintext_auth também é ignorado para
# essas redes. Normalmente, você especificaria seus servidores IMAP proxy aqui.
# login_trusted_networks =

# Lista separada pelo espaço de soquetes de verificação de acesso ao login (por exemplo, TCPWRAP)
# login_access_sockets =

# Com proxy_maybe = sim se o destino de proxy corresponder a algum desses ips, não faça
# proxying. Isso não é necessário normalmente, mas pode ser útil se o destino
# IP é, por exemplo O IP de um balanceador de carga.
# auth_proxy_self =

# Mostre mais títulos de processo detalhados (no PS). Atualmente mostra o nome de usuário e
# Endereço IP. Útil para ver quem está realmente usando os processos IMAP
# (por exemplo, caixas de correio compartilhadas ou se o mesmo UID for usado para várias contas).
# verbose_proctitle = não

# Se todos os processos forem mortos quando o processo master do DOVECOT se desligar.
# Definir isso como "não" significa que o Dovecot pode ser atualizado sem
# forçar as conexões existentes do cliente a fechar (embora isso também possa ser
# Um problema se a atualização for, por exemplo por causa de uma correção de segurança).
# Shutdown_clients = Sim

# Se diferente de zero, execute os comandos de email por meio dessas conexões para o servidor DoVeadm,
# Em vez de executá -los diretamente no mesmo processo.
# doveadm_worker_count = 0
# Soquete ou host Unix: porta usada para conectar -se ao servidor doveadm
# Doveadm_socket_path = doveadm servidor

# Lista separada por espaço de variáveis ​​de ambiente que são preservadas no Dovecot
# Startup e passou para todos os seus processos infantis. Você também pode dar
# chave = pares de valor para sempre definir configurações específicas.
# Import_environment = tz

## 
## Configurações do servidor de dicionário
## 

# O dicionário pode ser usado para armazenar listas de key = value. Isso é usado por vários
# plugins. O dicionário pode ser acessado diretamente ou embora um
# servidor de dicionário. Os seguintes nomes de dicionário de mapas de bloco de dicto para Uris
# Quando o servidor é usado. Estes podem então ser referenciados usando URIs em formato
# "Proxy :: <nome>".

dict {
  # Quota = mysql: /etc/dovecot/dovecot-dict-sql.conf.ext
}

# A maior parte da configuração real é incluída abaixo. Os nomes de arquivos são
# primeiro classificado pelo seu valor ASCII e analisado nessa ordem. Os prefixos 00
# Nos nomes de arquivos, pretende facilitar a compreensão da ordem.
!include conf.d/*.conf

# Um arquivo de configuração também pode tentar ser incluído sem dar um erro se
# Não é encontrado:
!include_try local.conf

passdb {
  driver = passwd-file
  args = /etc/dovecot/passwd
}
userdb {
  driver = passwd
}

protocols = imap pop3

# Permite que o Dovecot ouça todas as conexões de entrada (IPv4 / IPv6)

listen = *, ::
Adicione uma senha para o usuário dovecot:

nano config/etc_dovecot_passwd
A primeira parte do arquivo, antes do cólon, é o nome de usuário. A última parte, "YourPassword", indica a senha que você gostaria de dar ao seu servidor de e -mail.

team:{plain}yourpassword
Em seguida, a configuração de Opendkim

nano config/etc_opendkim.conf
E adicione estas linhas:

# Esta é uma configuração básica para assinar e verificar. Pode ser facilmente
# adaptado para se adequar a uma instalação básica. Veja opendkim.conf (5) e
# /usr/share/doc/opendkim/examples/opendkim.conf.sample para completo
# Documentação dos parâmetros de configuração disponíveis.

Syslog			yes
SyslogSuccess		yes
# Logwhy não

# Parâmetros comuns de assinatura e verificação. Em Debian, o cabeçalho "de" é
# Oversenhado, porque geralmente é a chave de identidade usada por sistemas de reputação
# e, portanto, um pouco sensível à segurança.
Canonicalization	relaxed/simple
Mode			s
SubDomains		no
OversignHeaders		From

# Assinando domínio, seletor e chave (obrigatório). Por exemplo, executar a assinatura
# para domínio "exemplo.com" com seletor "2020" (2020._domainkey.example.com),
# Usando a chave privada armazenada em /etc/dkimkeys/example.private. Mais granular
# As opções de configuração podem ser encontradas em /usr/share/doc/opendkim/readme.opendkim.
# Domain			example.com
# Seletor 2020
# Keyfile /etc/dkimkeys/example.private

# No Debian, o Opendkim é executado como o usuário "Opendkim". Um UMASK de 007 é necessário quando
# Usando um soquete local com MTAs que acessam o soquete como um não privilegiado
# usuário (por exemplo, postfix). Pode ser necessário adicionar "Postfix" do usuário ao grupo
# "Opendkim" nesse caso.
UserID			opendkim
UMask			007

# Soquete para a conexão MTA (necessária). Se o MTA estiver dentro de uma prisão de chroot,
# Deve -se garantir que o soquete esteja acessível. No Debian, o Postfix está
# um chroot in/var/spool/postfix, portanto um soquete Unix teria que ser
# configurado como mostrado na última linha abaixo.
# Socket Local: /run/opendkim/opendkim.sock
# Socket Inet: 8891@localhost
# Socket Inet: 8891
Socket			local:/var/spool/postfix/opendkim/opendkim.sock

PidFile			/run/opendkim/opendkim.pid

# Os hosts para assinar em vez de verificar, o padrão é 127.0.0.1. Veja o
# Seção de operação do Opendkim (8) para obter mais informações.
# InternalHosts 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12

# A âncora de confiança permite o DNSSEC. No Debian, o arquivo âncora do Trust é fornecido
# pelo pacote DNS-Root-Data.
TrustAnchorFile		/usr/share/dns/root.key
# Names servidores 127.0.0.1

# Domínios de mapa de endereços para chaves usadas para assinar mensagens
KeyTable           refile:/etc/opendkim/key.table
SigningTable       refile:/etc/opendkim/signing.table

# Um conjunto de hosts internos cujo correio deve ser assinado
InternalHosts       /etc/opendkim/trusted.hosts

nano config/etc_default_opendkim
E adicione essas linhas

# Nota: Este é um arquivo de configuração herdado. Não é usado pelo Opendkim
# Systemd Service. Por favor, use os parâmetros de configuração correspondentes em
# /etc/opendkim.conf em vez disso.
# 
# Anteriormente, alguém editaria as configurações padrão aqui e depois executou
# /lib/opendkim/opendkim.service.gereate para gerar arquivos de substituição do Systemd para
# /etc/systemd/system/opendkim.service.d/override.conf e
# /etc/tmpfiles.d/opendkim.conf. Embora isso ainda seja possível, agora é
# Recomendado para ajustar as configurações diretamente em /etc/opendkim.conf.
# 
# Daemon_Opts = ""
# Alterar para/var/spool/postfix/run/opendkim para usar um soquete UNIX com
# Postfix em um chroot:
# RúnDir =/var/spool/postfix/run/opendkim
RUNDIR=/run/opendkim
# 
# Descomamento para especificar um soquete alternativo
# Observe que a definição disso substituirá qualquer valor de soquete em opendkim.conf
# padrão:
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
# Ouça em todas as interfaces na porta 54321:
# Socket = Inet: 54321
# Ouça no loopback na porta 12345:
# Socket = Inet: 12345@localhost
# Ouça é 192.0.2.1 é a porta 12345:
# Socket = Inet: 12345@192.0.2.1
USER=opendkim
GROUP=opendkim
PIDFILE=$RUNDIR/$NAME.pid
EXTRAAFTER=
Quando estivermos prontos para configurar nosso servidor Postfix, executaremos o código abaixo, com o nome de domínio apropriado incorporado. Comece criando um script

touch scripts/postfixsetup
sudo chmod a+x scripts/postfixsetup
nano scripts/postfixsetup
Agora, em Nano, o editor de texto, edite este arquivo para incluir seu nome de domínio em vez do femmebabe.com.

# !
# Configurar postfix
cd $DIR
echo "Mail services configuration"
sudo cp /etc/postfix/main.cf /etc/postfix/main.cf.backup
sudo cp config/etc_postfix_main.cf /etc/postfix/main.cf
sudo cp config/etc_postfix_master.cf /etc/postfix/master.cf
sudo cp config/etc_default_opendkim /etc/default/opendkim
sudo cp config/etc_dovecot_conf.d_10-auth.conf /etc/dovecot/conf.d/10-auth.conf
sudo cp config/etc_dovecot_conf.d_10-master.conf /etc/dovecot/conf.d/10-master.conf
sudo cp config/etc_dovecot_dovecot.conf /etc/dovecot/dovecot.conf
sudo cp config/etc_dovecot_passwd /etc/dovecot/passwd
sudo cp config/etc_opendkim.conf /etc/opendkim.conf
sudo cp config/etc_default_opendkim /etc/default/opendkim
sudo adduser postfix opendkim
sudo mkdir /etc/opendkim
sudo mkdir /etc/opendkim/keys
sudo mkdir /etc/opendkim/keys/femmebabe.com
sudo mkdir /var/spool/postfix/opendkim
sudo echo "*@femmebabe.com     sendonly._domainkey.femmebabe.com" | sudo tee -a /etc/opendkim/signing.table
sudo echo "sendonly._domainkey.femmebabe.com    femmebabe.com:sendonly:/etc/opendkim/keys/femmebabe.com/sendonly.private" | sudo tee -a /etc/opendkim/key.table
sudo echo "127.0.0.1" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "localhost" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "*.femmebabe.com" | sudo tee -a /etc/opendkim/trusted.hosts
sudo chown -R opendkim:opendkim /etc/opendkim
sudo opendkim-genkey -b 2048 -d femmebabe.com -D /etc/opendkim/keys/femmebabe.com -s sendonly -v
sudo chmod go-rw /etc/opendkim/keys
sudo chown opendkim:opendkim /etc/opendkim/keys/femmebabe.com/sendonly.private
sudo chown opendkim:postfix /var/spool/postfix/opendkim
cd $DIR
sudo cp mailbox/* /var/mail/
sudo chown :users /var/mail/*
sudo chmod -R a+rwx /var/mail/*
sudo systemctl restart opendkim postfix dovecot
sudo cat /etc/opendkim/keys/femmebabe.com/sendonly.txt | tr -d '\n' | sed 's/\s//g' | sed 's/""//g' | awk -F'[)(]' '{print $2}'
Agora, execute o script preenchido para configurar o Postfix, Opendkim e Dovecot.

./scripts/postfixsetup
Depois que este script estiver executado, copie a última linha, ele imprime e coloque -o na configuração do DNS como o valor para sendOnly._DomainKey. Esta é a tecla Opendkim usada para identificar seu domínio ao enviar e -mails seguros. Incrível! Dentro de alguns dias, você poderá enviar e -mails do servidor, desde que tudo esteja configurado corretamente. Se você acabou de configurar o DNS para o seu servidor de email, levará menos de 72 horas para que os registros sejam atualizados. Geralmente é muito mais rápido. Você pode verificar se o seu servidor está funcionando usando este comando, fornecido seu e -mail:

echo “test” | mail -s “Test Email” youremail@gmail.com
Se tudo parecer estar funcionando corretamente, você poderá enviar email com seu servidor. Se não estiver funcionando, tente olhar para os logs para ver qual pode ser o erro.

tail –lines 150 /var/log/mail.log
Isso oferecerá informações detalhadas sobre o e -mail que está sendo enviado pelo servidor e se está funcionando corretamente. Você também deve ver o email em sua caixa de entrada, se não estiver lá, verifique sua pasta de spam. Você também precisará configurar suas configurações em seu configuração.py para que seu servidor de e -mail possa conversar com o seu aplicativo Django, o projeto. Adicione ou substitua essas linhas em suas configurações

EMAIL_HOST = DOMAIN
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_ADDRESS = 'team@femmebabe.com'
EMAIL_HOST_USER = 'team' # 'Love@mamasheen.com'
EMAIL_HOST_PASSWORD = config['EMAIL_HOST_PASSWORD']
DEFAULT_FROM_EMAIL = '{} <{}>'.format(SITE_NAME, EMAIL_HOST_USER)
Observe que estamos usando um arquivo de configuração para obter a senha. Vamos carregar esse arquivo nas configurações assim, no início do arquivo.:

import os
import json

# Abra e carregue configuração
with open('/etc/config.json') as config_file:
    config = json.load(config_file)
Vamos criar esse arquivo e adicionar uma chave secreta a ele, bem como a senha de email. Para gerar uma chave secreta, use este comando, com o tempo que você quiser no final:

openssl rand -base64 64
Agora, copie o texto que o OpenSSL gerou e edit /etc/config.json

sudo nano /etc/config.json
Adicione as seguintes linhas ao seu arquivo, com a chave que o OpenSSL gerou como a chave secreta.

{
	"SECRET_KEY": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX-generated-using-openssl)",
	"EMAIL_HOST_PASSWORD": "yourpassword"
}
O formato JSON é simples e fácil de usar, podemos declarar outras chaves que queremos usar em nosso projeto dessa maneira e mantê -las separadas do nosso diretório de projeto para que outros usuários não possam escrever para eles e para que não possam ser lidos Somente no nosso diretório de projetos. Isso é prática recomendada para as teclas da API, das quais usaremos mais do que alguns aqui. Você também deseja fazer backup do seu projeto para garantir que tudo esteja salvo e poderá recuperar seu trabalho mais tarde, mesmo que não deseje mais alugar um servidor.

sudo backup
Agora, tente enviar um email HTML do servidor da Web, desde que o envio de um da linha de comando esteja funcionando. Consulte a instância do seu usuário no shell e envie um email HTML para esse usuário através do Django. Mude meu nome no código, Charlotte, para seu nome de usuário.

python manage.py shell
from django.contrib.auth.models import User
u = User.objects.get(username='Charlotte')
from users.email import send_welcome_email
send_welcome_email(u)
exit()
Se o primeiro comando não funcionar, certifique -se de usar

source venv/bin/activate
Desde que tudo esteja configurado corretamente, agora você receberá um e -mail de boas -vindas em sua caixa de correio enviada pelo seu aplicativo da Web. Bom trabalho! Você percorreu um longo caminho. Eu queria acrescentar, se você estiver lutando com algum erro enquanto trabalha em um projeto como esse, não hesite em procurar respostas e pedir ajuda. O Google, entre outros mecanismos de pesquisa, são ótimos recursos para procurar ajuda de programação. Basta procurar o erro que está recebendo e você poderá ver como outras pessoas resolvem o problema. Além disso, você pode entrar em contato comigo, seus educadores (professores, professores, tutores), quaisquer colegas da Internet que estejam disponíveis para ajuda de programação ou consulte este livro novamente ou outros recursos para encontrar soluções para os problemas que você está enfrentando. Entendo que isso não é fácil, mas mesmo se você já leu até aqui e não está escrevendo nenhum código, está aprendendo muito sobre a criação de um aplicativo da web a partir do zero. Tapam -se nas costas, você está fazendo um ótimotrabalho. Obrigado por reservar um tempo para ler este Guia de Desenvolvimento da Web da Terceira Edição. Nas edições futuras, incluirei mais dos exemplos importantes discutidos no início do documento e mergulharemos muito mais profundamente no mundo do desenvolvimento de software e hardware. Fique atento ao que está por vir, e estou ansioso para ensiná -lo a criar software incrível. Vejo você no próximo






Fechar
Página 1
Pular
Veja o artigo completo
Continue lendo

Comprar | Compre com criptografia



https://glamgirlx.com/pt/practical-web-based-deep -


(Clique ou toque para baixar a imagem)
Entretenimento profissional, fotos, vídeos, áudio, transmissão ao vivo e jogabilidade casual, além de digitalização de ID, desenvolvimento da web e serviços de barriga de aluguel.

Deixe -me uma dica no Bitcoin usando este endereço: 3KhDWoSve2N627RiW8grj6XrsoPT7d6qyE

© Glam Girl X 2025

Termos de Serviço