Практическое веб-обучение и безопасность на примере

DaisyФотография профиля

К Daisy

Практическое веб -глубокое обучение и безопасность по примеру Третье издание Шарлотта Харпер 3 июля 2024 года Предисловие: Соображения безопасности в создании программного обеспечения для Интернета являются важной частью плана и выполнения любого веб -разработчика, в то время как создание прототипа, который является надежным, стабильным и полезным для практических целей. Dom (Markup объекта документа), с его реализацией HTML, JavaScript и CSS, а также бэкэнд -программного обеспечения, внедряющего Python, C/C ++, Java и Bash, дают веб -разработчикам свободу и силу для создания широкого спектра проектов, которые выражают экспресс. Творчество, обеспечивают простоту использования и функциональность, изображают смирение и характер, а также обеспечивают простоту использования, а также удобство и важные услуги, которые привлекательны для среднего Джо, конечный пользователь хочет убить время или сделайте что -нибудь в Интернете, обычно на смартфоне с сенсорным экраном. Большинство людей даже не знали бы, с чего начать, когда они хотят создать веб -сайт с нуля,Они склонны начинать с веб -сайта другого человека и создавать что -то ограниченное по функциональности, надежности, простоте использования и особенно творчества, когда у них могло быть все последние мощные инструменты в их распоряжении, чтобы создать что -то полезное, не теряя времени нажатия кнопок, и и Особенно тратить деньги, оплачивая дорогие подписки на программное обеспечение, которое мало кто хотел использовать, учитывая его ограничения в простоте использования и гибкости. Если у вас есть несколько минут, чтобы прочитать эту книгу и узнать, чему я хочу научить вас, или даже лично поговорить со мной о своих целях и получить некоторое руководство в правильном направлении, и вы мотивированы научиться кодировать и писать собственное программное обеспечение , возьмите эту книгу домой и отложите некоторое время, чтобы научиться создавать следующее влиятельное, мощное, оптимизированное и важное веб -приложение, веб -сайт, который все на вас и делает именно то, что вы хотите, и удовлетворяет потребности вашей аудитории. Обо мне: Я разработчик программного обеспечения с широкимAnge of Experience в C/C ++, Java, Python, HTML, CSS и JavaScript. Я строю веб -сайты, которые люди хотят использовать, хотят посетить и даже пристраститься к использованию просто для изучения, воссоздания и убивать время, и, что самое важное, я продаю программное обеспечение. Если у вас была идея относительно того, как именно вы хотели, чтобы веб -сайт выглядел и функционировал, вы были готовы поддержать меня, чтобы я мог удовлетворить свои собственные потребности, пока я удовлетворяю ваши, и вы готовы покрыть расходы на запуск веб -сайта, Я бы построил вам следующее YouTube, Tiktok, Twitter, Google или даже высокотехнологичное приложение безопасности, которое только вы можете получить. Вместо того, чтобы пытаться продать вам свое время, я пытаюсь купить ваше: я хочу рассказать вам о создании приложения (веб -сайт) с информацией, которая уже существует, и научить вас тому, что вам нужно, чтобы стать независимым разработчиком программного обеспечения, Предприниматель, возглавляя успешную карьеру в любой области, которую вы желаете. И позвольте мне прояснить, что образование, которое я вам даю, будет неформальным. Вы можете пойти в школу и узнать все это с помощьюRMAL Education или даже прочитайте эту книгу в школе, выполните свои задания и убирайте из вашего образования, но я официально не поставлю вас в горячее место и попрошу вас выполнить задания. Я не ваш профессор, вы можете думать обо мне, как о другом, который хочет направить вас к карьере, обусловленной вашим личным успехом. И я не продаю вам успех, вам нужно будет купить его со своим временем. Обучение коду имеет крутую кривую обучения и никогда не было легким или даже предполагалось. Вам нужно работать настолько усердно, насколько это возможно, и продолжать пытаться потерпеть неудачу и повторить попытку, даже когда вы разочарованы, чтобы учиться и создавать приложения самостоятельно. Это в природе самого кода. Код запускается компилятором, который предназначен для предоставления сообщений об ошибках программиста, и они научат вас, как кодировать, даже если вы просто копируете ошибку в свою поисковую систему и читаете примеры других людей. И я должен сказать, вам не нужно быть чрезвычайно богатым, умным, успешным,подробно ориентированы или организованы для создания приложения. Компьютер заботится об этой организации для вас. Вам просто нужно продолжить пробную версию и ошибки, поддерживать фокус и усердно работать над тем, что вы делаете, и у вас будет очень успешная карьера в целом, что вы делаете. Кто я: Я понимаю, что последний раздел был больше о обучении и вы, как вы берете на себя, из этой книги. Кто я именно? Это сложный вопрос. Я сам неясен, так как я страдаю от заболеваний, которые могут затруднить мне даже кодировать или писать эту книгу, в то же время представляя проблемы с проблемами социализации и идентичности, которые затрудняют мою жизнь, когда дело доходит до представления себя Полем Короче говоря, если вы читаете эту книгу, вы принесли ее домой, потому что вы пропустили ее и подумали, что это было полезно, или даже если вы просто читаете это далеко, для вас я похожий на единомышленник, который хочет видеть, что вы добились успеха в все, что вы делаете. Я сам инженер, программное обеспечениеРазработчик и студент, и я пишу эту книгу для других студентов, которые хотят облегчить свою жизнь, получив справочник по программному обеспечению, в котором им нужно упростить их жизнь, приводя примеры для копирования, которые соединяются, как большая головоломка в работу , полезное, большое, функциональное, сплоченное и привлекательное приложение, которое может добиться успеха независимо от линии бизнеса. Во многом это то, что я делаю: я строю приложения, чтобы помочь себе и другим людям добиться успеха. Я также автор, хотя это моя первая публикация, которую я намерен завершить, чтобы собрать свое портфель в полезный документ, и я тоже художник. Я признаю это вам, я своего рода странный человек. Я не идеален, у меня были законы, даже заставляя меня покинуть колледжи и университеты и покинуть штаты, чтобы попытаться сделать себе имя с большим успехом. Я женщина по рождению, я ношу макияж, фотографирую себя, ношу платья и другую женскую одежду, и я остаюсь осознавать себя какмужчина по природе. В прошлом у меня были проблемы с другими людьми, которые привели к борьбе с написанием и созданием веб -приложений, и я прошу прощения, что я не смог получить эту книгу раньше в руках: вам это нужно. Вы захотите прочитать и написать код, который выглядит как мой и работает как мой, и делает то же самое, но даже лучше, потому что, если вы можете позволить себе купить эту книгу вместо того, чтобы сбивать с клавиатуру, как я, просто чтобы создать книгу самостоятельно спрашивать деньги Для этого у вас есть ресурсы, необходимые для достижения успеха в вашей жизни. У меня были всевозможные проблемы с семью, растущей, состояния здоровья, врачей, СМИ и закона, и мой кодекс глубоко отражает борьбу, которая является феминизмом и женской природой в разделенном и разочарованном мире. Тем не менее, эта книга - это то, о чем меня глубоко заботятся, моего ребенка, моего портфолио и моего средства к существованию, поэтому я ценю ваше внимание, когда вы забираете текст домой и тщательно разбираются в нем, чтобы учиться у меня. Пожалуйста, имейте в виду, что я не идеален,В книге будут ошибки, изменения и новые издания, и вам нужно будет думать с вашим логическим мозгом как можно лучше, чтобы получить успешный опыт работы с моим письмом. Кроме того, поймите, что я имею в виду хорошо для вас, даже когда вы сталкиваетесь с проблемами при написании. Подумайте об этом так: когда вы можете просто арендовать компьютерную систему, чтобы сделать все, что вы можете себе представить в цифровом пространстве, хранить всю информацию, с которой вы сталкиваетесь, #$%! YZE и организовать ее, и вы понимаете, вы будете Неизбежно сталкивается с трудностями с информацией, которую вы принимаете и даже публикуете. Я говорю вам об этом, потому что я сталкиваюсь с теми же трудностями. Используйте эту книгу на свой страх и риск, работайте с вашим сообществом и сообществами, доступными для создания программного обеспечения в безопасной обстановке, и не берите вещи лично, когда вы потерпите неудачу или даже не практически справляетесь: вот как я ушел так далеко и почему я могу принести вам этот текст и помочь вам добиться успеха, не расходясь на пути безумия, который уходитЯ разрушил, разорван и потерпел неудачу, когда я сталкиваюсь с обычными проблемами, которые все делают в глобальном масштабе благодаря паралеллистическому глобальному масштабу сети, над которой мы будем работать, Интернет. Возможно, вы не очень хорошо знакомы с тем, кто я есть с несколькими словами, но я призываю вас читать дальше, вы познакомитесь со мной, продолжая читать и понимать меня, создавая свои собственные проекты, чтобы завершить свою работу. В этой книге не будет домашней работы, если ваши профессора или учителя не назначают вас, но я настоятельно рекомендую вам создать портфель проектов самостоятельно, как вы читаете, а также проект Capstone, демонстрирующий, как вы можете Примените то, что вы узнали. Мой проект Capstone является основой для большей части того, что вы прочтете в этой книге, поскольку он включает код из моих предыдущих проектов, код, который я создал и научился писать методически вручную, и широкий спектр идей и советов, которые мне помогли преуспеть до такой степени, что я могу раскрутить простое приложение, котороеUlly показал и выглядит и ведет себя как популярное приложение, которое вы можете видеть, что ваш друг или семья использует, в Интернете, рекламируется вам или в новостях. Что это за книга: Эта книга является учебником по примеру. Вы можете найти код здесь, инструкции о том, как научиться кодировать, информацию о коде отладки и исправления ошибок, устран...
Практическое веб-обучение и безопасность на примере

Практическое веб -глубокое обучение и безопасность по примеру Третье издание Шарлотта Харпер 3 июля 2024 года Предисловие: Соображения безопасности в создании программного обеспечения для Интернета являются важной частью плана и выполнения любого веб -разработчика, в то время как создание прототипа, который является надежным, стабильным и полезным для практических целей. Dom (Markup объекта документа), с его реализацией HTML, JavaScript и CSS, а также бэкэнд -программного обеспечения, внедряющего Python, C/C ++, Java и Bash, дают веб -разработчикам свободу и силу для создания широкого спектра проектов, которые выражают экспресс. Творчество, обеспечивают простоту использования и функциональность, изображают смирение и характер, а также обеспечивают простоту использования, а также удобство и важные услуги, которые привлекательны для среднего Джо, конечный пользователь хочет убить время или сделайте что -нибудь в Интернете, обычно на смартфоне с сенсорным экраном. Большинство людей даже не знали бы, с чего начать, когда они захотят построить веб -сайт сПоцарапайте, они склонны начинать с веб -сайта другого человека и создавать что -то ограниченное в функциональности, надежности, простоте использования и особенно творчества, когда они могли иметь все последние мощные инструменты в их распоряжении, чтобы создать что -то полезное, не теряя времени нажатия кнопок , и особенно впустую деньги, платя на дорогие подписки на программное обеспечение, которое мало кто хотел использовать, учитывая его ограничения в простоте использования и гибкости. Если у вас есть несколько минут, чтобы прочитать эту книгу и узнать, чему я хочу научить вас, или даже лично поговорить со мной о своих целях и получить некоторое руководство в правильном направлении, и вы мотивированы научиться кодировать и писать собственное программное обеспечение , возьмите эту книгу домой и отложите некоторое время, чтобы научиться создавать следующее влиятельное, мощное, оптимизированное и важное веб -приложение, веб -сайт, который все на вас и делает именно то, что вы хотите, и удовлетворяет потребности вашей аудитории. Обо мне: Я разработчик программного обеспечения сДиапазон опыта в C/C ++, Java, Python, HTML, CSS и JavaScript. Я строю веб -сайты, которые люди хотят использовать, хотят посетить и даже пристраститься к использованию просто для изучения, воссоздания и убивать время, и, что самое важное, я продаю программное обеспечение. Если у вас была идея относительно того, как именно вы хотели, чтобы веб -сайт выглядел и функционировал, вы были готовы поддержать меня, чтобы я мог удовлетворить свои собственные потребности, пока я удовлетворяю ваши, и вы готовы покрыть расходы на запуск веб -сайта, Я бы построил вам следующее YouTube, Tiktok, Twitter, Google или даже высокотехнологичное приложение безопасности, которое только вы можете получить. Вместо того, чтобы пытаться продать вам свое время, я пытаюсь купить ваше: я хочу рассказать вам о создании приложения (веб -сайт) с информацией, которая уже существует, и научить вас тому, что вам нужно, чтобы стать независимым разработчиком программного обеспечения, Предприниматель, возглавляя успешную карьеру в любой области, которую вы желаете. И позвольте мне прояснить, что образование, которое я вам даю, будет неформальным. Вы можете пойти в школу и узнать все это с помощьюФормальное образование, или даже прочитайте эту книгу в школе, выполните свои задания и заберу из вашего образования, но я официально не поставлю вас в горячее место и попрошу вас выполнить задания. Я не ваш профессор, вы можете думать обо мне, как о другом, который хочет направить вас к карьере, обусловленной вашим личным успехом. И я не продаю вам успех, вам нужно будет купить его со своим временем. Обучение коду имеет крутую кривую обучения и никогда не было легким или даже предполагалось. Вам нужно работать настолько усердно, насколько это возможно, и продолжать пытаться потерпеть неудачу и повторить попытку, даже когда вы разочарованы, чтобы учиться и создавать приложения самостоятельно. Это в природе самого кода. Код запускается компилятором, который предназначен для предоставления сообщений об ошибках программиста, и они научат вас, как кодировать, даже если вы просто копируете ошибку в свою поисковую систему и читаете примеры других людей. И я должен сказать, вам не нужно быть чрезвычайно богатым, умным,Expul, или даже детализация, ориентированные или организованные для создания приложения. Компьютер заботится об этой организации для вас. Вам просто нужно продолжить пробную версию и ошибки, поддерживать фокус и усердно работать над тем, что вы делаете, и у вас будет очень успешная карьера в целом, что вы делаете. Кто я: Я понимаю, что последний раздел был больше о обучении и вы, как вы берете на себя, из этой книги. Кто я именно? Это сложный вопрос. Я сам неясен, так как я страдаю от заболеваний, которые могут затруднить мне даже кодировать или писать эту книгу, в то же время представляя проблемы с проблемами социализации и идентичности, которые затрудняют мою жизнь, когда дело доходит до представления себя Полем Короче говоря, если вы читаете эту книгу, вы принесли ее домой, потому что вы пропустили ее и подумали, что это было полезно, или даже если вы просто читаете это далеко, для вас я похожий на единомышленник, который хочет видеть, что вы добились успеха в все, что вы делаете. Я сам инженер,Разработчик и студент, и я пишу эту книгу для других студентов, которые хотят облегчить свою жизнь, получив справочник по программному обеспечению, в котором им нужно упростить их жизнь, приводя примеры для копирования, которые соединяются, как большая головоломка в работу , полезное, большое, функциональное, сплоченное и привлекательное приложение, которое может добиться успеха независимо от линии бизнеса. Во многом это то, что я делаю: я строю приложения, чтобы помочь себе и другим людям добиться успеха. Я также автор, хотя это моя первая публикация, которую я намерен завершить, чтобы собрать свое портфель в полезный документ, и я тоже художник. Я признаю это вам, я своего рода странный человек. Я не идеален, у меня были законы, даже заставляя меня покинуть колледжи и университеты и покинуть штаты, чтобы попытаться сделать себе имя с большим успехом. Я женщина по рождению, я ношу макияж, фотографирую себя, ношу платья и другую женскую одежду, и я остаюсь осознавать себя какЖенщина по своей природе. В прошлом у меня были проблемы с другими людьми, которые привели к борьбе с написанием и созданием веб -приложений, и я прошу прощения, что я не смог получить эту книгу раньше в руках: вам это нужно. Вы захотите прочитать и написать код, который выглядит как мой и работает как мой, и делает то же самое, но даже лучше, потому что, если вы можете позволить себе купить эту книгу вместо того, чтобы сбивать с клавиатуру, как я, просто чтобы создать книгу самостоятельно спрашивать деньги Для этого у вас есть ресурсы, необходимые для достижения успеха в вашей жизни. У меня были всевозможные проблемы с семью, растущей, состояния здоровья, врачей, СМИ и закона, и мой кодекс глубоко отражает борьбу, которая является феминизмом и женской природой в разделенном и разочарованном мире. Тем не менее, эта книга - это то, о чем меня глубоко заботятся, моего ребенка, моего портфолио и моего средства к существованию, поэтому я ценю ваше внимание, когда вы забираете текст домой и тщательно разбираются в нем, чтобы учиться у меня. Пожалуйста, имейте в виду, что я неИ. Кроме того, поймите, что я имею в виду хорошо для вас, даже когда вы сталкиваетесь с проблемами при написании. Подумайте об этом так: когда вы можете просто арендовать компьютерную систему, чтобы сделать все, что вы можете себе представить в цифровом пространстве, хранить всю информацию, с которой вы сталкиваетесь, #$%! YZE и организовать ее, и вы понимаете, вы будете Неизбежно сталкивается с трудностями с информацией, которую вы принимаете и даже публикуете. Я говорю вам об этом, потому что я сталкиваюсь с теми же трудностями. Используйте эту книгу на свой страх и риск, работайте с вашим сообществом и сообществами, доступными для создания программного обеспечения в безопасной обстановке, и не берите вещи лично, когда вы потерпите неудачу или даже не практически справляетесь: вот как я ушел так далеко и почему я могу принести вам этот текст и помочь вам добиться успеха, не расходясь на пути безумияAves Me разрушил, разорванную и потерпевшим неудачу, когда я сталкиваюсь с обычными проблемами, которые все делают в глобальном масштабе благодаря паралеллистическому глобальному масштабу сети, над которой мы будем работать, Интернет. Возможно, вы не очень хорошо знакомы с тем, кто я есть с несколькими словами, но я призываю вас читать дальше, вы познакомитесь со мной, продолжая читать и понимать меня, создавая свои собственные проекты, чтобы завершить свою работу. В этой книге не будет домашней работы, если ваши профессора или учителя не назначают вас, но я настоятельно рекомендую вам создать портфель проектов самостоятельно, как вы читаете, а также проект Capstone, демонстрирующий, как вы можете Примените то, что вы узнали. Мой проект Capstone является основой для большей части того, что вы прочтете в этой книге, поскольку он включает код из моих предыдущих проектов, код, который я создал и научился писать методически вручную, и широкий спектр идей и советов, которые мне помогли преуспеть до такой степени, что я могу раскрутить простое приложение, котороеПолностью представлен и выглядит и ведет себя как популярное приложение, которое вы можете видеть, что ваш друг или семья использует, в Интернете, рекламируется вам или в новостях. Что это за книга: Эта книга является учебником по примеру. Вы можете найти код здесь, инструкции о том, как научиться кодировать, информацию о коде отладки и исправления ошибок, устранения неполадок, инструкции о том, как сделать резервное копирование и сохранить код, повторно развернуть, если кто-то нарушает ваш код, защищает код, разверните Ваш код, создание интерактивных веб -сайтов, которые интересны, привлекают и вызывают привыкание, и вы поймете, кто я, почему это важно и как изобразить себя, свое приложение и имидж компании, а также Программное обеспечение, которое вы создаете в абсолютном лучшем свете, чтобы быть наиболее привлекательным для ваших конечных пользователей, посетителей вашего сайта. В этой книге я продемонстрирую ряд примеров дизайна программного обеспечения с акцентом на Интернет как на платформе, так и безопасности. Мы инициируем опыт обучения, создав базовыйВыберите, используя оболочку UNIX, с функциями резервного копирования и сценариев. Затем мы рассмотрим базовый веб -сайт блога, обновите наш блог с помощью функций фото и видео, а также используем эти функции для использования решений безопасности с использованием бесплатного программного обеспечения, а также обеспечить наш сервер, используя модуль подключаемой аутентификации (PAM). Затем мы рассмотрим обработку и обработку файлов, изучение редактирования видео, пожертвования голоса, сканирования штрих -кода и распознавания оптических символов, среди других концепций. По пути мы рассмотрим API, которые помогут нам сделать наше программное обеспечение более полезным и безопасным, с бесплатными и оплачиваемыми вариантами. Попутно мы рассмотрим физическую безопасность и инструменты воинствующих, такие как огнестрельное оружие и проектирование боеприпасов и производство, включая дизайн ствола и ретранслятора, дизайн башни и беспилотников, и другие принципы, которые мы будем интегрироваться с нашим программным обеспечением в существующей сети, чтобы защитить наше программное обеспечение. и продемонстрировать самооборону и разрешение. Мы сделаем перерывы по пути, чтобы построить игры, 2D и 3DЭнджепирование двигателей и работа со встроенным аппаратным обеспечением в примерах из тематического исследования основного программного обеспечения для рендеринга и электронного вибрирующего массажа, отлитого в силиконовом резине соответственно. Попутно мы также будем использовать решения для машинного обучения, уже доступные, чтобы лучше обеспечить наше программное обеспечение. Мы также будем использовать акционерные инструменты, доступные для Интернета, чтобы оптимизировать и обеспечить процесс. Эта книга представляет собой руководство по вашему успеху в создании веб -приложения и интеграции его с профессиональной сетью компьютерных и встроенных механических систем, а также в целом руководство по созданию программного обеспечения и встроенного оборудования без правого знания или предыдущего опыта. Чем нет этой книги: Если вы действительно хотите иметь веб -сайт, вы можете просто настроить простой магазин и продать то, что вам нужно, опубликовать блог, публиковать фотографии или видео или иным образом, никогда не записывая ни одну строку кода. Эта книга это не так. Эта книга научит вас создавать программное обеспечение, которое является более полезным, полностьюПоказанный, функциональный и безопасный, чем любое программное обеспечение, которое вы уже можете найти, потому что оно развертывает новейшее программное обеспечение, которое все еще является прототипами, может быть дорогостоящим для работы в масштабных работах пожилых компаний, и не привлекает обратных, запутанных компаний, созданных в Зарабатывайте деньги для людей, которые на самом деле ничего не делают. Если вы внимательно следите за этой книгой, вы захотите написать код, код исследования, создать свои собственные приложения, и вы заработаете деньги на то, что вы делаете. Я заработаю деньги на этой книге, даже на ранних этапах, потому что она содержит информацию, которую люди нуждаются и хотят читать, и уже покупают, когда покупают или используют мои приложения. Эта книга не будет создавать для вас приложение, но она укажет вам в правильном направлении и вооружает вас необходимыми инструментами, а также навыками и советами, которые будут способствовать вашему собственному успеху в создании программного обеспечения для Интернета, при каждой линии Код, который вам нужно будет написать в качестве примера, готовый к сочетанию в программное обеспечение, которые вы и ваши сторонники, гости, клиентуру,Рендс, семья, посетители, подрядчики и жители Интернета хотят использовать и поддержать. Чему вы узнаете: Эта книга научит вас, как создавать и продавать программное обеспечение, действительно функциональное, полезное программное обеспечение, запись медиа, функции безопасности, такие как распознавание лиц, сканирование штрих -кодов в зоне машины, веб -API для аутентификации, записи и визуализации видео и фотографий, а также обмена сообщениями, такими как Bluetooth и связь с полевым (NFC). Эта книга научит вас, как использовать сетевой компьютер, сосредоточившись на Debian Linux, как создать код Bash для установки и резервного копирования вашего программного обеспечения бесшовным, автоматизированным бризом, как создать код Python в качестве бэкэнда для обслуживания динамических сообщений, стиля Вещи хорошо используют стили CSS с Bootstrap, включите вход пользователей и интерактивность через сетевые устройства, создайте интерактивные носители и сеть с другими веб -сайтами, чтобы предложить функции безопасности, такие как текстовые сообщения для проверки или другого Цели, идентификационное сканирование, модерация изображений и видео, данныеРанзации, чтобы сохранить ваше программное обеспечение безопасным, обработка платежей, торговлю криптовалютой, асинхронные задачи и многое другое. Вы узнаете, как построить свои собственные устройства Bluetooth, с батареями, зарядными устройствами, микроконтроллерами, схемами, двигателями и датчиками, с использованием припоя, проволоки и 3D, а также литых материалов. Я продемонстрирую 3D -принципы, применяемые к аддитивному производству и изготовлению инструментов и матрице, поэтому вы можете производить свои собственные встроенные аппаратные устройства со встроенными батареями, зарядными устройствами, электронными схемами и функциональными выходами. и пообщаться с ними с Bluetooth и Интернетом. В частности, мы рассмотрим два тематических исследования, вибрирующий массажер и домашнее огнестрельное оружие, оба запрограммированы в OpenScad, который доступен в виде графического интерфейса или утилиты командной строки и может быть интегрирована в сеть для более быстрых результатов. Вы узнаете, как создавать и развернуть веб -сайт с нуля без предварительного опыта, сделать его функциональным, безопасным, красивым, полезным и большинствоммногозначально практично. Вы узнаете, как использовать машинное обучение и компьютерное зрение, чтобы сделать сайт безопасным и более практичным, записывать видео и аудио с вашего сайта, пожертвовать свой голос, создавать музыку и модулировать аудио для создания полезных образцов и как прорвать шум Используя другие веб -сайты для создания наилучшей возможной сети веб -сайтов, которые вы можете ссылаться непосредственно на ваши, чтобы поделиться всей полезной информацией, которую вы можете предложить, и, что более важно, привлечь людей к вашему программному обеспечению и бизнесу. Эта книга будет больше всего сосредоточена на медиа, безопасности и машинном обучении, которые представляют собой основные три компонента, которые помогут вам создать полезное программное обеспечение для Интернета, привлекая правильных пользователей и отключив неправильные, как реалистично, практическое, практическое, практическое Руки и увлекательные, но и автоматические и крепкие. Эта книга учит Unix, в частности Debian (Ubuntu), Bash Shell, Python, HTML, CSS, JavaScript и ряд полезных программных пакетов дляНравится запросы, а также полезное программное обеспечение для Bash, такое как GIT и FFMPEG. Я также научу вас, как автоматически обменять криптовалюту, и принимать платежи по криптовалюте или на обычных дебетовых картах, даже выплачивая вашим посетителям долю вашего дохода, если вы решите это сделать. Я научу вас, как заработать деньги с вашего веб -сайта и через рекламу, как подготовить ваше приложение для поисковых систем и сделать его быстро, в первом рейтинге по тому, что ваши клиенты будут искать вас, и рейтинг во многих обычных ищет как можно больше. Я научу вас, как продавать ваше программное обеспечение, рекламировать его, обращаться к клиентам, ищущим ваши услуги, и сделаю себе имя в Интернете через возможности, которые уже существуют, являются недорогими и хорошо работают. Я научу вас, как сохранить ваши данные на облачных компьютерах, которые работают на вас, и дешево сохранить ваши данные, как планировать и создать веб -сайт, который делает то, что хотят ваши пользователи и что вы хотите, и как держать ваших пользователейНажмите на ваш сайт, нажмите на свои телефоны уведомлениями, электронной почтой, текстовыми сообщениями, телефонными звонками и большим количеством возможностей, чтобы вернуть ваших пользователей на ваш веб -сайт в вашем распоряжении за щелчком кнопки, защищенной для вас. Эта книга будет сосредоточена на практичности публикации и распространения медиа в больших количествах, от текста до фотографий до видео до аудио, создание хорошего впечатления на конечных пользователей (ваши клиентуру) и продавать себя любым способом, чтобы сделать, чтобы создать Веб -сайт, приложение, которое является представителем вас и только вас, и делает вас, ваше программное обеспечение и ваша компания хорошо выглядят как можно лучше. Вы также узнаете от меня несколько советов и рекомендаций: от советов по кодированию, практического тщеславия, таких как макияж и фотография, моделирование и актерское мастерство, и многое другое, что будет важно для изображения себя и свою компанию в наилучшем свете, используя все доступные инструменты Для вас при распределении столько контента, сколько вам нужно по здоровому балансу платформ, чтобы принести вашиE, чтобы реализоваться без больших усилий, работы или денег, чем необходимо. Эта книга называется «Практическое веб -глубокое обучение и безопасность по примеру» по какой -то причине: она имеет дело с обучением для кода, в частности для Интернета, в частности, с акцентом на безопасность, с практической точки зрения, с примерами рабочего кода, который служит Практические цели, изложенные в тексте. Компонент обучения этого текста также включает в себя машинное обучение, код, который я покажу вам, как работать в Интернете, который будет обрабатывать компьютерное зрение, распознавание лица, модерацию изображений и видео, улучшение изображений, улучшение разрешения, подписание изображений и другие задачи, такие как Метрики прогнозирования, полученные из изображений, таких как природа изображения в качестве подлинного, передаваемого компьютером изображением или оптической копии (фотография изображения или напечатанного фото). Машинное обучение очень важно, когда речь заходит о безопасности веб -безопасности и безопасности программного обеспечения, потому что оно может выполнять задачи, которые в противном случае были невозможны. Ваш компьютерВойдите в систему с помощью пароля, но это может быть безопаснее использовать его, если он входит в вас в систему с вашим лицом. Вы можете сделать серверный компьютер таким безопасным, компьютером, который обычно просит вас об этом имени пользователя и пароля и вошел в систему, возможно, с токеном подтверждения для каждого нового входа в систему или нового IP -адреса, но если вы создаете крупномасштабные, легко в Использовать, принципиально безопасное и мощное программное обеспечение, этого может быть достаточно. Случай вашего программного обеспечения слишком близко к чьему -либо другому программному обеспечению, например, службы электронной почты или службы текстовых сообщений, недостаточно, чтобы сделать ваше программное обеспечение безопасным или любом (любой сайт, который вы используете). Любой, кто строит программное обеспечение, которое безупречно безопасно, имеет некоторое представление о том, что это подразумевает. Программное обеспечение по своей сути небезопасно, потому что устройства и учетные записи, которые мы используем для доступа к нему, не всегда находятся в нашем распоряжении, они могут находиться в руках любого, кто страдает от программного обеспечения и, следовательно, может представлять риск для самого программного обеспечения. Это что -то в центре внимания этой книги. Сетевой компьютер по умолчаниюЗакреплен с помощью длинного токена ключа, называемого и SSH или защищенного ключа оболочки, и в остальном лучше всего защищен с помощью веб -сервера, поскольку веб -сервер предоставляет открытый доступ, а также современные инструменты безопасности, работающие на самом сервере. Веб -сервер имеет доступ к веб -браузеру пользователя, который, возможно, является самой мощной частью устройства пользователя, потому что это место, где пользователь может получить доступ к сетевому программному обеспечению. Этот инструментарий может отображать текст, веб -страницы, которые вы видите, а также могут записывать изображения, аудио и видео (например, фотография лица или идентификатора состояния), могут читать и писать на радиоустройства Bluetooth и могут читать и писать в ближнем поле Теги Transponder, недорогие карты ключей, FOBS, наклейки, кольца и даже чип -имплантаты с уникальными последовательными номерами, которые можно прочитать и записать с данными, сгенерированными и подтвержденными веб -сервером, привязанным к веб -сайту. Используя все инструменты в вашем распоряжении, с этой книгой вы дадите себе знания, чтобы создать безопасный веб -сайт и в целомКомпьютерная система URE, которая работает на вас, выполняет ваши торги, выглядит и кажется правильной. С чего начать: Вы можете пропустить мимо раздела, с которой я начинаю эту книгу, или в любом разделе, к точному коду, особенно если у вас есть опыт работы с кодированием или любым из вышеупомянутых инструментов, которые я буду подробно описать в этой книге как а также документирование вариантов использования и практических примеров их. Если у вас нет опыта в написании кода, я настоятельно рекомендую вам прочитать всю эту книгу, и особенно рекомендую прочитать предыдущие разделы, чтобы убедиться, что эта книга подходит для вас. Если эта книга не подходит для вас, подумайте о том, чтобы подарить его другу или родственнику, которые могут быть заинтересованы в том, чтобы узнать о веб -развитии сами и даже подумайте о том, чтобы занять его обратно и учиться у них, чтобы заполнить пробелы, где я подвел вас как Учитель или другие учителя сделали передо мной. Начните там, где вы будете, каждая часть этой книги будет полезна, если вы собираетесь построить полезныйPP, и считайте, что лучшие приложения создаются с учетом конечного пользователя: знайте своего клиента. Теперь вы знаете меня, вы знаете эту книгу, и вы готовы начать. Для начала возьмите компьютер (даже самый дешевый ноутбук из магазина коробки, Amazon или старый рабочий стол, и установите его так, чтобы это работало для вас. Как прочитать эту книгу: Текст выделен, обозначает, что текст принадлежит в командной строке, где вы напишите код, который вы запускаете. Командная строка в значительной степени ориентирована на клавиатуру и практически не требует щелчка, ускоряя ваш рабочий процесс и облегчает вам ситуацию. Начиная: Давайте погрузимся. Мы начнем с создания кода на локальной машине и начнем без создания веб -сайта, подключенного к Интернету. Это безопаснее начать, ничего не стоит, и вам легко. В зависимости от вашей операционной системы, попадание в оболочку Bash будет немного другим. Для Mac OS я рекомендую установить виртуальную машину в этот момент, так как вы получите наибольшую совместимость свиртуальная машина. Различные поставщики, такие как VirtualBox и Paralells, могут запускать для вас виртуальную машину, хотя также можно установить Ubuntu непосредственно на машину, если вы предпочитаете использовать собственную среду, которая рекомендуется для создания быстрого, упорядоченного опыта. Если вы используете Linux или Windows, которые я рекомендую, это должно быть довольно легко создать проект. Откройте свой терминал, отрегулируйте размеры по мере того, как вы видите, и начните с следующим шагом 2. Если вы используете Windows, следуйте шагу 1. Шаг 1: - Только пользователи Windows В Windows, откройте командную строку в качестве администратора и введите WSL –Install Шаг 2: - Продолжайте здесь или пропустите шаг 1 к здесь, если вы не используете Windows В открытом терминале (в зависимости от вашей ОС, называемой Ubuntu в Windows, терминале в Mac или Linux или аналогичном имени), начните с создания проекта. Мы делаем это с командой MKDIR, которая создает каталог. Если вам нужно создать каталог для хранения вашего проекта, который рекомендуется, используйтеКоманда CD для перехода на каталог и и CD/PATH/TO/Directory - Путь - это папки (файлы), которые предшествуют вашему каталогу назначения, ваш путь по умолчанию - ~ или/home/username (где имя пользователя является вашим именем пользователя). Чтобы перейти на каталог по умолчанию, введите CD или CD ~ Пример MKDIR - замените «пример» на имя каталога Теперь у вас есть рабочий каталог для вашего проекта. Будучи так важно, чтобы этот каталог сохранил, если вам нужно переключиться на другую машину или развернуть код, который вы пишете, чтобы он был готов к Интернету, мы создадим скрипт для резервного копирования вашего каталога в следующих нескольких шагах. Но создание сценария требует немного кода, и код должен быть автоматизирован, чтобы быть максимально полезным. Итак, давайте сначала построим сценарий для строительства сценариев. Давайте начнем с создания сценария и сделаем его исполняемым файлом. Мы будем использовать Sudo, CHMOD и прикоснуться к этому, и вызовуте сценарий


sudo touch /usr/bin/ascript
sudo chmod a+x /usr/bin/ascript
sudo nano /usr/bin/ascript
Теперь мы создали сценарий, сделали его исполняемым файлом и готовы его редактировать. Nano - это текстовый редактор, который позволит вам редактировать текст без щелчка, что намного проще, чем использование графического интерфейса пользователя. Чтобы отредактировать файл с помощью Nano, используйте NANO, а затем путь к файлу. Чтобы сделать сценарий, который делает сценарий, он довольно похож на создание нашего сценария. Мы будем использовать тот же код, что и выше, заменив имя сценария «Ascript» параметром аргумента, 1 доллар. Это позволяет нам позвонить в скрипт, набрав просто Newscript Sudo Ascript, и в этот момент мы можем создать любой новый сценарий, заменив «Newscript» на имя вашего сценария. Код в Нано должен выглядеть так:

sudo touch /usr/bin/$1
sudo chmod a+x /usr/bin/$1
sudo nano /usr/bin/$1
И чтобы закрыть Nano, мы можем удерживать клавишу управления и нажать X, затем y, чтобы обозначить, что мы сохраняем файл и нажимать возврат. Теперь вместо того, чтобы вводить эти три команды для редактирования сценария, мы сможем напечатать Ascript Sudo Ascript, чтобы снова редактировать скрипт. Это работает! И любой новый сценарий можно легко запустить, позвонив в оболочку. Давайте сохраним нашу работу сейчас: давайте напишем резервный сценарий, чтобы сохранить наш новый сценарий, а затем вернуть его в нашем каталоге проектов, а также резервным образом подтвердим сценарий резервного копирования.

sudo ascript backup
Теперь в Нано:

sudo cp /usr/bin/backup /path/to/directory/
sudo cp /usr/bin/ascript /path/to/directory/
Где/path/to/directory - это путь к проекту, который вы создали с Mkdir. Позже мы узнаем, как копировать такие пути повторения, как это с помощью цикла и списка, который меньше кода, но сейчас давайте будем держать его простыми и иметь несколько строк. Чтобы запустить этот скрипт и резервное копирование кода, сохраните файл в Nano с Control+X, Y и верните, и введите ниже

backup
Если вам вообще предложено пароль во время чтения этой книги и следите за оболочкой, пожалуйста, введите пароль пользователя правильно, у вас будет три попытки, прежде чем вам понадобится повторный разряд команды. Вы можете использовать стрелки вверх и вниз, чтобы повторно затронуть команды и отредактировать их, если вам нужно что -нибудь запустить что -либо дважды. Просто нажимайте вверх и вниз периодически, чтобы выбрать команду, перед редактированием команды правыми, стрелками влево и клавиши удаления, а также клавиатуру, и запустить ее с возвратом. Поздравляю! Вам удалось создать потрясающий сценарий резервного копирования, который поддерживает два важных сценария оболочки в вашем рабочем каталоге. Мы могли бы перемещать вещи позже, так как проект становится больше, но сейчас это работает. Давайте перейдем к резервным копированию в облаке, мы будем использовать GitHub для этого (хотя есть много других решений GIT для резервного копирования, они примерно одинаково.) GIT - это программное обеспечение для управления Veris программное обеспечение, когда вы делаете их на сервере, в то время какТакже позволит вам загрузить целые копии вашего программного обеспечения за паролем или ключом. Это способствует сохранению вашего программного обеспечения, тем более что мы перемещаемся на защитные экземпляры Linux, которые иногда ломаются, когда одна строка кода не стерла, оставляя вас заблокированным, пока ваш код не может быть резервным, если у вас нет возможности поддержать его автоматически, что мы рассмотрим. Если вы еще не используете виртуальную машину Ubuntu на этом этапе, я рекомендую использовать виртуальную машину Ubuntu на данный момент, потому что она облегчит вашу жизнь при установке всех необходимых пакетов для создания рабочего веб -сайта и преформировать глубокое обучение операции на вашем компьютере. В ближайшем будущем мы перенесем код на веб -сервер, но мы хотим убедиться, что за нашим веб -сервером есть как минимум несколько уровней безопасности этот. Если вы все еще хотите использовать Mac OS, вы можете искать и установить и установитьEneful Packages Online, но не может быть альтернативы для каждого пакета, который будет охватывать эту книгу или сериал. Давайте добавим несколько команд, чтобы выполнить нашу работу с помощью сценария резервного копирования, запустив команду Sudo Ascript

# …
git add –all
git commit -m “backup”
git push -u origin master
Еще раз контроль X, чтобы сохранить. Теперь нам нужно сделать некоторую конфигурацию для этого проекта. Поскольку вскоре это будет проект GIT, нам не нужно печатать каждую команду каждый раз, когда мы развертываем из репозитория GIT, но мы узнаем об этом, когда пишем наши сценарии развертывания. Для начала давайте убедимся, что мы находимся в правильном каталоге, инициализируем репозиторий GIT и генерируем ключи SSH.

cd /path/to/directory
git init
git branch -m master
ssh-keygen
После того, как мы набираем SSH-KeyGen, новый ключ должен быть сохранен в домашней папке под папкой, называемой .ssh. Это называется id_rsa.pub. Давайте найдем этот ключ и скопируем его. Чтобы увидеть это,

cd ~
cat .ssh/id_rsa.pub
Скопируйте текст, который возвращается последней командой, и создайте учетную запись с вашим поставщиком GIT (в идеале GitHub), прежде чем добавить ключ SSH в вашу учетную запись. После того, как у вас есть учетная запись, щелкните верхнее правое меню и введите настройки, прежде чем добавить ключ SSH в клавиши SSH и GPG под доступом в меню. Выберите добавить ключ SSH и добавить свой, вставив его и дав ему заголовок, прежде чем сохранить и вернуться в GitHub, чтобы создать новый репозиторий. Это похоже на других поставщиков GIT, вам нужно будет прочитать их документацию. В новой конфигурации репозитория дайте вашему репозиторию описательное имя и решите, хотите ли вы его опубликовать, и убедитесь, что пока не настроите файлы для включения. Как только репозиторий создается, скопируйте клон с помощью SSH URL и вставьте его в следующую команду.

git remote add git://… (your remote URL)
Теперь вы можете вернуться в свой репозиторий с CD, вы будете знакомы с этим. Попробуйте свой сценарий резервного копирования сейчас с резервной копией Большой! Теперь мы действительно можем получить кодирование. Давайте установим Django теперь, когда мы хорошо понимаем Bash and Git. Django позволит нам автоматически резервное копирование нашего программного обеспечения, Bash может сделать это тоже, но у Django должна быть более безопасная реализация (его можно отключить и настроить легче). Чтобы установить программное обеспечение в Ubuntu, мы будем использовать команду Sudo Apt-Get. Во -первых, давайте обновим и обновим программное обеспечение, которое у нас уже было. Это можно сделать с помощью обновления Sudo Apt-Get и обновления Sudo Apt-Get-Y. Далее, давайте установим Python и нашу виртуальную среду, дом нашего кода, со следующей командой: sudo apt-get установить python-is-python3 python3-venvv Это все, что вам нужно, чтобы начать с Джанго с точки зрения установки программного обеспечения в экземпляре Ubuntu. Для Windows и Linux это должно быть довольно простым, но для Mac вы можете установить виртуальную машину иLinux на нем, используя бесплатную или платную виртуальную среду, такую ​​как VirtualBox или Paralells Desktop, и воссоздайте вышеуказанные шаги, чтобы настроить среду Ubuntu. В этом случае Ubuntu имеет решающее значение, потому что это программное обеспечение, которое запускают веб -сайты, и позволяет им размещать веб -сайты со всем вышеупомянутым программным обеспечением. Давайте копаем в Джанго. В нашем каталоге снова, с

python -m venv venv # Создает виртуальную среду, в которой хранится код
source venv/bin/activate # Активирует виртуальную среду
pip install Django
django-admin startproject mysite . # Где MySite - это проект, который я начинаю в своем текущем каталоге.
Django только начинает нас, потому что Django размещает веб -сервер и делает все, что нам нужно, чтобы получить базовый локальный веб -сайт. Теперь, когда у нас установил Django, давайте немного отредактируем настройки, чтобы они работали так, как нам нужно. Во -первых, давайте создадим новое приложение

python manage.py startapp feed
Вы заметите, что первое приложение называется Feed. Приложение должно называться как бы вам понравилось, и мы создадим новые приложения, но имя каждого приложения должно быть последовательным каждый раз, когда приложение упоминается в коде. Чтобы добавить новое приложение, мы всегда будем отредактировать настройки. Используя Nano,

nano app/settings.py
В настройках найдите stasted_apps и разделяйте [] на 3 строки. Используя четыре пространства на пустой центральной линии, добавьте «подачу» или имя вашего приложения. Этот раздел настроек.

INSTALLED_APPS = [
    'feed',
]
Прежде чем мы забудем, давайте проверим, что Джанго работает. Используя команду Python Manage.py Runserver 0.0.0.0:8000, мы можем запустить сервер, а затем перемещаться в веб -браузере на компьютере, запускающем код по адресу http: // localhost: 8000 и посмотреть пример веб -страницы (она работает!) Выйдите из сервера с помощью Control C, так же, как и любая другая команда. Теперь давайте копаться в написании кода Python. У Джанго есть три основных компонента, все они выполняют код. Компоненты называются моделью, представлением и шаблоном, и каждый находится на более высоком и более низком уровне, соответственно, до того, как веб -страница будет доставлена ​​пользователю. Модель - это код, который хранит информацию в базе данных для поиска, сортировки и рендеринга. В представлении решается, как модель отображается, манипулируется и модифицирована, почти каждый вид будет использовать модель напрямую. Шаблон - это HTML -код с некоторыми дополнительными наворотами и свистами, называемыми языком шаблонов. Шаблон визуализируется представлением, где он заполнен кодом Python иКонтекст, такой как модели и информация (Usuall Strings и целые числа) из представления. У Джанго тоже есть другие компоненты, включая, помимо прочего: Настройки, которые настраивают приложение, как мы обсуждали. URL -адреса, которые являются шаблонами, которые пользователь следует, чтобы получить доступ к определенным частям веб -приложения. Формы, которые определяют, как информация, которая отправляется на сервер, обрабатывается и отображается в базу данных, а также с пользователем. Это основа информации о обработке на стороне сервера и могут принимать любую информацию, которую компьютер хранит, особенно текстовые строки, номера и True/False Booleans (обычно флажки). Шаблоны, которые являются HTML -кодом и языком шаблонов и преодолевают разрыв между Python и HTML, что означает, что информация о Python может быть обслуживалась HTML -кодом, к которому можно получить доступ, и может получить веб -сайт с ограниченным доступом, в то же время делая код Python, доступным для Интернета и полезно Для различных целей на удаленном устройстве, которое неЭд должен быть рядом с сервером. Статические файлы, которые обычно представляют собой JavaScript, и это библиотеки, которые обслуживают сервер и связаны с шаблоном. Медиа -файлы, которые сервер обслуживает или размещено извне, или только что записано на сервер, прежде чем обрабатывать и отправлять на другой сервер (ведро) для хостинга. Промежуточное программное обеспечение, которое представляет собой кусочки кода, которые запускаются одновременно с каждым представлением и считаются «включенными» в представлении. Контекстные процессоры, которые обрабатывают контекст каждого представления и используются для добавления дополнительного контекста. Тесты, которые подтверждают, что пользователь или запрос выполняют определенные требования до того, как представление будет отображаться. Потребители, которые определяют, как веб -тока обрабатывают и реагируют на общение. Администратор, который используется для регистрации моделей, чтобы их можно было подробно манипулировать на странице администратора Django, где базу данных можно вводить через графический интерфейс. Сельдерей, который определяет асинхронные задачи части кода Джанго могут начатьНонн, прежде чем немедленно перейти к следующей задаче или строке кода. У Джанго может быть много других компонентов, которые мы подробно обсудим здесь. Существует множество способов сделать Django более функциональным, добавляя WebSockets, которые представляют собой быстрые, оптимизированные каналы связи, сельдерей, которые выполняют асинхронные задачи и множество других частей программного обеспечения для расширения django, особенно в функциях представления, где большинство из Код выполнен. Функции просмотра являются ключевыми, потому что они обычно объявляют каждый фрагмент кода, специфичный для конкретного шаблона URL или раздела сервера. Во -первых, давайте рассмотрим функции просмотра. Функции просмотра начинаются с обозначения кода импорта, который будет использоваться в представлении, и определяются с использованием регулярных определений функций или классов. Самые простые представления определяются определением функции и возвращают HTTPresponse с основным шаблоном. Давайте начнем с определения основного представления, чтобы вернуть текст «Привет, мир». Помните, что каждый раз, когда вы добавляетеСделайте оператор, как DEF, если, в то время как, для и т. Д., Вам нужно будет добавить 4 места для каждого из предыдущих определений, которые вы хотели бы применить к вашей функции. Мы пойдем в то, что каждый из них в ближайшее время значит. Из каталога нашего сайта отредактируйте файл feed/views.py, используя Nano и добавьте следующие строки в конце

from django.http import HttpResponse

def hello(request):
    return HttpResponse('hello world')
Httpresponse Django отвечает текстовой строкой, обозначенной открытием и закрытием ». Каждый раз, когда вы передаете информацию в функцию или класс, например, запрос или строку, вам нужно будет использовать скобку (открытие и закрытие). Это еще не все, что нам нужно увидеть наше мнение. Конечно, мы не сказали серверу, где именно является представление, нам все равно нужно определить путь, по которому представление должно отображаться. Давайте начнем с определения базового пути в App/urls.py, и мы попадем в группы пути позже. В App/urls.py добавьте строку после операторов импорта после начала импорта только что созданного представления.

from feed import views as feed_views
Теперь давайте определим шаблон представления. Паттерны просмотра имеют три компонента, компонент Path, который сообщает серверу, где представление существует на сервере (путь URL, который пользователь вводит в панель навигации для входа на веб -страницу), компонент представления, где указан представление, и Дружественное имя для представления, поэтому при работе с шаблоном легко получить его шаблон, особенно так, чтобы его имя можно изменить и обновить, если это необходимо, чтобы освободить место для другого представления или принять более логичное имя. Имеет смысл делать вещи таким образом и быть гибким, потому что ваша кодовая база будет постоянно меняющейся средой, которая нуждается в гибкости и импровизации, чтобы быть ценной и с ним простым в работе. Вот как будет выглядеть ваше представление, вы можете добавить это в urlpatterns = [раздел App/urls.py. Паттерн представления определяется тремя компонентами, описанными выше, и функцией, называемой пути. Ваши шаблоны URL - это список, поэтому обязательно заканчивайте каждый элемент в нихс запятой, потому что это отделяет каждый. Каждый элемент также должен перейти на новую линию, еще раз с четырьмя пробелами перед ним, как приложение в Sutess.py. Мы определим первый компонент представления с помощью пустой строковой функции, чтобы создать представление, которое работает в корневом каталоге веб -сервера. Ваш urls.py теперь должен выглядеть как

from feed import views as feed_views

urlpatterns = [
    path('', feed_views.hello, name='hello'),
]
Это основа для создания веб -сайта с Django, который полностью статичен. Чтобы сделать более динамичный веб -сайт, на котором мы можем начать кэшировать информацию, такую ​​как изображения, видео, аудио и многое другое, нам нужно будет использовать модели, которые мы рассмотрим дальше. На данный момент давайте проверим наш код и запустим сервер. Чтобы проверить код на предмет ошибок, запустите:

python manage.py check
Если есть какие -либо сообщения об ошибках, вам следует тщательно просмотреть изменения, которые вы внесли в свое приложение, и посмотреть, есть ли что -то, что нужно исправить, например, постороннее или не хватает места, дополнительный символ, неподготовленная строка, любая опечатка, любая случайно Удаленный характер или что -то еще. Читая сообщение об ошибке (если у вас есть), вы сможете увидеть путь к созданному вами файлу или отредактированию вместе с номером строки, поэтому посмотрите на этот файл и строку и посмотрите, сможете ли вы исправить что -нибудь, что есть Полем Если вы исправили проблему, запустите вышеуказанную команду снова. Когда ваше программное обеспечение будет готово к запуску и работает, вы увидите вывод «Проверка системы идентифицирована без проблем». Теперь ты готов к работе. Запустите сервер с помощью:

python manage.py runserver 0.0.0.0:8000
Теперь откройте веб -браузер и перейдите к http: // localhost: 8000. Вы должны увидеть текст, возвращенный в скобках и цитаты функции httpresponse в вашем представлении. Это всего лишь основной пример, но если вы сделали это так далеко, вы понимаете основы того, как работают Linux, Bash, Python и Django. Давайте углубимся в некоторое моделирование базы данных и изучим силу класса Python в хранении информации. Затем мы начнем захватывать HTML и CSS, прежде чем сделаем наш сайт полностью представленным, гибким и безопасным с помощью JavaScript и машинного обучения. Занятия хранятся в моделях.py вашего приложения. Используя Nano, редактируйте app/models.py и добавьте новый класс. Класс определяется с определением класса и проходит суперкласс, от которого он наследует, в данном случае модели. Модель. Название класса поступает после определения класса, и после использования определения класса A: (Colon), прежде чем атрибуты и определения функций, связанные с классом, обозначены ниже. Наш классНужен идентификатор, который мы можем использовать, чтобы получить его и сохранить его уникальным, и ему также необходимо текстовое поле для хранения некоторой информации. Позже мы сможем добавить метку времени, файлы, логические (истинные или ложные определения, которые могут помочь нашему коду принимать решения о том, что делать с моделью, и могут использоваться для ее сортировки), экземпляр, чтобы связать модель с пользователем, вошли в систему в сервер и многое другое. Давайте распаковать код

from django.db import models # Импорт, который используется для определения нашего класса и его атрибутов

class Post(models.Model): # Определение нашего класса
    id = models.AutoField(primary_key=True) # Идентификатор нашей модели, автоматически сгенерированного ключа, который позволит нам запросить модель, сохранить ее уникальной и полезно, когда нам нужно взаимодействовать с моделью после ее создания.
    text = models.TextField(default='') # Атрибут нашего класса, в данном случае, какой -то текст, дефолт на пустую строку.
Закройте и сохраните файл, как мы делали раньше, чтобы закончить. Есть много других областей и параметров, которые мы рассмотрим, когда обновляем этот класс по мере развития нашего приложения, но это основные необходимость создания приложения для публикации некоторого текста. Однако эта модель не будет работать в одиночку. Как описано ранее, нам понадобятся пользовательский вид и пользовательский шаблон URL -адреса, чтобы эта модель работала, и нам также понадобится форма вместе с шаблоном. Давайте сначала рассмотрим форму. Чтобы определить форму, редактируйте App/Forms.py с помощью Nano и добавьте следующие строки. Нам понадобятся два импорта, наш класс форм, а также модель, которую мы создали (Feed.Models.post), определение класса, аналогичное модели, и поле вместе с подклассом, называемым Meta, который будет определять модель. Форма взаимодействует с. Форма также может иметь функцию инициализации, которая устанавливает ее на основе информации в запросе, модели или ином, мы рассмотрим это позже. Модельные формы настолько полезны, потому что они могут создать модель или также редактировать модель,Таким образом, мы будем использовать их для обоих. Давайте определим один в forms.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',)
Это основы того, как выглядят форма и модель. Эта форма модели может использоваться для создания или редактирования поста, изменяя его текст. Мы рассмотрим интеграцию этой формы в вид. Во -первых, давайте сделаем миграции и перенесем базу данных, чтобы наш код мог взаимодействовать с моделью при запуске. Для этого запустите следующие команды:

python manage.py makemigrations
python manage.py migrate
Это займет минуту, чтобы выполнить, но как только это это произойдет, это позволит вам получить доступ к модели в представлениях, промежуточном программном обеспечении или где -либо еще в программном обеспечении. Давайте продолжим, увидим, где мы можем увидеть нашу модель. Редактировать Feed/views.py и добавьте следующий код, как отмечено. Вам не нужно что -либо добавлять после знака #, этот код - это комментарии, которые используются для обозначения информации о коде. Мы начнем с импорта нашей модели в представлениях и добавив ее в контекст, где мы можем отображать ее в шаблоне в качестве списка для отображения. Далее мы добавим шаблон, в котором мы можем отображать форму и модель с помощью кнопки для создания нового объекта на основе модели и разместить его на сервер. Это звучит сложно, так что давайте просто сделаем это шаг за шагом. Прежде чем мы закончим представление, давайте создадим шаблон, который просто отображает модель, и убедитесь, что мы можем увидеть его, создав новый пост в оболочке. Вот как должен выглядеть этот взгляд:

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

def feed(request):
    posts = Post.objects.all() # Запросите все сообщения в базе данных до сих пор
    return render(request, 'feed/feed.html', {
        'posts': posts,
    })
Все выглядит довольно просто, пока мы не дойдем до дна. Рендеринг, значение, возвращаемое функцией, а не в ответе HTTP, подобном предыдущему примеру, всегда принимает запрос в качестве первого ввода, принимает контекст (в данном случае посты в базе данных), который теперь можно отображать в шаблоне и возвращает шаблон, определенный в функции. Шаблон станет HTML -документом с небольшим языком под названием Jinja2, который делает информацию Python в HTML. Чтобы начать создавать шаблоны, сделайте два каталога в подаче.

mkdir feed/templates
mkdir feed/templates/feed
Затем отредактируйте шаблон в каталоге выше, Feed/Semplates/Feed и добавьте код для этого примера. Давайте посмотрим на шаблон для этого примера.
 
<!doctype HTML>
<html>
<body>
<legend>Feed</legend>
<hr>
{% for post in posts %}
<p>{{ post.text }}</p>
{% endfor %}
</body>
</html>
 
Это очень простой шаблон. Он определяет открытие и закрытие HTML -тегов, тег типа документа, тег кузова с заголовком легенды, бир шаблон. Это все, что нужно для рендеринга, но в базе данных еще нет. Давайте создадим немного с оболочкой. Мы можем запустить оболочку с помощью mange.py

python manage.py shell
Теперь давайте импортируем нашу модель Post

from feed.models import Post
Затем мы создадим простой пост со строкой и выйдем из оболочки. Строка может быть чем угодно, пока это достоверный текст.

Post.objects.create(text='hello world')
exit()
Наконец, нам нужно будет добавить URL -шаблон в нашем каналов. Поскольку наше приложение Feed будет использовать несколько URL -адресов, и мы хотим сохранить размеры файлов небольшим, давайте создадим локальный urls.py в нашем приложении Feed, которое выглядит следующим образом:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.feed, name='feed'),
]
Нам также нужно будет отредактировать urls.py в базовом приложении, как бы мы ни называли его, это был первый каталог, который мы создали. Изменить app/app.py и добавить следующее в шаблоны URL -адреса

from django.urls import include # наверху

urlpatterns = [
    # ... предыдущий код здесь
    path('feed/', include(('feed.urls'), namespace='feed')),
]
Теперь, когда мы запускаем сервер с помощью Python Manage.py Runserver, мы увидим страницу, которую мы создали, потому что у нас есть модель, просмотр и шаблон, а также шаблон URL, а также элементы в базе данных. Далее, давайте внедрим форму, которую мы создали, и начнем создавать наши собственные посты. Но прежде чем мы напишем слишком много кода, давайте сделаем резервную копию, используя сценарий, который мы написали ранее, резервное копирование. Запустите этот сценарий в оболочке, подождите несколько мгновений, и весь код будет подкреплен в нашем репозитории GIT.

backup
Реализация формы относительно проста. Мы импортируем нашу форму, добавим обработчик запроса POST в представление и сохраняем сообщение в базе данных, прежде чем перенаправить в то же представление. Мы можем использовать функцию перенаправления, которую мы уже импортировали, и еще одну функцию, называемую реверс, чтобы получить URL для шаблона представления. Мы рассмотрим это с помощью строки «Feed: Feed», потому что пространство имен прилагаемого шаблона является подачей, а представление также называется Feed.

from feed.forms import PostForm

def feed(request):
    posts = Post.objects.all() # Запросите все сообщения в базе данных до сих пор
    if request.method == 'POST': # Обрабатывать запрос сообщения
        form = PostForm(request.POST) # Создайте экземпляр формы и сохраните в нем данные
        if form.is_valid(): # Проверить форму
            form.save() # Сохранить новый объект
        return redirect(reverse('feed:feed')) # Перенаправить на тот же URL -адрес с помощью запроса GET
    return render(request, 'feed/feed.html', {
        'form': PostForm(), # Обязательно передайте форму в контекст, чтобы мы могли ее представить.
        'posts': posts,
    })
Теперь нам нужно обновить шаблон для учета новой формы. Мы можем сделать это, используя
Оставьте в HTML и рендеринг формы в шаблоне HTML с помощью кнопки отправки. Нам также понадобится токен CSRF, токен, который предотвращает публикацию внешних сайтов в форму без первой загрузки страницы.
 
<!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>
 
Давайте разберем это. Есть новый класс форм, токен, сама форма и кнопка отправки. Довольно просто, но когда мы посмотрим на это, мы могли бы сделать его лучше. Это работает, мы можем публиковать новые сообщения с формой, и теперь они сохраняются в базе данных. Здесь происходит несколько вещей. Мы используем теги HTML, чтобы объявить, что документ является документом HTML, мы используем метку шаблона ({ %… %}) для отображения токена для формы, а другой - {{…}} для визуализации формы. У нас также есть цикл, чтобы отобрать текст, используя блок -теги и теги шаблона. Блок -теги действительно важны, потому что мы можем определить, как разделы шаблона отображаются с ними, а теги шаблонов являются основой того, как мы вкладываем переменные в наш код. Теперь нам нужно, чтобы наше приложение выглядело лучше, потому что сейчас оно выглядит действительно простым. Мы можем сделать это, используя CSS, либо встроенный, или в классах, связанных с каждым объектом в документе. CSS действительно хорош, потому что он говорит все на странице, как это должно выглядеть,И может заставить его выглядеть действительно хорошо. Есть несколько библиотек, которые могут сделать это, но мой личный ход - это начальная загрузка. Bootstrap можно загрузить с их веб -сайта,Getbootstrap.com/Полем Оказавшись там, нажмите кнопку, чтобы прочитать документы по установке, и скопируйте код из раздела Incult Via CDN. Вам понадобится этот код в верхней части вашего HTML -документа, в теге, называемом Head. Кроме того, давайте продолжим и создадим базовый шаблон, чтобы нам не нужно воссоздать эти ссылки в каждом шаблоне. Сделайте новый каталог, называемые шаблонами с шаблонами MKDIR, а затем редактируйте шаблоны/base.html. Это должно выглядеть так:
 
<!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>
 
Обязательно скопируйте CSS и JavaScript, файлы .CSS и .JS, потому что нам понадобится JavaScript, чтобы сделать наш сайт более функциональным в будущем. Теперь давайте вернемся к оболочке Bash и запустим быструю команду. Помните, что если вам когда -нибудь понадобится доступ к виртуальной среде, введите источник источника venv/bin/activate. Это позволит вам установить пакеты Python локально таким образом, чтобы Django получил доступ к ним. Чтобы дать наши формы, сгенерированные классами Django Bootstrap, мы будем использовать пакет Python под названием Crispy Forms. Мы можем скачать это со следующей командой

pip install django-crispy-forms
Как только это будет установлено, добавьте его в настройки.

INSTALLED_APPS = [
    # … Предыдущий код здесь
    'crispy_forms',
]
Теперь, в нашем шаблоне подачи, мы можем удалить некоторые вещи. Давайте удалим начало и окончание документа и заменим его наследством из нашего базового шаблона, используя Extends и определение блока. Кроме того, мы добавим импорт фильтра шаблона с помощью нагрузки и шаблон фильтра в форму. Наконец, давайте добавим класс начальной загрузки в кнопку в форме, чтобы он был более похожим на кнопку. Это должно выглядеть так:
 
{% 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 %}
 
Красивый! Это уже немного кода. Затем мы должны проверить это и убедиться, что мы видим, что все выглядит красиво, а также убедитесь, что все работает правильно. Запустите сервер в соответствии с предыдущими инструкциями и убедитесь, что сайт выглядит и работает хорошо. Отличная работа! Вы готовы перейти к следующему шагу, на котором мы добавим функциональность входа в систему пользователя, используя аналогичные URL -адреса, формы, представления и шаблоны. Базовый шаблон важен, и мы будем продолжать изменять его и вносить изменения по мере необходимости, но пока давайте сосредоточимся на том, чтобы сделать наш сайт более безопасным, позволив пользователям войти в систему с именем пользователя и пассажиров и в конечном итоге еще более важной информации, которая поможет сохранить ваше приложение в безопасности, а ваша собственная учетная запись доступна только вами. Для этого нам нужно использовать пользовательскую модель, встроенную в Django. Пользовательская модель представляет собой модель базы данных, как и наше сообщение, которое можно отобрать, чтобы войти в систему пользователя на веб -сайте. В будущем, прежде чем мы развертываем сайт в Интернет, мы будемРасширить эту модель с помощью других моделей, приписанных ей, и создайте дополнительные меры безопасности для входа в систему, которые устойчивы к фишингу. Мы начнем с использования некоторых встроенных форм входа в систему, которые предоставляет Django. Во -первых, давайте создадим новое приложение, которое мы будем использовать для визуализации шаблонов и представлений для основного входа в систему. Мы также создадим другие приложения для представления продолжающихся задач входа в систему, чтобы обеспечить приложение, включая пинкод, распознавание лица, ближнюю полевую связь, внешние устройства, многофакторную аутентификацию и распознавание отпечатков пальцев. Мы уже говорили о запуске приложения. Из нашего каталога, внутри виртуальной среды, пройти управление.

python manage.py startapp users
Теперь у нас должен быть каталог для нового приложения. Давайте начнем с создания представления в этом каталоге, который соответствует входу в систему пользователя. У Django есть встроенные представления для входов пользователей, но они не будут подходить для нас, потому что нам нужен пользовательский вид, который предпочтительно выполняется с определением. В этой точке мы начнем с проверки запроса POST, PASS QUERSE.POST в логинформу, импортируемое из DJANGO, аутентификации учетной записи пользователя и войдите в пользователь, прежде чем перенаправить их в наше приложение для подачи. В пользователях/views.py добавьте следующий код

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'] # Получите имя пользователя и пароль из запроса POST
        password = request.POST['password'] # Аутентификация пользователя
        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()})
Это все, что вам нужно для основного представления входа в систему. Теперь давайте создадим форму для представления, расширяя базовый шаблон. Мы начнем с создания нового каталога для шаблонов в папке пользователей.

mkdir users/templates
mkdir users/templates/users
Теперь мы должны быть в состоянии редактировать пользователей/шаблонов/пользователей/login.html. Пока мы находимся в этом, мы создадим шаблон, чтобы позволить пользователю зарегистрироваться.

nano users/templates/users/login.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 break">Log In</legend>
        {{ form|crispy }}
    </fieldset>
    <div class="form-group">
        <button class="btn btn-outline-info" type="submit">Login</button>
    </div>
</form>
{% endblock %}
 
Это основы шаблона входа в систему. Это действительно как другой шаблон в структуре, но он выглядит немного по -другому, когда он отображается. Мы можем скопировать этот код, чтобы создать еще один очень похожий шаблон под названием Register.html, где мы изменим формулировку и используем новую форму, которую мы строим. Давайте сначала сделаем шаблон. Редактировать пользователи/шаблоны/users/regist.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 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 %}
 
Теперь давайте создадим форму для нашей регистрации пользователя и вернемся к представлениям, прежде чем мы обновим наши пользовательские входы с помощью модели. Мы сделаем эту форму базовой для начала, но включим больше деталей и функций безопасности, таких как соглашения и Captcha в будущем. Отредактируйте формы с помощью Nano Users/forms.py и добавьте следующий код.

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']
Итак, у нас есть другая форма, которая работает довольно просто. Это форма регистрации пользователя с именем пользователя, электронной почтой и паролем, а также поле подтверждения пароля. Обратите внимание, что эта форма не расширяет обычный класс форм. Форма, это модельная форма, которая означает, что она имеет мета. Одно поле определяется точно так же, и классовая мета определяет модель, которую форма соответствует остальной информации, которая будет записана в форму. Большая часть этого уже существует в встроенной пользовательской форме Django, поэтому мы будем использовать это в качестве основы для класса (пройденное в скобках). Затем мы рассмотрим представление, чтобы зарегистрировать пользователя, теперь, когда у нас есть форма и шаблон. Это Modelform, как и тот, который в новом виде. Редактировать пользователи/views.py и добавить следующий код:

# ... суммы
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})
Это все, что нам нужно, чтобы зарегистрировать пользователя, но у нас должно быть больше информации. Мы хотим знать время, которое пользователь зарегистрировал, в какое время он был в последний раз на сайте, некоторая информация о них, такая как биография, часовой застрой моделируйте и атрибут сообщения каждому пользователю. Для этого мы обновим модели.py в обоих приложениях. Давайте начнем с редактирования модели подачи. Теперь это должно выглядеть так:

from django.db import models # ... суммы
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') # Добавить в эту строку
    text = models.TextField(default='')
Обратите внимание на вторую строку, которая была добавлена ​​в файл. Это иностранный ключ, который будет приписывать каждое сообщение одному пользователю на пост, поэтому мы можем убедиться, что мы сохраняем сообщения на основе пользователя на пользователь, и не может быть сделано никакое сообщение, не приписывая его пользователю. Мы определяем этот иностранный ключ с помощью класса, который он представляет, аргумент Delete, чтобы гарантировать, что сообщения удаляются с пользователями, нулевыми и пустыми аргументами, чтобы убедиться, что мы сможем удалить пользователя, если это необходимо, и приспособиться к отсутствию пользователя на сообщениях, которые мы уже уже Создано, и связанное имя, которое мы можем использовать для обозначения объектов POST, которые создает пользователь. Это связанное имя, в отличие от Post.author, автор сообщения, дает нам пользователя, который разместил сам пост. Теперь мы можем получить сообщения, созданные пользователем, используя user.posts.all () или author.posts.all (). Теперь давайте сделаем наши логины более устойчивыми. Мы уже можем сделать наш сайт гораздо менее уязвимым для фишинга, просто ограничивая количество раз, сколько раз мы допустим вход вСайт, это довольно просто. Давайте также начнем хранить некоторую информацию о каждом пользователе, прежде чем мы продолжаем разрабатывать наше приложение. Редактирование пользователей/models.py, добавьте следующее

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='')
Обратите внимание, что эта модель довольно похожа на модель Post. У нас есть дополнительный импорт Timezone, который позволит нам устанавливать значения по умолчанию в областях DateTime, и у нас также есть символ и текстовое поле, как сообщение. Использование всех этих временных метров помогает нам обеспечить сайт и понять его использование, и текстовые поля позволяют нам показывать информацию о каждом пользователе или авторе на веб -сайте. Onetoonefield должен быть единственным незначительным соображением, он ведет себя точно так же, как и у Foreginkey, но только с одним на последующую модель. Таким образом, у пользователя есть только один профиль, в то время как у него может быть много постов. Теперь давайте улучшим наш вход в систему и зарегистрируйте представления, чтобы учесть профиль. Во -первых, редактировать пользователи/views.py и сосредоточиться на представлении регистрации:

# ... суммы
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) # Обязательно добавьте эту строку, чтобы создать профиль для пользователя
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
Это просто создает профиль для пользователя, не заполняя какую -либо информацию. Теперь мы хотим убедиться, что учетная запись пользователя не может быть зарегистрирована слишком часто, или, по крайней мере, пароли не могут быть опробованы слишком часто, поэтому давайте обновим представление входа в систему.

# ... суммы
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(): # Обратите внимание, что теперь мы проверяем, может ли пользователь войти в систему
            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.')
            user = User.objects.filter(username=username).first() # Это та часть, где мы обновляем профиль пользователей
            if user: 
                profile = user.profile
                profile.can_login = timezone.now() + datetime.timedelta(seconds=15) # Так что они не могут снова войти в систему в течение нескольких секунд
                profile.save()
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
Это основная фундаментальная безопасность. Убедитесь, что сайт не уязвим для кого -то, просто пробуя каждую возможную комбинацию паролей, или даже некоторые из них одновременно. Это не будет разочаровывает обычного пользователя, который знает свой пароль и просто входит в систему на нескольких устройствах, но он будет выдержать многочисленные фишинговые роботы от приложения. Обратите внимание, что мы добавили оператор IF с переменной, Can_Login, который должен быть временем в прошлом, и обновить его с помощью каждого неудачного входа в систему, используя одно и то же имя пользователя. Таким образом, вредоносный пользователь не сможет угадать пароль, где -нибудь приближается. Количество секунд в datetime.timedelta () также может быть обновлено, и веб -сайт будет более устойчивым, но немного менее полезным с большим количеством секунд. Я рекомендую 15, чтобы начать с. Помните, что мы построили резервный сценарий, чтобы сохранить нашу работу, поэтому давайте пойдем и подтвердим то, что у нас есть, чтобы убедиться, что у нас все сохранилось. Запустите команду:

sudo backup
Еще раз, это до сих пор спасет вашу работу. Я рекомендую запускать частые резервные копии, чтобы сохранить вашу работу, и вы даже захотите автоматически запустить резервное задание. Вы можете сделать это с помощью утилиты Unix под названием Cron. Чтобы активировать эту утилиту, запустите следующую команду и введите свой пароль:

sudo crontab -e
Если вы еще не выбрали опцию 1 для Nano, текстового редактора, с которым вы уже должны быть знакомы, и прокрутите в нижней части файла, используя клавиши со стрелками. Добавьте следующую строку:

0 * * * * sudo backup
Cron использует формат минуты, час, день месяца, месяца, дня недели, где A * или число представляет собой, когда запустить команду. Используя 0 в течение минуты и * для остальных вариантов, мы можем запустить команду на первую минуту каждого часа в начале минуты. Это позволяет нам автоматически создавать резервную копию кода. Все задания Cron при выполнении с Sudo Run в качестве root, поэтому нам не нужно будет вводить пароль каждый час. Чтобы облегчить резервное копирование нашего кода без использования пароля, давайте отключим пароль для нашей команды резервного копирования. Мы сделаем это, выполнив следующую команду и введя пароль:

sudo visudo
Теперь давайте прокрутим в нижней части файла и добавим другую строку:

ALL ALL=NOPASSWD: /bin/backup
Это позволяет нам запустить команду «резервное копирование» как любого пользователя, без пароля. Формат для этого прост, просто префикс строки с «All All = nopasswd:/bin/» и заканчивается командой, например,/bin/backup, который существует в/usr/bin/. Теперь давайте начнем работать с электронной почтой. Электронная почта действительно важна для веб -сайтов, потому что это способ сохранить более безопасный веб -сайт, проверить, что пользователи являются реальными людьми, и даже продают продукты или услуги для клиентов. Многие люди, которые часто посещают интернет, ежедневно проверяют свою электронную почту и получают всевозможные маркетинговые электронные письма о продуктах и ​​услугах, которые им интересны. Есть несколько вариантов, когда речь идет о включении электронной почты на веб -сайте Django, и вы можете выбрать что бы ни лучшее было для вас. Во -первых, вы можете оплатить услугу по электронной почте, которая позволит вам отправлять электронную почту из вашего домена и требует минимального кода. Есть много сервисов, которые предлагают это, такие как Google Workspace, Sendinblue, Mailgun и многое другое. В противном случае вы хорошо зданиеВаша собственная служба электронной почты на вашем сервере с нуля. Я рекомендую этот вариант, хотя это больше кода и может потребовать специального хостинга. Вы не сможете запустить почтовый сервер с вашего домашнего компьютера, поэтому давайте рассмотрим конфигурацию и код для отправки электронной почты, прежде чем запустим сервер в облаке и создадим наш собственный почтовый сервер внутри. Во -первых, редактировать настройки.py со следующим

nano app/settings.py
Где приложение - это имя приложения, которое вы создали с StartApp. Добавьте следующие строки:

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)
Обязательно измените их, когда вы будете готовы развернуть свое приложение, мы вернемся к этому позже. Настройка email_address должна быть электронной почтой, с которой вы хотели бы отправить, а пароль (email_host_password) должен быть установлен на пароль, который вы генерируете для сервера. Я загружаю пароль из файла конфигурации, чтобы не допустить его из кода, используя следующую логику, над этими строками в Sturts.py:

import os
import json
with open('/etc/config.json') as config_file:
    config = json.load(config_file)
Затем я настроил файл JSON с конфигурацией в /etc/config.json, используя NANO следующим образом. Редактировать файл:

sudo nano /etc/config.json
Добавьте следующие строки:

{
	“EMAIL_HOST_PASSWORD”: “<some password here>”
}
Мы будем продолжать редактировать файл конфигурации и добавлять все пароли и ключи, которые мы будем использовать в приложении. На данный момент давайте быстро рассмотрим, как отправить электронное письмо с помощью Python. Во -первых, давайте создадим шаблон для проверки электронной почты, которое мы можем отправить нашим пользователям, и поместить его в каталог пользовательских шаблонов. Этот шаблон будет написан в 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>
 
Это электронное письмо довольно простое. Требуется контекст пользователя, базовый URL для сайта, а также идентификатор пользователя и токен, которые используются для проверки электронной почты пользователя. Обязательно определите базовый URL в настройках. Идите вперед и добавьте следующие строки в App/sutres.py, ближе к началу.

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

BASE_URL = PROTOCOL + '://' + DOMAIN
В конце концов, когда ваш сайт будет готов к Интернету, и вы разверните его, вы захотите определить свой домен как доменное имя, которое вы покупаете для представления сайта. Это имя, которое вы будете вводить в Navbar, чтобы получить доступ к вашему сайту. На данный момент вы можете покинуть домен пустым или использовать заполнителя. Вы также захотите изменить сайт_name на имя, которое вы хотите дать вашему сайту, по вашему выбору. Прежде чем отправлять электронную почту, давайте создадим генератор токенов, чтобы у нас был токен активации аккаунта, который никогда не истекает. Мы можем сделать это, создав и импортировав токен активации аккаунта, который выглядит как следующее. Измените файл:

nano users/tokens.py
Добавьте следующий код:

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()
Этот базовый генератор токенов генерирует токен, который мы можем отправить пользователю в URL -адрес, и пользователь может использовать для проверки своей электронной почты и активировать свою учетную запись. Далее, давайте посмотрим, как отправить электронное письмо. Используя NANO, отредактируйте пользователей/email.py.

nano users/email.py
Отправка проверки электронной почты HTML будет выглядеть следующим образом:

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)
Это довольно просто. Мы импортируем функции, которые нам нужно отправить электронную почту, отображать электронное письмо с шаблонами и наши настройки, а затем мы определяем электронное письмо по имени шаблона и отправляем его пользователю, используя функцию. Вы заметите, что мы еще не определили функцию для отправки почты, send_html_email, так что давайте напишем это ниже кода, который мы уже добавили пользователям/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()
Это немного сложнее, и мы еще не готовы запустить весь этот код. Обратите внимание, что мы определяем UNSUB_LINK, ссылку, которую пользователь может использовать для отмены подписки на наши электронные письма. Это важно, потому что пользователи должны будут иметь возможность отказаться от наших электронных писем, если они не хотят их видеть, в любое время. Мы также добавляем текстовую альтернативу нашему сообщению, которое представляет собой HTML -сообщение, лишенное тегов HTML. Наконец, мы проверяем, отправлено ли электронное письмо, и если это не так, мы отмечаем в профиле пользователя, что их электронная почта не является действительной. Давайте вернемся к моделям пользователей, чтобы мы могли сделать все это работать. Нам необходимо определить функцию для создания ссылки на отмену подписки, и определить логическое поле, чтобы отметить, что электронное письмо пользователя недопустимо. Сначала добавьте следующий импорт в верхнюю часть пользователей/модели.py

nano users/models.py

# …
from django.core.signing import TimestampSigner, BadSignature, SignatureExpired
from django.urls import reverse
Далее, давайте добавим функции в пользовательскую модель, чтобы сделать токен и проверить токен, используемый для активации электронной почты, а также поле, чтобы сохранить, успешно ли пользователь получает свою почту. В пользователях/моделях.

# …
    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) # Действительно в течение 30 дней
        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,})
Это довольно просто, мы используем TimeStSigner, который является основным криптографическим инструментом, для создания токена, который истекает через определенное время, и мы также используем другую функцию, чтобы проверить, действителен ли он. Мы используем эти токены дважды, один раз, чтобы проверить электронную почту, и один раз для ссылки от подписки. Теперь, когда у нас есть это, последняя работа, которую нам нужно будет сделать, - это в взглядах. В пределах пользователей/views.py давайте добавим представления, чтобы проверить адрес электронной почты и отказаться от подписки.

nano users/views.py
Во -первых, добавьте следующий импорт. Я добавил несколько дополнительных, поэтому нам не придется импортировать больше предметов позже.

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 # Обязательно импортируйте функцию отправки электронной почты проверки
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
Возможно, у вас уже есть некоторые из этих импортов, но это не повредит их повторять. Вам нужно будет импортировать функцию отправки электронной почты для проверки, а также account_activation_token от users.tokens, а также другие импорты. Теперь, в нижней части файла, добавьте следующий код:

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)):
        # Отписать их
        profile = user.profile
        profile.subscribed = False
        profile.save()
        return render(request, 'users/unsubscribe.html')
    # В противном случае перенаправить на страницу входа в систему
    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 (запрос, пользователь)
        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})
Это много кода. Давайте разберем это. Первая функция, чистая и простая, отписывает пользователя из списка рассылки. Вторая функция активирует их электронную почту, и вы заметите, что я добавил комментированную функцию, SendWelcomeMail. Вы можете использовать шаблон электронной почты и определение функции, чтобы отправить приветственное электронное письмо, я просто еще не сделал. Последняя функция, которую я бросил, важна, потому что истекают электронные письма с активацией. Поэтому нам нужно будет отправить электронное письмо с активацией некоторое время. Мы можем использовать базовую форму для этого и вызвать функцию, чтобы отправить электронное письмо с проверкой. Прежде чем мы это сделаем, давайте убедимся, что он будет отправлен в первую очередь, добавив функциональный вызов в представление регистра. Добавьте эту строку непосредственно перед перенаправлением в представлении регистра, DEF Register, в пользователях/views.py.

nano users/views.py

# … (После) def Register (запрос):
            send_verification_email(user)
# … (Прежде) перенаправить (
Вам не нужно добавлять первые и последние строки в этот фрагмент кода, просто убедитесь, что представление регистра отправляет электронное письмо с проверкой пользователю. Это должно выглядеть так:

# ... суммы
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) # Обязательно добавьте эту линию!
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
Теперь нам нужно добавить форму, чтобы отправить электронное письмо с активацией. В пользователях/forms.py добавьте следующую форму:

# … (Суммы)
class ResendActivationEmailForm(forms.Form):
    email = forms.EmailField(required=True)
Нам также понадобится шаблон, соответствующий этой форме активации электронной почты. Давайте добавим этот шаблон. Изменить файл:

nano users/templates/users/resend_activation.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">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 %}
Вот, это много! Теперь, когда мы развертываем код на нашем сервере, мы сможем отправлять электронную почту HTML и активировать учетные записи пользователей с помощью щелчка по электронной почте. Мы также можем прислать простое приветственное электронное письмо, так что давайте посмотрим, как это сделать. Вернуться в пользователи/email.py, добавьте следующий код:

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)
Кроме того, нам понадобится шаблон, чтобы представить всю эту информацию. На моем веб -сайте шаблон выглядит как ниже, но вы можете отформатировать его, как вам нравится.
 
<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>
 
Обратите внимание, что у нас нет закрывающих тегов тела или HTML, потому что мы добавляем их, когда добавляем ссылку HTML USOUBSCRIBE. Это важно, но мы не хотим определять их дважды. Так что же дальше? Мы прошли долгий путь. На самом деле, мы должны быть готовы развернуть сайт на сервер. Мы можем добавить декоратор @Login_Required и сделать наши взгляды в защите, принять пользовательские регистрации, отправить соответствующую электронную почту и информацию о кеше, что является основой того, что должен сделать веб -сайт, чтобы оставаться актуальным. Мы добавим еще несколько полезных функций, а затем создадим основу для развертывания нашего кода на удаленный сервер, настройку почтового сервера, конфигурации домена и фильтров, чтобы сделать наш сайт безопасным и подходящим. Нам также понадобится представление сброса пароля, поэтому давайте очень быстро добавим это. Встроенное представление Django сброса пароля сломано в некоторых функциях, но мы рассмотрим, как написать наш собственный представление, шаблон электронной почты, формы и шаблоны URL. Вот как выглядит представление, в пользователях/views.py

# ... суммы
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)
Эта форма встроена в Django, но нам понадобится шаблон для подтверждения сброса пароля, пользователей/шаблонов/пользователей/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 %}
 
У нас также есть шаблон для отправки электронной почты сброса пароля с простой формой, в пользователях/шаблонах/пользователях/password_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 %}
 
Шаблон для самого электронного письма прост, это базовый html -файл, рендеринг ссылки для сброса пароля, в пользователях/шаблонах/пользователях/password_reset_email.html. Джанго автоматически интерпретирует этот файл.
 
<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>
 
Нам также понадобится еще два шаблона. Первое - подтвердить, что электронное письмо было отправлено. Взгляды на них уже в Джанго, поэтому нам просто нужно обратиться к ним в urls.py. Этот шаблон расположен в пользователях/шаблонах/пользователях/password_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 %}
 
И, наконец, чтобы подтвердить, что сброс пароля завершен, пользователи/шаблоны/пользователи/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 %}
 
Теперь нам нужны шаблоны URL для этих взглядов. В пользователях/urls.py добавьте следующие шаблоны URL:

urlpatterns = [
    # ... предыдущие URL -адреса здесь
    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'),
]
Четыре шаблона, это много! Но теперь мы можем быть уверены, что сможем сбросить пароль пользователя в любое время, когда нам нужно, все из веб -браузера. Я понимаю, что это много кода. Если это кажется немного над вашей головой, это нормально. Вы улучшите, ваше понимание улучшится, и вы скоро станете гораздо более компетентным с кодом. Если вы полностью потеряны, я рекомендую вернуться к этому программному обеспечению позже после работы над самостоятельным курсом Code Code Online. Обычно они могут начать работу, и будут вести вас через все, что вам нужно, чтобы добиться успеха, когда вы вернетесь к этому проекту. Если вы чувствуете, что готовы к продолжению, прочитайте дальше, мы рассмотрим развертывание вашего кода на удаленный сервер и настройку почтового сервера, а также автоматизируют ваше развертывание с помощью BASH, чтобы вы всегда могли настроить новый проект с Несколько простых команд. Последнее, что нам нужно сделать, прежде чем развернуть на удаленном сервере, это сделать наш сайт немного более безопасным. ТыОбратите внимание, что представление входа в систему занимает только имя пользователя и пароль, и нет многофакторной аутентификации или одноразового кода. Это простое исправление, и с тем же кодом мы можем заставить наш сайт отправлять текстовые сообщения и даже отвечать на текстовые сообщения, отправленные на сервер. Для начала мы вернемся в пользовательские модели и добавим подписавшееся временные метки, которая будет представлять каждый логин. Мы также добавим уникальный вращающийся идентификатор в модель пользователя, который будет использоваться для добавления дополнительной безопасности в наш вход. Редактирование пользовательских моделей, пользователей/models.py, добавьте следующее

from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
# Обязательно импортируйте UUID, TimeStamp Signer и Generator (обратный)
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='')
    # Добавьте этот код здесь
    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)

    # И добавить эту функцию
    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) # Действительно в течение 3 минут
        except (BadSignature, SignatureExpired):
            return False
        return True
Убедитесь, что ваши пользователи/модели. Разбивая это, это просто. У нас есть несколько импортов, временный ламп, который представляет собой криптографическую утилиту, которая может генерировать безопасный код и проверить его, чтобы убедиться, что он действителен, использовался только один раз, а не старше определенного количества секунд. Мы также используем UUID, который является уникальным идентификатором, который идентифицирует нашего пользователя при подписании токена и в URL, где токен отправляется пользователю. Мы будем использовать эту базовую криптографию для создания двухфакторного представления аутентификации. Прежде чем мы сделаем что -нибудь еще, давайте запустим миграции, чтобы наши пользовательские модели были обновлены. В каталоге с Manage.py запустите следующие команды, чтобы выполнить и завершить миграции.

source venv/bin/activate
python manage.py makemigrations && python manage.py migrate
Это важно, потому что каждый раз, когда мы вносим изменения в модели, нам нужно будет создать таблицы и обновить базу данных с помощью по умолчанию, прежде чем мы сможем на самом деле использовать модели. Далее, давайте импровизируем наше представление о входе в систему, чтобы перенаправить на вторичный вид аутентификации. В пользователях/Views.py удалите функцию входа в систему и перенаправьте на URL, который мы только что сгенерировали в пользовательских моделях.

# ... суммы

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(): # Обратите внимание, что теперь мы проверяем, может ли пользователь войти в систему
            # Удалить функцию auth_login, которая была здесь
            messages.success(request, 'Your password was accepted. Please continue.')
            if user.profile.mfa_enabled:
                return redirect(user.profile.create_auth_url()) # Примечание мы перенаправляем на новый URL
            else: # Если пользователь не использует многофакторную аутентификацию, просто войдите в систему.
                auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
                return redirect('feed:feed')
        else: # Если логин не был успешным,
            messages.warning(request, 'Username or password incorrect. Please try again.')
            user = User.objects.filter(username=username).first() # Это та часть, где мы обновляем профиль пользователей
            if user: 
                profile = user.profile
                profile.can_login = timezone.now() + datetime.timedelta(seconds=15) # Так что они не могут снова войти в систему в течение нескольких секунд
                profile.save()
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
Так что это довольно просто, теперь у нас есть способ перенаправить в представление двух факторной аутентификации, когда мы его создаем. У нас также есть резерв в случае, если пользователь не добавил номер телефона. Мы добавим базовый вид, чтобы скоро добавить номер телефона и вскоре войти в систему с текстовым сообщением. Во -первых, нам нужен простой способ отправить текстовое сообщение из нашего кода. Для этого мы можем выбрать из ряда API, но самый простой, на мой взгляд, это Twilio. Они также предлагают хорошие цены на небольшие проекты, а также объемные скидки. Создайте учетную запись на Twilio.com, заполните некоторые подробности о вашем проекте, купите номер телефона и скопируйте свои ключи API на свой настройки. Затем добавьте этот код в новый файл, пользователи/sms.py.

nano users/sms.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
import traceback

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

# Этот код отправляет текст с 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())

# Вспомогательная функция, чтобы получить номер с таким количеством цифр
def get_num_length(num, length):
    n = ''
    for x in range(length):
        n = n + str(num)
    return int(n)

# Отправить текст, чтобы проверить пользователя
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)))

# Отправить пользователю любой текст с этой функцией
def send_user_text(user, text):
    send_text(user.profile.phone_number, text)

# Проверить код этой функцией
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

# Подтвердить время
def check_verification_time(user):
    result = user.profile.mfa_code_expires > timezone.now()
    return result
Обязательно измените свои настройки соответствующим образом, добавив эти строки с помощью ключей:

# Обязательно скопируйте их со своей панели мониторинга 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 # Количество минут, которые страница TFA активна после экземпляра
Во -первых, нам понадобятся формы для наших двух факторных представлений аутентификации. Редактирование пользователей/forms.py, добавьте следующий код.

# ... суммы
from django import forms

# Форма для ввода нашего номера телефона
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

# Форма для аутентификации
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.'
    }
Далее, давайте создадим представления в пользователях/views.py

# ... суммы
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})
Нам также понадобятся шаблоны для обоих этих взглядов. Давайте сначала добавим шаблон MFA.

nano users/templates/users/mfa.html
Добавьте этот HTML -код в шаблон
 
{% 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 %}
 
Это довольно самостоятельно. Форма отправляет либо код, либо пустой код, и вы заметите в представлении, что мы отправляем код, если получим пустой код. Тогда у нас просто есть две кнопки отправки, и таким образом мы можем отправить код с любой кнопкой. Далее мы добавим простую форму, чтобы добавить номер телефона.

nano users/templates/users/mfa_onboarding.html
Добавьте следующий 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 %}
 
Эта форма намного проще, она просто отображает форму телефона, которую мы создали, и позволяет пользователю добавить номер телефона. Это выглядит действительно хорошо! Пока все правильно настроено, мы должны быть в состоянии отправлять сообщения и ввести пользователя по номеру телефона, как только добавим шаблоны URL. Последнее, что нам нужно настроить, - это представление профиля, поэтому мы можем убедиться, что пользователь может изменить свой номер телефона, не будучи входом «Остановите», чтобы отказаться от будущих текстовых сообщений. Давайте добавим представление профиля в пользователи/views.py. Эта точка зрения обновит биографию пользователя, электронную почту, имя пользователя и номер телефона, а также позволит нам включить многофакторную аутентификацию. Во -первых, нам понадобятся еще две формы в пользователях/forms.py

# ... импорт
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']
Далее мы можем создать представление, чтобы использовать обе эти формы. Редактировать пользователи/views.py и добавить в представление.

# Добавьте этот импорт
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)
Нам также нужен шаблон для этой точки зрения.

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 %}
 
Вы заметите, что это довольно простая форма, но в нем есть какой -то JavaScript, который автоматически публикует содержимое формы по мере их обновления. Это полезно, поэтому вы можете вносить изменения без необходимости нажимать на отправку каждый раз. Затем нам нужны URL -адреса, представляющие все эти представления в паттернах URL -адресов пользователей. Редактировать пользователи/urls.py и добавить этот код:

# … Предыдущий код, импорт
from django.urls import path
from . import views

app_name='users'

urlpatterns = [
# … Узоры URL, которые мы ранее ввели, добавьте следующие три строки
    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'),
]
Сейчас хорошее время, чтобы проверить наш проект. Но сначала давайте запустим еще одну резервную копию.

backup
И запустить сервер. Прежде чем мы развертываем на сервере Linux, рекомендуется включить двух факторную аутентификацию в учетной записи. Мы сделаем это, перейдя на URL нашего профиля,/пользователи/профиль/, и проверим поле, чтобы включить аутентификацию после входа в наш номер телефона, а затем отправить форму.

python manage.py runserver localhost:8000
Посетите веб -страницу, перейдя в ваш веб -браузер, я использую Google Chrome в этом примере и введя URL https: // localhost: 8000/accounts/profile/ Вы сможете войти в систему при необходимости и включить двух факторную аутентификацию. Этот проект нуждается в сервере для работы, чтобы он мог действительно отправлять почту. Но сначала нам нужен способ увидеть ошибки. Вы заметите, что если вы запустите сервер в режиме отладки, с настройками. Чтобы показать ошибки без использования режима отладки, который небезопасен на производственном сервере, мы должны добавить для него представление. Наиболее важные ошибки, которые нам нужны для обработки, - это: Ошибка 500 - Проблема с нашим кодом Ошибка 404 - страница, которая не была найдена (разбитый URL) Ошибка 403 - разрешение отказано в ошибке Давайте добавим новое приложение для обработки этих ошибок, называемых ошибками.

python manage.py startapp errors
Добавьте это в настройки.

handler404 = 'errors.views.handler404'
handler500 = 'errors.views.handler500'
handler403 = 'errors.views.handler403'
Это все, что нам нужно, кроме видов ошибок, шаблонов и немного промежуточного программного обеспечения. Давайте определим их как так:

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

# Создайте свои взгляды здесь.
@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.'})
Затем давайте определим промежуточное программное обеспечение для обработки этих ошибок. Мы сделаем это, сначала добавив в Middleware_classes в sutres.py с именем нашего промежуточного программного обеспечения.

MIDDLEWARE_CLASSES = [
    # ... предыдущее промежуточное программное обеспечение
    'errors.middleware.ExceptionVerboseMiddleware,
]
Далее, давайте добавим промежуточное программное обеспечение.

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.')
Мы добавляем функцию, чтобы получить текущее исключение, используя локальный поток, который помогает нам проследить любые ошибки в нашем коде. С точки зрения шаблонов, нам нужен только один, потому что мы динамически определяем заголовок в представлении. Шаблон просто должен отображать заголовок и «трассировку», нашу ошибку трассировки из контекста.

nano errors/templates/errors/error.html
 
{% extends 'base.html' %}
{% block content %}
<h1>{{ pagetitle }}</h1>
<p>{{ trace }}</p>
{% endblock %}
 
Это наш самый простой шаблон, но так легко увидеть ошибки в нашем проекте. Далее давайте отключим отладку в настройках.

nano app/settings.py
Найдите эту строку, в которой она установлена ​​на TRUE, и измените ее на ложь

DEBUG = False
Идите вперед и резервную копию приложения сейчас. Мы готовы развернуть на удаленном сервере Linux и продолжать добавлять оттуда.

sudo backup
Прежде чем мы опубликуем этот код на сервере, мы должны учитывать, что могут возникнуть некоторые проблемы с кодом. В зависимости от случая, сайты, которые принимают информацию, размещенную для них, будут иметь проблемы с публикацией спама и затруднению удаления спама. Это не должно произойти сразу, но если это произойдет, мы позже рассмотрим, как автоматически смягчить спам на сайте и упростить для роботов доступ к сайту, а также как деактивировать учетные записи и проверить личность пользователя с помощью сканирование их удостоверения личности или биометрического сканирования, например, отпечаток пальца или распознавание лица. Глядя на пример многофакторной аутентификации, который мы изучили в производстве, все может быть иначе. Обратите внимание, как мы являемся ограничивающими ставками, и истекают токены. Если роботы получают доступ к сайту, двух факторная аутентификация может быть более сложной, поскольку они могут вводить коды одновременно, когда пользователь. Чтобы бороться с этим, давайте использовать модель в моделях пользователей, заявив, как мы взаимодействуем с сайтом, когда мыАутентификация с использованием многофакторной аутентификации с номером телефона. Мы также добавим опцию для аутентификации по электронной почте. Начните с редактирования моделей пользователей с

nano users/models.py
Это то, как должна выглядеть модель, которую мы добавляем. Нам не нужны какие -либо методы, просто переменные для хранения идентификатора, пользователя, TimeStamp, истечения срока действия, длины и попыток против любой многофакторной аутентификации (код, такой как 123456, отправленный на телефон или электронную почту).

# Основной токен, используемый для входа на веб -сайт
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)
Давайте также добавим привилегию к нашему пользователю, и мы на данный момент установим его вручную, прежде чем в конечном итоге переехать, чтобы автоматически привлечь привилегированных пользователей. В пользовательских моделях добавьте эту строку в профиль:

    vendor = models.BooleanField(default=False)
Как и в случае любых изменений в базе данных, нам нужно сделать миграции и перенести базу данных в любое время, когда мы редактируем файл моделей.py в Django. Помните, что для этого мы сначала используем источник (если он еще не использовался с момента открытия терминала), а затем Python Manage.py, чтобы сделать миграции и миграции.

cd project-directory-you-named # (при необходимости)
source venv/bin/activate
python manage.py makemigrations && python manage.py migrate
На данный момент вы можете заручиться любыми учетными записями, которые вы создали в качестве поставщиков, используя оболочку.

python manage.py shell
from users.models import Profile
p = Profile.objects.get(user__username='Charlotte')
p.vendor = True
p.save()
exit()
Теперь давайте развиваем нашу многофакторную аутентификацию, чтобы использовать этот токен. Во -первых, нам нужно изменить наши утилиты MFA Helper. Используя 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

# Аутентификация пользователя, используя их электронную почту или номер телефона
def mfa(request, username, usertoken):
    token = MFAToken.objects.filter(uid=username, expires__gt=timezone.now() + datetime.timedelta(seconds=30)).order_by('-timestamp').last() # Отфильтруйте токен по значению, передаваемому в URL (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)) # Если этот сеанс не был создан, создайте его
    user = User.objects.filter(id=token.user.id).first() # Получить пользователя из токена
    if not user and request.user.is_authenticated: return redirect(reverse('feed:home')) # Если они уже аутентифицируются, войдите в них
    if not user: raise PermissionDenied() # Отрицать, если пользователь не найден
    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): # Проверьте токен AUTH
        auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Войдите в пользователя, если он еще не вошел в систему
        user.profile.mfa_expires = timezone.now() + datetime.timedelta(minutes=settings.LOGIN_VALID_MINUTES) # Установите истечение срока их многофакторной аутентификации
        user.profile.save()
        return HttpResponseRedirect(next if next != '' else reverse('landing:landing')) # Перенаправить пользователя на следующую страницу
    if not user.profile.mfa_enabled: # Проверьте, включена ли MFA
        if not check_verification_time(user, token): # Проверьте время
            user.profile.mfa_enabled = False # Очистить номер телефона
            user.profile.enable_two_factor_authentication = True # Включить MFA
            user.profile.phone_number = '+1' # Отключить номер телефона
            user.profile.save() # Сохраните профиль
            auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Войдите пользователя, если их MFA не включен
            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): # Если запрос является запросом почты
        form = TfaForm(request.POST) # Создавать форму
        code = str(form.data.get('code', None)) # Получите код
        if code and code != '' and code != None: # Убедитесь, что это не пусто
            token_validated = user.profile.check_auth_token(usertoken) # Проверьте токен AUTH
            p = user.profile
            is_verified = check_verification_code(user, token, code) # Проверьте код
            p.mfa_authenticated = is_verified
            if token_validated: # Если все
                if is_verified: # В порядке
                    user.profile.mfa_enabled = True # Включить MFA (если еще не включено)
                    user.profile.save()
                    auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Войдите в пользователь
                    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(): # Создайте запрос для следующего параметра (если есть)
                        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) # Перенаправить
                    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: # Если жетон был недействительным
                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()
            if form.data.get('send_email', False): # Отправить электронное письмо (или текст)
                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('/'))
    # Видрировать форму (для получения запросов)
    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'})
Когда мы добавляем в этот код, обязательно импортируйте функцию для отправки электронной почты. В верхней части файла представления пользователя (с другими импортами), добавьте

from .mfa import send_verification_email as send_mfa_verification_email
Теперь нам нужно написать эту функцию, прежде чем что -либо из этого сработает. Он должен расширить нашу функцию отправки электронной почты и просто отправить пользователю электронное письмо с кодом проверки.

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))
Так что все это отлично работает, теперь у нас есть многофакторная система аутентификации, которая зависит от номера телефона или электронной почты для входа. Но нам также нужен способ удалить или, по крайней мере, скрывать пользователей, которые не сотрудничают с нашими условиями. Это могут быть спамеры, роботы или любой, кто плохо значат для нашей работы. Посмотрите на представление, которое я имею для мониторинга пользователей на моем сайте:

# суммы
from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import user_passes_test
from .tests import is_superuser_or_vendor # Нам нужно будет создать этот тест

@login_required
@user_passes_test(is_superuser_or_vendor)
def users(request):
    # Получите список пользователей
    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', { # Вернуть пользователей в шаблоне
        'title': 'All Accounts',
        'users': User.objects.all(),
        'new_today': new_today,
        'new_this_month': new_this_month,
        'subscribers': subscribers
    })
Обратите внимание, что этот код использует тест, нам нужно будет объявить этот тест в файле tests.py и импортировать его. Редактирование пользователей/tests.py, давайте создадим тест.

def is_superuser_or_vendor(user):
    return user.profile.vendor or user.is_superuser
Это в сочетании с шаблоном users/users.html, который выглядит примерно так:
 
{% 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 %}
 
Обратите внимание, что шаблон включает в себя еще один шаблон, пользователи/_user.html. При использовании шаблона, который имеет подзагентный и не использующий Extends, это хорошая идея добавить подчеркивание (_) перед именем файла для расширения, чтобы отличить шаблоны. Обратите внимание, что это много джинджи, у вас, возможно, не определены все эти переменные. Но это то, на что выглядит мой код.
 
{% 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}} </small>
      <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>
 
Нам также нужен еще один почильник, toggle_active.html. Этот шаблон должен быть формой, которая позволяет нам переключать, активен ли пользователь.
 
<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>
 
Нам также нужно будет добавить представление, чтобы переключить активность пользователя и соответствующие шаблоны URL. Пока мы находимся в этом, давайте добавим представление, чтобы удалить пользователя на случай, если нам это понадобится.

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>')


# Суммы
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.views.generic import DeleteView

class UserDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    model = User
    success_url = '/' # Перенаправление на URL успеха
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        return context

    def test_func(self): # Проверьте, является ли пользователь суперпользователь и имеет разрешение на удаление
        user = self.get_object()
        if self.request.user != user and self.request.user.is_superuser:
            return True
        return False
Хотя это практично, когда это необходимо, удаление пользователя не должно потребоваться большую часть времени, мы можем просто переключить видимость пользователей, которые посещают сайт, если нам нужно их уволить. Узоры URL, которые мы добавили, выглядят так. С Nano отредактируйте пользователей/urls.py и добавьте эти строки:

nano users/urls.py
Линии должны идти в списке путей в представлениях пользователей, до окончания «]», но после начала «[».

# …
    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'),
# …
Теперь обязательно сделайте резервную копию сайта, чтобы вы могли загрузить его на веб -сервере, над которым мы продолжим работать. Из командной строки,

sudo backup
Теперь наш сайт резервирован. Так что теперь у нас есть еще несколько полезных функций. Но как насчет общей картины здесь? Этот код по -прежнему не доступен из Интернета, у нас еще нет почтового сервера, и нам нужно расширить наше приложение, чтобы включить комплексный процесс проверки, а также плавные макеты, чтобы помочь нам исследовать сайт, а также безопасные протоколы для аутентификации привилегированных пользователей Полем Мы доберемся до всего этого. Самым важным на данный момент будет просто получить этот код онлайн, что мы можем сделать с несколькими линиями Bash на сервере Ubuntu. Вам нужно будет арендовать сервер для этого, если только у вас нет сервера дома и бизнес -подписка в Интернете, которая позволяет вам открывать порты. Я лично запускаю свой веб -сайт на HP Z440, который установлен в моей квартире, но обычно это намного дешевле для базовых потребностей в аренде виртуального частного сервера (VPS). Имейте в виду, что код, который мы используем сейчас, относительно тонкий, его нужно будет поддерживать и улучшить, прежде чем мыГотовы использовать то, что мы должны построить продукт. Обязательно будьте осторожны с тем, что вы делаете с Интернетом, убедитесь, что если вы публично развернете этот сайт в Интернете на сервере Linux, у вас есть план, чтобы блокировать нежелательные взаимодействия с вашим веб -сайтом. Сначала это не будет проблемой, но мы рассмотрим различные решения для борьбы с этим, включая машинное обучение, искусственный интеллект и компьютерное зрение. Когда это станет проблемой, посмотрите дальше в этом тексте для решения. С точки зрения аренды VPS, есть много мест, которые вы можете пойти. Google Cloud имеет VPS -серверы, Ionos, Kamatera, Amazon AWS и все больше поставщиков предлагают решения облачных серверов, которые будут удовлетворить наши потребности. Вам нужно будет нажать через их формы и выбрать план, чтобы начать работу. Вы можете использовать базовый план с любым поставщиком, но убедитесь, что поставщик позволяет вам открывать порты сервера порта почты для отправки электронной почты (это должен быть порт 587 и порт 25), некоторые поставщики блокируют эти порты. Пока что у меня былоОпыт EST с Ионом и Каматерой, оба они позволят мне отправлять неограниченную электронную почту, а их цены довольно дешевые. Вы подключитесь к своему новому серверу по протоколу под названием SSH или Secure Shell, который позволяет удаленно взаимодействовать с сервером точно так же, как ваш персональный компьютер, с вашего персонального компьютера. Когда вы настроите сервер, провайдер хостинга, вероятно, попросит вас добавить ключ SSH, или они дадут вам имя пользователя и пароль. Ключ SSH - это то, как вы войдете на сервер из командной строки, чтобы редактировать код. Используйте приведенные ниже параметры SSH-KeyGen для создания SSH

ssh-keygen
Сохраните файл и перезаписывайте его, если вам нужно, хорошо повернуть свои клавиши SSH, если вы еще этого не сделали. Теперь вы можете использовать следующую команду, чтобы увидеть свой ключ SSH. Вы захотите скопировать его на свой удаленный сервер, чтобы вы могли использовать его для аутентификации.

cat ~/.ssh/id_rsa.pub
Если вы не смогли увидеть клавишу SSH при печати этой команды (длинная строка цифр и букв, начиная с «SSH-RSA AAA»), попробуйте создать ключ RSA (они более безопасны, поэтому я советую им использовать их .) Следующий код будет генерировать 4096 -битный RSA SSH -ключ.

ssh-keygen -t rsa -b 4096
Создайте VPS под управлением Ubuntu, однако вы планируете сделать это. После того, как вы создали VPS, нажав на формы на веб -сайте поставщиков (kamatera.com, ionos.com или аналогичный), вы захотите войти в систему. Чтобы сделать это, используйте команду SSH с вашим IP -адресом (адрес Это выглядит как xx.xx.xx.xx). Вам также нужно быть чувствительным к имени пользователя по умолчанию на сервере, который мы создали, например, Ubuntu.

ssh ubuntu@XX.XX.XX.XX
Вам может попросить пароль, если вас попросят пароль, введите его. Мы не будем использовать имя пользователя по умолчанию, поэтому давайте начнем с создания нового пользователя и добавив ключ SSH в их учетную запись. Давайте начнем с добавления нового файла sshd_config, который сообщает серверу, как использовать SSH.

nano sshd_config

# Это файл конфигурации по всей системе SSHD.  Видеть
# sshd_config (5) для получения дополнительной информации.

# Этот SSHD был составлен с Path =/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

# Стратегия, используемая для параметров в SSHD_CONFIG по умолчанию
# Openssh - это указать параметры со значением по умолчанию, где
# возможно, но оставьте их прокомментированными.  Неправильные варианты переопределяют
# Значение по умолчанию.

# Порт 22
# Адресное число любого
# Список адреса 0.0.0.0
# Слушать Адрес ::

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

# Шифры и клавиши
# RekeyLimit по умолчанию нет

# Регистрация
# Syslogfacicility Auth
# Loglevel Info

# Аутентификация:

# Logringracetime 2m
# Разрешение на получение разрешений
# Строгиевзы да
# MaxAuthtries 6
# Макс. 10

PubkeyAuthentication yes

# Ожидайте .ssh/autorized_keys2 будет игнорироваться по умолчанию в будущем.
AuthorizedKeysFile	.ssh/authorized_keys .ssh/authorized_keys2

# Авторизованный principalsfile нет

# Уполномоченное кнодобое. Нет
# Авторизованный KeeyScommanduser никто

# Для этого вам также понадобятся клавиши хоста в/etc/ssh/ssh_ with_ witry_hosts
# HostBasedAuthentication №
# Изменить на да, если вы не доверяете ~/.ssh/stornal_hosts для
# HOSTBASEDAuthentication
# Игноризатор известных хост нет
# Не читайте пользователя ~/.rhosts и ~/.
# Игноризаторы да

# Чтобы отключить туннелированные текстовые пароли, изменитесь, чтобы нет здесь!
PasswordAuthentication no
# Разрешение № разрешения №

# Изменить на да, чтобы включить пароли-вызовов-ответ (остерегайтесь проблем с
# Некоторые модули и потоки PAM)
KbdInteractiveAuthentication no

# Варианты Kerberos
# Kerberosauthentication №
# Kerberosorlocalpasswd Да
# KerberosticketCleanup Да
# Kerberoscotted stod №

# Варианты GSSAPI
# GssapiaThentication №
# Gssapicleanupcredentials Да
# Gssapistrictacceptorcheck Да
# Gssapikeyexchange no

# Установите это на «да», чтобы включить аутентификацию PAM, обработку учетной записи,
# и обработка сеанса. Если это включено, Authentication PAM будет
# быть разрешенным через KbdinteractiveAuthentication и
# Пароль.  В зависимости от вашей конфигурации PAM,
# Аутентификация PAM через kbdinteractiveauthentication может обходить
# Установка «разрешенного кортлогина без пассового слова».
# Если вы просто хотите, чтобы проверка учетной записи PAM и сеанса запускались без
# Аутентификация PAM, затем включите это, но установите пароль
# и kbdinteractiveauthentication к «нет».
UsePAM yes

# AllowAgentForming Yes
# Разрешить да
# Gatewayports №
X11Forwarding yes
# X11displayoffset 10
# X11uselocalhost Да
# Проницаемое да
PrintMotd no
# Printlastlog Да
# Tcpakealive да
# Проницаемость в
# Сжатие задерживается
# Клиентский интервал 0
# ClientAliveCountMax 3
# Использовал в
# Pidfile /run/sshd.pid
# MaxStartups 10: 30: 100
# Pemittunl no
# Chrootdirectory Нет
# Версия добавка нет

# Нет пути баннера по умолчанию
Banner /etc/banner

# Позвольте клиенту передавать локальные переменные переменные
AcceptEnv LANG LC_*

# переопределить дефолт без подсистем
Subsystem	sftp	/usr/lib/openssh/sftp-server

# Пример переоценки настроек на основе пользователя
# Сопоставьте пользователь Anoncvs
# X11formiting no
# AllingTcpForwarding no
# Allowetty In
# FORCECOMMAND CVS SERVER
PermitRootLogin no
Помните, Ctrl+X и Y, чтобы сохранить файл. Далее, давайте напишем базовый сценарий под названием «Инициализировать» (все в домашнем каталоге по умолчанию нашего пользователя).

nano initialize
Добавить эти строки в файл, заменивС вашим SSH -ключом, который вы нашли с помощью 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
Чтобы провести вас через этот файл, давайте запустим линию по линии. Первая строка сообщает компилятору, что это сценарий Bash. Затем мы устанавливаем зависимости, копируем SSHD_CONFIG в правильный каталог, перезагружая SSH, генерируя клавиши SSH для ROOT, добавив пользователь «Команда» (вы можете выбрать имя, которое вам нравится, используйте команду AddUser с их именем и отключенным паролем для сейчас). Мы также добавляем команду в группу Sudo, генерируем их ключ SSH, добавляем наш ключ к авторизованным ключам и их, а также печатайте их ключ. Этот новый пользователь будет так, как мы войдем в сайт. В новом терминале продолжайте и снова откройте сервер.

ssh team@XX.XX.XX.XX
На этот раз вам не нужно пароль, будучи как у вас есть ключ SSH. Мы также отключили вход с паролем, чтобы сохранить сайт более безопасным. Теперь этот сервер запускается совершенно пустым без информации. Давайте начнем с клонирования нашего проекта из GIT, чтобы мы могли загрузить и запустить его на удаленной машине. На удаленном сервере, подключенном через SSH, сначала распечатайте ключ SSH:

cat ~/.ssh/id_rsa.pub
Затем вставьте этот ключ в настройки GIT, как и раньше, чтобы настроить наш репозиторий GIT. Теперь мы можем клонировать наш проект непосредственно на сервер. Убедитесь, что вы сначала подкрепили проект локально, так что он на сервере GIT для загрузки.

git clone git://github.com/you/yourproject.git
Идеальный. Теперь все файлы здесь. Мы можем видеть их с помощью LS

ls
Теперь давайте начнем настроить сервер. Во -первых, скопируйте свой каталог проектов в простое, запоминающееся имя, которое мы будем использовать для проекта.

cp -r yourproject whatyoucalledit
Где «что -то, что» - это новое название вашего проекта. Затем нам нужно будет создать базовую утилиту для настройки сервера. Мы сохраним эту утилиту и используем ее в будущем. Чтобы создать эту утилиту, давайте создадим бинар пользователя, чтобы определить, как мы редактируем сценарий. Использование Bash, редактирование/usr/bin/ascript

sudo nano /usr/bin/ascript
Обязательно используйте там Sudo, чтобы у вас были разрешения на редактирование файла. В файле добавьте эти строки:

# !
if [ ! -f /usr/bin/$1 ]; then
    sudo touch /usr/bin/$1
    echo "# !/bin/bash »>>/usr/bin/$ 1
    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
Помните, что этот скрипт принимает аргумент, имя сценария, как 1 доллар. Сначала он проверяет, существует ли файл, или иным образом создает его, добавляет первую строку, чтобы объявить, что сценарий - Bash, изменяет свои разрешения, редактирует его и добавляет свое имя в /и т. Д. /Приписывает, что позволяет нам хранить имена сценариев. создают. Если файл уже существует, просто измените разрешения и отредактируйте его. Сохраните файл, и затем мы изменим его разрешения. Пока мы используем этот сценарий, нам не придется этого делать снова.

sudo chmod a+x /usr/bin/ascript
Идеальный. Теперь давайте создадим сценарий под названием Setup. Во -первых, не ошеломлять вас, но посмотрите, как выглядит мой скрипт настройки. Мы будем проходить через то, как должен выглядеть этот сценарий в вашем проекте, вам не понадобится все в моем сценарии, чтобы начать.

# !
SECONDS=0
PYTHON_VERSION=3.12
echo "femmebabe installer initialized."
# Sudo Chmod A+X Scripts/UserseTup
# ./scripts/usersetup
# Ssh-keyen
# Проектный каталог
DIR="/home/team/femmebabe"
USER="team"
# Команды журнала
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
# Git config
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
# Обновить и установить
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
# Включить Clamav Antivirus
echo "Starting antivirus"
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Установить имя хоста
echo "127.0.0.1 femmebabe" | sudo tee -a /etc/hosts
sudo hostnamectl set-hostname localhost
# Настройка 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;"
# Настройка базы данных резервного копирования
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
# Отключенные ипатаблии
echo "Configuring firewall"
sudo iptables -P INPUT ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -F
sudo iptables-save
# Установите 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
# Настройка 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
# Создать 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
# Установка VirtueAlenv
cd $DIR
echo "Creating virtual environment"
python -m venv venv
source venv/bin/activate
# Получить и построить зависимости
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
# Установить правила брандмауэра
cd $DIR
# Установите зависимости 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 установить OpenCV-Python == 4.5.5.64
# 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
# Установите 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
# Запустить Certbot
sudo certbot --apache --non-interactive --agree-tos --domains femmebabe.com --email jasper.camber.holton@gmail.com
# Перезагрузить почтовый сервер
sudo systemctl restart opendkim postfix dovecot
# Копировать сертификаты
# sudo cp /etc/letsencrypt/live/femmebabe.com/privkey.pem privkey.pem
# sudo cp /etc/letteSencrypt/live/femmebabe.com/cert.pem cert.pem
# Пластырь
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"
# Установите настройки пользователя
sudo gpasswd -a www-data users
# Установить разрешения
echo "Setting permissions"
sudo chown -R team:users cache/
sudo chmod a+rwx -R cache/
# Sudo Chown -R Команда: пользователи/var/run/
# Sudo Chown Root: root/run/sudo/ts -r
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: пользователи 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
# Копировать конфигурацию и установить разрешения
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
# Настройка базы данных
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"
# Inject Pam Config и удалить неисправную конфигурацию SSH
# sudo sed -i '' -e '$ d' /tc/pam.d/sshd
# Sudo sed -i '' -и $ d ' /etc /profile
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
# Скопировать сценарии бина и установить разрешения
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
# Перезагрузить и включить услуги
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
# Включить модули 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
# Отключить сайт по умолчанию
sudo a2dissite 000-default
sudo a2dissite 000-default-le-ssl
# Включить для сайта
sudo a2ensite femmebabe-le-ssl
# Перезагрузить демон и перезапустить Apache, Postfix и Opendkim
sudo systemctl daemon-reload
sudo systemctl restart apache2
sudo systemctl restart opendkim postfix
sudo systemctl start daphne
# Установить разрешения
sudo chown -R :www-data /var/www/
sudo chown -R :www-data /var/www/.deepface
# Смена конфигурации
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
# 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
# Настройка 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
# Показать IPv6 и Opendkim для конфигурации домена
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}'
# Настройка завершена
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."
Это много настроек! Короче говоря, этот код журнал ведет команды, настраивает NANO и GIT, копии над файлами, загрузки и устанавливает пакеты Ubuntu APT, зависимости Python, настраивает PostFix, настраивает PostGRESQL (сервер базы данных) и загружает базу данных, конфигурирует UFW (неосновный бранд),, и загружает базу данных, настраивает UFW (неосновный бранд), и загружает базу данных, конфигурирует UFW (неосновной бранд), и загружает базу данных, конфигурирует UFW (неосновной бранд), и загружает базу данных UFW (неосновной бранд), и загружает базу данных UFW (неосновной бранд (сервер базы данных) и загружает базу данных. Отключает iptables, загружает антивирус, делает каталоги, зависимости клонов, устанавливает сертификаты и устанавливает Сервер, устанавливает конфигурацию, запускает и позволяет SEAR, выделяет обмен, устанавливает разрешения и печатает IP, адрес IPv6 и ключ Opendkim. Довольно просто, но это похоже на много кода. Нам не понадобится много этого, потому что у нас нет зависимостей, мы не используем сельдерей, сельдери или Дафну, но мы все равно установим некоторые из них, чтобы начать работу. Обратите внимание, что этот код имеет домен, объявленный несколько раз. Нам также нужно будет приобрести доменное имя (которое является небольшой годовой платой). Я рекомендую Squarespace для покупки домена, их макетинтуитивно понятный и прост в использовании. Вы можете купить любой домен по вашему выбору, но в этом примере я использую домен Femmebabe.com. После того, как вы купили домен, отправляйтесь на панель конфигурации DNS Squarespace и добавьте запись, указывающую ваш домен на сервер с помощью IP -адреса. Это должно выглядеть так: @ A xx.xx.xx.xx С оператором @ в качестве хоста, то есть все субдомены в этом домене и корневой домен все будут перенаправляться на сервер. Есть больше записей, которые нужно объявить, но мы можем перейти к ним, как только мы будем готовы отправить почту. Имейте в виду, что может потребоваться несколько дней, прежде чем вы сможете успешно отправлять почту с сервера. Записи DNS, которые мы устанавливаем, займет время для распространения. Во всяком случае, единственная запись, которую нам нужно начать, - это запись. Итак, теперь мы можем заполнить приведенный ниже сценарий в соответствии с нашим проектом и запустить его. Давайте начнем с меньшего сценария настройки, чтобы просто установить то, что нам нужно для базового прогресса. Мы еще не будем использовать так много зависимостей или postgresql, мы простоВверх по базовому HTTP -серверу и беспокойтесь о его сертификации, когда это будет сделано. Помните, чтобы получить сертификат HTTPS и надежно запустить сервер, нам нужно будет купить домен вместе с арендой сервера. На данный момент замените «команду» в этом файле с именем вашего пользователя «Dir» на каталог вашего проекта, и поставьте свою электронную почту и домен в <> тегах. Кроме того, прежде чем мы запустим этот код, нам нужно изменить настройки на брандмауэр, который поддерживает провайдер хостинга, если таковые имеются. Обычно это находится на вкладке «Сети» вашего хостингового поставщика, или, если вы самостоятельно хостинг, в разделе «Переадресация порта» вашего маршрутизатора. Вы также захотите настроить статический IP -интерфейс через маршрутизатор с адресом вашего серверного машины, если вы используете самостоятельное хостинг. Вам нужно будет открыть следующие порты для доступа к чтению/записи. 22 (SSH) 25 (почта) 587 (почта) 110 (почтовый клиент) 80 (http) 443

# !
SECONDS=0
PYTHON_VERSION=3.12
echo "femmebabe installer initialized."
DIR="/home/team/<yourproject>"
USER="team"
# Команды журнала
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
# Git config
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
# Обновить и установить
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
# Включить Clamav Antivirus
echo "Starting antivirus"
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Установить имя хоста
echo "127.0.0.1 femmebabe" | sudo tee -a /etc/hosts
sudo hostnamectl set-hostname femmebabe
# Настройка базы данных резервного копирования
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
# Отключенные ипатаблии
echo "Configuring firewall"
sudo iptables -P INPUT ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -F
sudo iptables-save
# Установка VirtueAlenv
cd $DIR
echo "Creating virtual environment"
python -m venv venv
source venv/bin/activate
pip3 install -r requirements.txt
# Установите 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
# Запустить Certbot
sudo certbot --apache --non-interactive --agree-tos --domains femmebabe.com --email <youremail>@gmail.com
# Установите настройки пользователя
sudo gpasswd -a www-data users
# Установить разрешения
echo "Setting permissions"
sudo chown -R team:users cache/
sudo chmod a+rwx -R cache/
# Sudo Chown -R Команда: пользователи/var/run/
# Sudo Chown Root: root/run/sudo/ts -r
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 ./
# Перезагрузить и включить услуги
echo "Enabling services"
sudo systemctl daemon-reload
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Включить модули 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
# Перезагрузить демон и перезапустить Apache, Postfix и Opendkim
sudo systemctl daemon-reload
sudo systemctl restart apache2
sudo systemctl restart opendkim postfix
# Показать IPv6 и Opendkim для конфигурации домена
echo "COPY the below information to domain configuration."
hostname -I
ip a | grep inet
ip -6 addr | grep "scope link"
Перед запуском этого кода убедитесь, что приобретенная вами домен подключен к серверу. Для этого откройте терминал на вашей локальной машине и запустите эту команду со своим доменом:

ping femmebabe.com # Вставьте здесь свой домен, после пинга
Если все выглядит хорошо, и сервер отправляет ответы, мы готовы запустить сценарий и установить пакеты, а также запустить, включить и сертифицировать наш сервер Apache. Это не вся настройка, необходимая для настройки Postfix, мы рассмотрим эту настройку более позже. На данный момент запустите этот код настройки, и для установки и сертификации вашего сервера потребуется несколько минут. Еще раз, обязательно замените имя, электронную почту и доменное имя в сценарии в соответствии с купленным именем. Теперь, когда сервер предоставлен, вы можете перейти на URL -адрес в любом веб -браузере и проверить, чтобы убедиться, что сервер работает HTTPS. Если это не так, попробуйте немного подождать, пока записи DNS наверстают упущенное, а затем запустите следующую команду, чтобы повторить сертификацию Certbot:

sudo certbot --apache --non-interactive --agree-tos --domains <domain>.com --email <youremail>@gmail.com
Пока вы правильно настроили все, вы сможете получить доступ к странице Apache по умолчанию, чтобы узнать, что ваш код работает и отображает живую веб -страницу. Далее, давайте отредактируем настройки. Мы также настроим домен в настройках, а также внутренние IPS.

nano yourproject/settings.py
В настройках измените/добавьте эти строки.

DEBUG = False

# Сайт конфигурация
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',
]
Теперь нам нужно будет настроить Apache2. Давайте отредактируем файл конфигурации, который мы будем развернуть с этой строкой:

sudo nano /etc/apache2/sites-available/femmebabe-le-ssl.conf
Этот файл конфигурации должен иметь наше доменное имя и имя пользователя и проекта. Я использую доменное имя femmebabe.com, команду пользователя и название проекта 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>
Обязательно замените имя проекта, каталогов и домена в этом примере кода при настройке вашего сервера. Теперь нам нужно будет отключить сайт по умолчанию. Это можно сделать с помощью Bash.

sudo a2dissite 000-default-le-ssl
sudo a2dissite 000-default
sudo a2dissite default-ssl
Затем мы можем включить сайт по умолчанию и перезагрузить Apache2, также используя Bash. Не забудьте заменить Femmebabe именем файла, который вы объявляете при редактировании в/etc/apache2/sites-vailable/.

sudo a2ensite femmebabe-le-ssl
sudo systemctl reload apache2
Вернитесь к своему домену в Navbar. Вы должны увидеть сайт, который вы настроили в своем веб -браузере. Поздравляю! Если вы этого не видите, вам может потребоваться внести некоторые изменения. Осторожно просмотрите настройки в вашем проекте, конфигурацию Apache и убедитесь, что у вас нет ошибок, и запустите следующие команды, чтобы проверить проект на наличие ошибок.

cd projectname
source venv/bin/activate
python manage.py check
Если у вас есть ошибки в вашем проекте Python, проведите их туда, где они находятся, и исправьте их. Вы, возможно, не сможете увидеть все ваши ошибки в зависимости от того, где они находятся, поэтому, если у вас есть ошибка, которая просто говорит «Заполнение не повторно», отредактируйте следующий файл в виртуальной среде, Registry.py, чтобы выявить ошибка.

nano venv/lib/python3.12/site-packages/django/apps/registry.py
Прокрутите до строки 83, где возникает эта ошибка выполнения (поднять runtimeerror («opulate () не повторно»)) и добавьте комментарий перед этой строкой, а затем добавление с тем же отступлением, Self.App_Configs = {}. Это выглядит так:

            if self.loading:
                # Предотвратить вызовы повторных ресурсов, чтобы избежать запуска appconfig.ready ()
                # Методы дважды.
# Поднимите RuntimeError ("opulate () не повторно")
                self.app_configs = {}
            self.loading = True
Затем вы можете снова проверить проект и разоблачить ошибку.

python manage.py check
Затем вы можете увидеть ошибку и исправить ее. Когда у вас его исправлено, и код компилируется без ошибок, обязательно измените файл, чтобы он выглядел так:

            if self.loading:
                # Предотвратить вызовы повторных ресурсов, чтобы избежать запуска appconfig.ready ()
                # Методы дважды.
                raise RuntimeError("populate() isn't reentrant")
# self.app_configs = {}
            self.loading = True
При условии, что сервер находится в Интернете, когда мы вносим в него дальнейшие изменения, нам нужно использовать следующую команду для перезагрузки сервера:

sudo systemctl reload apache2
Потрясающий! Но как насчет отправки почты? Чтобы начать отправку электронной почты, нам сначала необходимо обновить конфигурацию домена. Это должно быть на вашей панели DNS в Squarespace или любом регистраторе доменного имени, которое вы выбрали. Нам также нужно будет установить и добавить конфигурацию, а также запустить несколько команд. Во -первых, давайте получим адрес IPv6 сервера. Затем мы откроем ваш DNS и добавим записи. Чтобы получить адрес IPv6 сервера, используйте эту команду:

ip -6 addr
Теперь мы можем добавить следующие записи в настройки DNS. Мои записи выглядят так. Однако для ваших записей вы должны заменить IP -адрес вашим IP (не 75.147.182.214, это мое). Также добавьте свой домен вместо Femmebabe.com, а также свой адрес IPv6, найденное с предыдущей командой (вы не можете использовать мой, Fe80 :: 725A: FFF: FE49: 3E02). Не беспокойтесь о домене на данный момент, это создается, когда мы настраиваем Postfix, почтовый сервер, с Opendkim, и печатайте ключ. Мы настроим это последнее. @ А N/a 75.147.182.214 @ Мкс 10 femmebabe.com @ Пт N/a femmebabe.com @ ТЕКСТ N/a Txt @ v = spf1 mx ip75.147.182.214ip6: fe80 :: 725a: fff: fe49: 3e02 ~ all default._bimi ТЕКСТ N/a v = bimi1; l = https: //femmebabe.com/media/static/femmebabe.svg _dmarc ТЕКСТ N/a v = dmarc1; p = нет sendonly._domainkey ТЕКСТ N/aТеперь нам нужно добавить некоторую постоянную конфигурацию для Postfix. Все, что нам нужно сделать, это убедиться, что мы заменим доменное имя, femmebabe.com, с помощью доменного имени, которое вы используете. Давайте посмотрим на все файлы конфигурации один за другим и установим их в каталоге, называемом Config в нашем проекте, для установки в ОС.

nano config/etc_postfix_main.cf
Добавьте этот текст в файл

# См. /USR/Share/postfix/main.cf.dist для прокомментированной, более полной версии


# Debian Specifice: указание имени файла вызовет первое
# строка этого файла, который будет использоваться в качестве имени.  Debian по умолчанию
# IS /etc /mailName.
# Myorigin = /etc /mailName

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

# Добавление. Домен - это работа MUA.
append_dot_mydomain = no

# Неуместно следующая строка, чтобы генерировать предупреждения «отсроченная почта»
# dolement_warning_time = 4H

readme_directory = no

# См. Http://www.postfix.org/compatibility_readme.html - по умолчанию 3,6 на
# свежие установки.
compatibility_level = 3.6



# Параметры 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

# Конфигурация Милтера
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
Следующая конфигурация!

nano config/etc_postfix_master.cf
Добавьте эти строки:

# 
# Postfix Master Process File.  Для получения подробной информации о формате
# файла см. Мастер (5) Страница ручной работы (команда: «Человек 5 Мастер» или
# Онлайн: http://www.postfix.org/master.5.html).
# 
# Не забудьте выполнить «Postfix Reload» после редактирования этого файла.
# 
# ============================================================================= =======================
# Тип сервиса Private непревзойденный chroot quaintup maxproc command + args
# (Да) (да) (нет) (никогда) (100)
# ============================================================================= =======================
smtp      inet  n       -       y       -       -       smtpd
# SMTP inet n - y - 1 пост -экран
# SMTPD Pass - - y - - SMTPD
# Dnsblog unix - - y - 0 dnsblog
# Tlsproxy unix - - y - 0 tlsproxy
# Выберите один: включите представление только для клиентов Loopback или для любого клиента.
# 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/pretriching
# -o smtpd_tls_security_level = incrypt
# -o smtpd_sasl_auth_enable = да
# -o smtpd_tls_auth_only = yes
# -o smtpd_reject_unlisted_recipient = нет
# -O smtpd_client_restrictions = $ mua_client_restrictions
# -o smtpd_helo_restrictions = $ mua_helo_restrictions
# -o smtpd_sender_restrictions = $ mua_sender_restrictions
# -o smtpd_recipient_restrictions =
# -o smtpd_relay_restrictions = vermit_sasl_authenticated, отклонить
# -O milter_macro_daemon_name =
# Выберите один: включите SMTPS только для клиентов Loopback или для любого клиента.
# 127.0.0.1:Smtps inet n - y - - smtpd
# smtps inet n - y - - smtpd
# -O syslog_name = postfix/smtps
# -О smtpd_tls_wrappermode = да
# -o smtpd_sasl_auth_enable = да
# -o smtpd_reject_unlisted_recipient = нет
# -O smtpd_client_restrictions = $ mua_client_restrictions
# -o smtpd_helo_restrictions = $ mua_helo_restrictions
# -o smtpd_sender_restrictions = $ mua_sender_restrictions
# -o smtpd_recipient_restrictions =
# -o smtpd_relay_restrictions = vermit_sasl_authenticated, отклонить
# -O milter_macro_daemon_name =
# 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
# 
# ============================================================================= ==================
# Интерфейсы на непостфикс-программное обеспечение. Обязательно изучите руководство
# Страницы неподвижного программного обеспечения, чтобы выяснить, какие варианты он хочет.
# 
# Многие из следующих сервисов используют доставку Postfix Pipe (8)
# агент  См. Страницу трубы (8) Женщина для получения информации о $ {получатель}
# и другие параметры конверта сообщения.
# ============================================================================= ==================
# 
# maildrop. См. Файл Postfix maildrop_readme для получения подробной информации.
# Также укажите в main.cf: maildrop_destination_recipient_limit = 1
# 
maildrop  unix  -       n       n       -       -       pipe
  flags=DRXhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
# 
# ============================================================================= ==================
# 
# Недавние версии Cyrus могут использовать существующую запись «lmtp» Master.cf.
# 
# Укажите в Cyrus.conf:
# lmtp cmd = "lmtpd -a" listen = "localhost: lmtp" proto = tcp4
# 
# Укажите в main.cf одно или несколько из следующих:
# mailbox_transport = lmtp: inet: localhost
# Virtual_transport = lmtp: inet: localhost
# 
# ============================================================================= ==================
# 
# Сайрус 2.1.5 (Амос Гуаук)
# Также укажите в main.cf: cyrus_destination_recipient_limit = 1
# 
# Cyrus unix - n n - - труба
# flags = drx user = cyrus arg =/cyrus/bin/delive -e -r $ {sender} -m $ {endension} $ {user}
# 
# ============================================================================= ==================
# Старый пример доставки через Сайруса.
# 
# Старый -corus unix - n - - труба
# flags = r user = cyrus argv =/cyrus/bin/delivery -e -m $ {endension} $ {user}
# 
# ============================================================================= ==================
# 
# См. Файл Postfix UUCP_README для деталей конфигурации.
# 
uucp      unix  -       n       n       -       -       pipe
  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
# 
# Другие методы внешней доставки.
# 
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}
И конфигурация Opendkim. Opendkim идентифицирует почтовые серверы с ключами домена, чтобы сделать их более безопасными. Без этого Mail не подписана и не может добраться до почтового ящика.

nano config/etc_default_opendkim
Добавьте эти строки:

# Примечание. Это устаревший файл конфигурации. Он не используется opendkim
# Systemd Service. Пожалуйста, используйте соответствующие параметры конфигурации в
# /etc/opendkim.conf вместо этого.
# 
# Ранее можно было бы редактировать настройки по умолчанию здесь, а затем выполнить
# /lib/opendkim/opendkim.service.generate для генерации файлов переопределения Systemd в
# /etc/systemd/system/opendkim.service.d/override.conf и
# /etc/tmpfiles.d/opendkim.conf. Хотя это все еще возможно, сейчас
# Рекомендуется настроить настройки непосредственно в /etc/opendkim.conf.
# 
# Daemon_opts = ""
# Изменить на/var/spool/postfix/run/opendkim, чтобы использовать розетку Unix с
# постфикс в хр -в кру:
# Roundir =/var/spool/postfix/run/opendkim
RUNDIR=/run/opendkim
# 
# Неудобно указать альтернативный розет
# Обратите внимание, что настройка Это будет переопределить любое значение сокета на opendkim.conf
# по умолчанию:
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
# Слушайте все интерфейсы на порту 54321:
# Сокет = inet: 54321
# Слушайте Loopback на порту 12345:
# Сокет = inet: 12345@localhost
# Слушайте 192.0.2.1 - порт 12345:
# Сокет = inet: 12345@192.0.2.1
USER=opendkim
GROUP=opendkim
PIDFILE=$RUNDIR/$NAME.pid
EXTRAAFTER=

nano config/etc_dovecot_conf.d_10-master.conf
Добавьте эти строки:

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

# Ограничение VSZ (размер виртуальной памяти) по умолчанию для процессов обслуживания. Это в основном
# намеревался ловить и убивать процессы, которые протекают память, прежде чем они съесть
# все.
# default_vsz_limit = 256m

# Пользователь входа в систему используется внутри процесса входа в систему. Это самый ненадежный
# Пользователь в системе DoveCot. Это вообще не должно иметь доступа.
# default_login_user = dovenull

# Внутренний пользователь используется в неполнологических процессах. Он должен быть отделен от
# Войдите в систему, чтобы процессы входа в систему не могли нарушать другие процессы.
# default_internal_user = dovecot

service imap-login {
  inet_listener imap {
    # Порт = 143
  }
  inet_listener imaps {
    # Порт = 993
    # ssl = да
  }

  # Количество подключений для обработки перед началом нового процесса. Обычно
  # Единственные полезные значения - 0 (неограниченное) или 1. 1 более безопасно, но 0
  # быстрее. <doc/wiki/loginprocess.txt>
  # service_count = 1

  # Количество процессов, которые всегда продолжают ждать больше соединений.
  # process_min_avail = 0

  # Если вы установите service_count = 0, вам, вероятно, нужно это вырастить.
  # Vsz_limi = $ default_vsz_limit
}

service pop3-login {
  inet_listener pop3 {
    # Порт = 110
  }
  inet_listener pop3s {
    # Порт = 995
    # ssl = да
  }
}

service submission-login {
  inet_listener submission {
    # Порт = 587
  }
}

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

  # Создайте INET слушатель только в том случае, если вы не можете использовать вышеупомянутый сокет Unix
  # inet_lister lmtp {
    # Не делайте LMTP видимым для всего Интернета
    # Адрес =
    # порт =
  # }
}

service imap {
  # Большая часть памяти переходит в файлы mmap (). Вам может потребоваться увеличить это
  # Ограничение, если у вас огромные почтовые ящики.
  # vsz_limit = $ default_vsz_limit

  # Максимум Количество процессов IMAP (соединения)
  # Process_limit = 1024
}

service pop3 {
  # Максимум Количество процессов POP3 (соединения)
  # Process_limit = 1024
}

service submission {
  # Максимум Количество процессов отправки SMTP (соединения)
  # Process_limit = 1024
}

service auth {
  # Auth_socket_path указывает на этот сокет userdb по умолчанию. Это обычно
  # Используется Dovecot-LDA, Doveadm, возможно, процесс IMAP и т. Д. Пользователи, у которых есть
  # Полные разрешения на этот сокет способны получить список всех имен пользователей и
  # Получите результаты поиска пользователей пользователя.
  # 
  # Режим по умолчанию 0666 позволяет любому подключаться к розетку, но
  # Поиск userDB будет успешным, только если userDB возвращает поле «UID», которое
  # соответствует UID процесса вызывающего абонента. Также, если UID или GID вызывающего абонента соответствуют
  # Сокетское UID или GID The Lookup успешно. Все остальное вызывает неудачу.
  # 
  # Чтобы дать абоненту полные разрешения на поиск всех пользователей, установите режим на
  # что -то другое, чем 0666 и Dovecot позволяет ядру применить
  # Разрешения (например, 0777 допускают все полные разрешения).
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix
  }
}

service auth-worker {
  # Процесс работника AUTH работает по умолчанию как root, чтобы он мог получить доступ к
  # /и т.д./тень. Если это не необходимо, пользователь должен быть изменен на
  # $ default_interal_user.
  # user = root
}

service dict {
  # Если используется DICT Proxy, почтовые процессы должны иметь доступ к ее розетку.
  # Например: Mode = 0660, Group = vmail и Global Mail_access_groups = vmail
  unix_listener dict {
    # Режим = 0600
    # Пользователь =
    # группа =
  }
}
Еще раз, обязательно замените домен во всех этих файлах, Femmebabe.com, на выбранном вами домене. Отредактируйте следующий файл, конфигурация DoveCot,

nano config/etc_dovecot_dovecot
И добавить эти строки

## Файл конфигурации DoveCot

# Если вы спешите, см.

# Команда "doveconf -n" дает чистый выход из измененных настроек. Используйте его
# Вместо копирования и вставки файлов при публикации в списке рассылки DoveCot.

# '# «Характер и все после того, как он рассматривается как комментарии. Дополнительные места
# и вкладки игнорируются. Если вы хотите использовать любой из них явно, положите
# value inside quotes, eg.: key = "# char и raying witpace "

# Большинство (но не все) настройки могут быть переопределены различными протоколами и/или
# ИС исходного/назначения IP, разместив настройки внутри разделов, например:
# Протокол IMAP {}, локальный 127.0.0.1 {}, удаленный 10.0.0.0/8 {}

# Значения по умолчанию показаны для каждой настройки, не требуется неудобства
# те. Это исключения из этого: нет разделов (например, пространство имен {})
# или настройки плагина добавляются по умолчанию, они указаны только в качестве примеров.
# Пути также являются просто примерами, когда реальные значения по умолчанию основаны на конфигурации
# параметры. Перечисленные здесь пути предназначены для настройки -prefix =/usr
# -sysconfdir =/etc-localstatedir =/var

# Включить установленные протоколы
!include_try /usr/share/dovecot/protocols.d/*.protocol

# Запятый список IPS или хостов, где слушать подключения.
# «*» Слушает во всех интерфейсах IPv4 »::« Слушает во всех интерфейсах IPv6.
# Если вы хотите указать порты, не связанные с делом или что-то более сложное,
# РЕДАКТИРОВАТЬ CONF.D/MASTER.CONF.
# Слушать = *, ::

# Базовый каталог, где хранить данные времени выполнения.
# base_dir =/var/run/dovecot/

# Имя этого экземпляра. В настройке с несколькими инстанциями Doveadm и других команд
# может использовать -i <concance_name>, чтобы выбрать, какой экземпляр используется (альтернатива
# to -c <config_path>). Имя экземпляра также добавлено в процессы dovecot
# В выводе PS.
# exance_name = dovecot

# Приветствующее сообщение для клиентов.
# Login_Greeting = DoveCot готово.

# Пространство разделено список доверенных сетевых диапазонов. Связи из них
# IP разрешают переопределить свои IP -адреса и порты (для регистрации и
# Для проверки аутентификации). disable_plaintext_auth также игнорируется для
# эти сети. Как правило, вы указываете свои прокси -серверы IMAP здесь.
# login_trusted_networks =

# Отдельное пространство Список логинного доступа. Проверка сокетов (например, TCPWRAP)
# login_access_sockets =

# С proxy_maybe = yes, если назначение прокси сопоставлено любое из этих IP, не делайте
# Прокси. Это не требуется обычно, но может быть полезно, если пункт назначения
# IP, например, IP балансировщика нагрузки.
# auth_proxy_elf =

# Показать больше словесных титулов процессов (в PS). В настоящее время показывает имя пользователя и
# IP -адрес. Полезно для наблюдения, кто на самом деле использует процессы IMAP
# (Например, общие почтовые ящики или, если для нескольких учетных записей используется тот же UID).
# Verbose_procitle = нет

# Если все процессы будут убиты, когда доверенный мастер -процесс отключается.
# Установить это на «нет» означает, что DoveCot может быть обновлен без
# принуждая существующие клиентские подключения к закрытию (хотя это также может быть
# Проблема, если обновление, например, из -за исправления безопасности).
# shutdown_clients = да

# Если ненулевые, запустите почтовые команды через это много подключений с сервером Doveadm,
# Вместо того, чтобы запускать их непосредственно в том же процессе.
# doveadm_worker_count = 0
# Unix Socket или Host: порт, используемый для подключения к серверу doveadm
# DOVEADM_SOCKET_PATH = DOVEADM SERVER

# Отдельный список переменных среды, которые сохраняются на Dovecot
# стартап и передал все свои детские процессы. Вы также можете дать
# Key = Value Pares, чтобы всегда устанавливать конкретные настройки.
# Import_environment = tz

## 
## Настройки сервера словаря
## 

# Словарь можно использовать для хранения списков Key = значения. Это используется несколькими
# плагины. Доступ к словарям можно получить прямо или хотя
# Словой сервер. Следующие названия словарных карт DICT -блоков на URIS
# Когда используется сервер. Затем их можно ссылаться с использованием URI в формате
# «Прокси :: <MANAITE>».

dict {
  # QUATA = mysql:/andc/dovecot/dovecot-dic-sql.conf.ext
}

# Большая часть фактической конфигурации включена ниже. Имена файлов есть
# Сначала отсортированы по их значению ASCII и анализируются в этом порядке. 00-Prefixes
# В именах файлов предназначены для облегчения понимания упорядочения.
!include conf.d/*.conf

# Файл конфигурации также может попытаться включить, не предоставив ошибку, если
# это не найдено:
!include_try local.conf

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

protocols = imap pop3

# Позволяет DoveCot прослушать все подключения ввода (IPv4 / IPv6)

listen = *, ::
Добавьте пароль для пользователя DoveCot:

nano config/etc_dovecot_passwd
Первой частью файла перед толстой кишкой является имя пользователя. Последняя часть, «YourPassword», обозначает пароль, который вы хотели бы дать вашему почтовому серверу.

team:{plain}yourpassword
Далее, конфигурация opendkim

nano config/etc_opendkim.conf
И добавить эти строки:

# Это базовая конфигурация для подписания и проверки. Это может быть легко
# адаптировано в соответствии с базовой установкой. См. Opendkim.conf (5) и
# /usr/share/doc/opendkim/examples/opendkim.conf.sample для завершения
# Документация доступных параметров конфигурации.

Syslog			yes
SyslogSuccess		yes
# Logwhy no

# Общие параметры подписания и проверки. В Debian заголовок "от"
# переоборудован, потому что это часто является ключом идентификации, используемым в системах репутации
# и, таким образом, несколько чувствительна к безопасности.
Canonicalization	relaxed/simple
Mode			s
SubDomains		no
OversignHeaders		From

# Подписание домена, селектора и ключа (требуется). Например, выполните подписание
# Для домена "example.com" с селектором "2020" (2020._domainkey.example.com),
# Использование закрытого ключа, хранящегося в /etc/dkimkeys/example.private. Более гранулированный
# Параметры настройки могут быть найдены в /ср /шаре/doc/opendkim/readme.opendkim.
# Домен Пример.com
# Селектор 2020
# Keyfile /etc/dkimkeys/example.private

# В Debian Opendkim работает как пользователь «opendkim». Umask 007 требуется, когда
# Использование локального гнезда с MTA, которые получают доступ к розетку в качестве не привилегированного
# Пользователь (например, Postfix). Вам может потребоваться добавить пользователь «постфикс» в группу
# "Opendkim" в этом случае.
UserID			opendkim
UMask			007

# Сокет для соединения MTA (требуется). Если MTA находится в тюрьме Chroot,
# Должно быть обеспечено, что розетка была доступна. В Debian Postfix работает в
# Chroot в/var/spool/postfix, поэтому должен быть сокет Unix
# настроен, как показано в последней строке ниже.
# Сокет локальный: /run/opendkim/opendkim.sock
# Сокет INET: 8891@Localhost
# СОКЦЕЙ INET: 8891
Socket			local:/var/spool/postfix/opendkim/opendkim.sock

PidFile			/run/opendkim/opendkim.pid

# Хосты, для которых можно подписать, а не проверять, по умолчанию составляет 127.0.0.1. Увидеть
# Раздел операции Opendkim (8) для получения дополнительной информации.
# Internalhosts 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12

# Доверительный якорь позволяет DNSSEC. В Debian предоставляется файл привязки доверия
# пакетом dns-root-data.
TrustAnchorFile		/usr/share/dns/root.key
# Серверы имен 127.0.0.1

# Карта доменов в адресах до ключей, используемых для подписи сообщений
KeyTable           refile:/etc/opendkim/key.table
SigningTable       refile:/etc/opendkim/signing.table

# Набор внутренних хостов, чья почта должна быть подписана
InternalHosts       /etc/opendkim/trusted.hosts

nano config/etc_default_opendkim
И добавить эти строки

# Примечание. Это устаревший файл конфигурации. Он не используется opendkim
# Systemd Service. Пожалуйста, используйте соответствующие параметры конфигурации в
# /etc/opendkim.conf вместо этого.
# 
# Ранее можно было бы редактировать настройки по умолчанию здесь, а затем выполнить
# /lib/opendkim/opendkim.service.generate для создания файлов переопределения SystemD при
# /etc/systemd/system/opendkim.service.d/override.conf и
# /etc/tmpfiles.d/opendkim.conf. Хотя это все еще возможно, сейчас
# Рекомендуется настроить настройки непосредственно в /etc/opendkim.conf.
# 
# Daemon_opts = ""
# Изменить на/var/spool/postfix/run/opendkim, чтобы использовать розетку Unix с
# постфикс в хр -в кру:
# Rundir =/var/spool/postfix/run/opendkim
RUNDIR=/run/opendkim
# 
# Неудобно указать альтернативный розет
# Обратите внимание, что настройка Это будет переопределить любое значение сокета на opendkim.conf
# по умолчанию:
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
# Слушайте все интерфейсы на порту 54321:
# Сокет = inet: 54321
# Слушайте Loopback на порту 12345:
# Сокет = inet: 12345@localhost
# Слушайте 192.0.2.1 - порт 12345:
# Сокет = inet: 12345@192.0.2.1
USER=opendkim
GROUP=opendkim
PIDFILE=$RUNDIR/$NAME.pid
EXTRAAFTER=
Когда мы будем готовы настроить наш сервер Postfix, мы запустим приведенный ниже код, с встроенным подходящим доменным именем. Начните с создания сценария

touch scripts/postfixsetup
sudo chmod a+x scripts/postfixsetup
nano scripts/postfixsetup
Теперь, в Nano, текстовый редактор, отредактируйте этот файл, чтобы он включал ваше доменное имя вместо Femmebabe.com.

# !
# Настройка 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}'
Теперь запустите завершенный скрипт для настройки Postfix, Opendkim и Dovecot.

./scripts/postfixsetup
Как только этот сценарий запустится, скопируйте последнюю строку, которую он печатает, и вставьте его в конфигурацию DNS в качестве значения Sendonly._Domainkey. Это ключ Opendkim, используемый для идентификации вашего домена при отправке Secure Mail. Потрясающий! В течение нескольких дней вы сможете отправлять почту с сервера, если все настроено правильно. Если вы просто настроили DNS для вашего почтового сервера, для обновления записей должно потребоваться менее 72 часов. Обычно это намного быстрее. Вы можете проверить, работает ли ваш сервер, используя эту команду, поставила вашу электронную почту:

echo “test” | mail -s “Test Email” youremail@gmail.com
Если все, кажется, работает правильно, вы сможете отправлять электронную почту со своим сервером. Если он не работает, попробуйте посмотреть на журналы, чтобы увидеть, какая ошибка может быть.

tail –lines 150 /var/log/mail.log
Это предложит словесную информацию о почте, которая отправляется сервером и работает ли она должным образом. Вы также сможете увидеть электронное письмо в своем почтовом ящике, если его там нет, проверьте папку спама. Вам также необходимо будет настроить настройки в вашем настройках. Добавьте или замените эти линии в ваших настройках

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)
Обратите внимание, что мы используем файл конфигурации, чтобы получить пароль. Давайте загрузим этот файл в настройки, как и в самом начале файла.:

import os
import json

# Открыть и загрузить конфигурацию
with open('/etc/config.json') as config_file:
    config = json.load(config_file)
Давайте создадим этот файл и добавим к нему секретный ключ, а также пароль почты. Чтобы сгенерировать секретный ключ, используйте эту команду, с любой длиной, которая вам нравится в конце:

openssl rand -base64 64
Теперь скопируйте текст, который сгенерировал и редактирует /etc/config.json

sudo nano /etc/config.json
Добавьте следующие строки в ваш файл с ключом, который сгенерирован как секретный ключ.

{
	"SECRET_KEY": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX-generated-using-openssl)",
	"EMAIL_HOST_PASSWORD": "yourpassword"
}
Формат JSON прост и прост в использовании, мы можем объявить другие ключи, которые мы хотим использовать в нашем проекте таким образом, и держать их отделенными от нашего каталога проекта, чтобы другие пользователи не могли писать им, и поэтому их нельзя прочитать из нашего каталога проекта. Это рекомендуемая практика для клавиш API, из которых мы будем использовать здесь больше, чем несколько. Вы также захотите сделать резервную копию своего проекта, чтобы убедиться, что все сохранилось, и вы сможете восстановить свою работу позже, даже если вы больше не хотите арендовать сервер.

sudo backup
Теперь попробуйте отправить HTML -электронную почту с веб -сервера, при условии, что отправка его из командной строки работает. Запросите экземпляр пользователя в оболочке и отправьте HTML -электронную почту этому пользователю через Django. Измените мое имя в коде, Шарлотта, на ваше имя пользователя.

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()
Если первая команда не работает, обязательно используйте

source venv/bin/activate
При условии, что все настроено правильно, теперь вы получите желанное письмо в своем почтовом ящике, отправленном вашим веб -приложением. Хорошая работа! Вы прошли долгий путь. Я хотел добавить, если вы когда -либо боретесь с любыми ошибками вообще, работая над таким проектом, не стесняйтесь искать ответы и попросить о помощи. Google, среди других поисковых систем, являются отличными ресурсами для поиска помощи в программировании. Просто найдите ошибку, которую вы получаете, и вы сможете увидеть, как другие люди решат проблему. Кроме того, вы можете связаться со мной, вашими преподавателями (учителями, профессорами, репетиторами), любыми сверстниками в Интернете, которые доступны для помощи в программировании, или обратитесь к этой книге или другим ресурсам, чтобы найти решения, которые вы сталкиваетесь. Я понимаю, что это нелегко, но даже если вы прочитали в этом далеко и не пишете код, вы многое узнаете о создании веб -приложения с нуля. Похлопывать себя по спине, ты делаешь отличныйработа. Спасибо, что нашли время, чтобы прочитать это руководство по веб -разработке третьего издания. В будущих выпусках я включу больше важных примеров, обсуждаемых в начале документа, и мы будем гораздо глубже в мир разработки программного обеспечения и оборудования. Следите за тем, что произойдет, и я с нетерпением жду, чтобы научить вас создавать невероятное программное обеспечение. Увидимся в следующем






Закрывать
Страница 1
Прыгать
Смотрите полную статью
Продолжить чтение

Купить | Купить с крипто



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


(Нажмите или нажмите, чтобы загрузить изображение)
Профессиональные развлечения, фотографии, видео, аудио, прямые трансляции и случайный геймплей, а также службы сканирования идентификации, веб -разработка и суррогатное материнство.

Оставьте мне совет в биткойнах, используя этот адрес: 3KhDWoSve2N627RiW8grj6XrsoPT7d6qyE

© Glam Girl X 2025

Условия обслуживания