Praktyczne głębokie uczenie się i bezpieczeństwo w oparciu o Internet na przykładzie

DaisyZdjęcie profilowe

Przez Daisy

Praktyczne głębokie uczenie się i bezpieczeństwo internetowe według przykładu Trzecie wydanie Charlotte Harper 3 lipca 2024 r Przedmowa: Rozważania dotyczące bezpieczeństwa w budowaniu oprogramowania dla sieci są ważną częścią każdego planu i realizacji programisty internetowych podczas inżynierii prototypu, który jest niezawodny, stabilny i przydatny do celów praktycznych. DOM (znaczniki obiektu Dokument), wraz z jego wdrożeniem HTML, JavaScript i CSS, a także oprogramowaniem zaplecza wdrażającego Python, C/C ++, Java i Bash, daj programistom internetowym swobodę i władzę do tworzenia wielu różnych projektów, które wyrażają Kreatywność, zapewnij łatwość użytkowania i funkcjonalności, przedstawić pokorę i charakter oraz zapewnić łatwość użytkowania, a także wygodę i ważne usługi, które są atrakcyjne dla przeciętnego Joe, użytkownika końcowego, który chce zabić czas lub coś zrobić w Internecie, Zwykle na urządzeniu do smartfona z ekranem dotykowym. Większość ludzi nawet nie wiedziałaby, od czego zacząć, kiedy chcą zbudować stronę internetową od zera,Zwykle zaczynaliby na stronie innej osoby i budować coś ograniczonego pod względem funkcjonalności, niezawodności, łatwości użytkowania, a zwłaszcza kreatywności, gdy mogliby mieć do dyspozycji wszystkie najnowsze potężne narzędzia, aby zbudować coś przydatnego bez marnowania czasu naciskania przycisków i naciskania przycisków i Zwłaszcza marnowanie pieniędzy płacących za drogie subskrypcje oprogramowania niewiele osób chciało skorzystać, biorąc pod uwagę jego ograniczenia łatwości użycia i elastyczności. Jeśli masz kilka minut na przeczytanie tej książki i dowiedz się, czego chcę cię nauczyć, a nawet porozmawiać ze mną osobiście o swoich celach i uzyskać wskazówki we właściwym kierunku, i jesteś zmotywowany do nauki kodowania i pisania własnego oprogramowania , Zabierz tę książkę do domu i odłóż trochę czasu, aby nauczyć się budować następną wpływową, potężną, usprawnioną i ważną aplikację internetową, witrynę, która jest na tobie i robi dokładnie to, czego chcesz i spełnia potrzeby twoich odbiorców. O mnie: Jestem programistą z szerokimAnge doświadczenia w C/C ++, Java, Python, HTML, CSS i JavaScript. Buduję strony internetowe, które ludzie chcą korzystać, chcą odwiedzić, a nawet uzależnić się od używania, aby uczyć się, odtwarzać i zabijać czas, a co najważniejsze, sprzedaję oprogramowanie. Jeśli miałeś pomysł na to, jak chcesz wyglądać i funkcjonować witryny, byłeś gotów mnie wspierać, abym mógł zaspokoić własne potrzeby, gdy spotykam twoje, i jesteś gotów pokryć koszty uruchomienia witryny, samodzielnie, Zbudowałbym Cię następnego YouTube, Tiktok, Twittera, Google, a nawet zaawansowanej technologii bezpieczeństwa, który możesz uzyskać dostęp. Zamiast próbować sprzedać ci mój czas, próbuję kupić twoje: chcę sam porozmawiać o budowie aplikacji (strony internetowej) z informacjami, które już istnieją, i nauczyć, czego potrzebujesz, aby być niezależnym programistą, Przedsiębiorca, prowadzący udaną karierę w dowolnej dziedzinie. I pozwól, że wyjaśnię, edukacja, którą ci daję, będzie nieformalne. Możesz iść do szkoły i nauczyć się tego wszystkiego zRMAL Education, a nawet przeczytaj tę książkę w szkole, wypełnij swoje zadania i odbierz wiele z edukacji, ale formalnie nie postawię cię na gorąco i poprosisz o wykonanie zadań. Nie jestem twoim profesorem, możesz pomyśleć o mnie jak o przyjacielu, który chce cię poprowadzić w kierunku kariery prowadzonej przez twój osobisty sukces. I też nie sprzedaję ci sukcesu, będziesz musiał go kupić wraz z czasem. Nauka kodu ma stromą krzywą uczenia się i nigdy nie była łatwa, a nawet nie powinna być. Musisz pracować tak ciężko, jak to możliwe, i nadal próbować porażić się i próbować ponownie, nawet jeśli jesteś sfrustrowany, aby samodzielnie uczyć się i budować aplikacje. To ma charakter samego kodu. Kod jest prowadzony przez kompilator, który ma na celu przekazanie komunikatów o błędach programisty, które nauczy Cię, jak kodować, nawet jeśli po prostu kopiujesz błąd w wyszukiwarce i czytasz przykłady innych osób. I muszę powiedzieć, że nie musisz być niezwykle bogaty, mądry, odnoszący sukcesy,En zorientowany lub zorganizowany w celu zbudowania aplikacji. Komputer opiekuje się tą organizacją. Musisz tylko wytrwać przez próbę i błędy, koncentrować się i ciężko pracować nad tym, co robisz, a będziesz miał bardzo udaną karierę w całości tego, co robisz. Kim jestem: Zdaję sobie sprawę, że ostatnia sekcja była bardziej na temat nauki i przechodzisz z tej książki. Kim dokładnie jestem? To skomplikowane pytanie. Nie jestem jasny, że sam, ponieważ cierpię na warunki medyczne, które mogą mi utrudniać nawet kodowanie lub pisanie tej książki, jednocześnie prezentując wyzwania związane z socjalizacji i tożsamości, które utrudniają moje życie, jeśli chodzi o wprowadzenie siebie . Krótko mówiąc, jeśli czytasz tę książkę, przyniósł ją do domu, ponieważ przerzuciłeś ją i myślałeś wszystko, co robisz. Sam jestem inżynierem, oprogramowaniemDeweloper i student, a ja piszę tę książkę dla innych studentów, którzy chcą ułatwić swoje życie, mając podręcznik oprogramowania, którego potrzebują, ułatwiając swoje życie, podając przykłady do kopiowania, które pasują do siebie jak duża łamigłówka do pracy , Przydatna, duża, funkcjonalna, spójna i angażująca aplikacja, która może zwiększyć sukces bez względu na linię biznesu. W dużej mierze to właśnie robię: buduję aplikacje, aby pomóc sobie i innym ludziom odnieść sukces. Jestem również autorem, choć jest to moja pierwsza publikacja, którą zamierzam ukończyć, aby połączyć moje portfolio w użyteczny dokument, a także artysta. Przyznaję ci to, jestem trochę dziwną osobą. Nie jestem doskonały, biegałem INS z prawem, nawet prowadząc mnie do opuszczenia uczelni i uniwersytetów i opuszczenia stanów, aby spróbować nadać sobie markę z większym sukcesem. Jestem kobietą z urodzenia, noszę makijaż, robię sobie zdjęcia, noszę sukienki i inne odzież damskie, a ja jestem świadomy siebie jakoMężczyzna z natury. W przeszłości miałem problemy z innymi ludźmi, które doprowadziły do ​​walki z pisaniem i budowaniem WebApps, i przepraszam, że nie byłem w stanie wcześniej dostać tej książki w twoich rękach: potrzebujesz tego. Będziesz chciał przeczytać i napisać kod, który wygląda jak mój i działa jak moje i robi to samo, ale jeszcze lepiej, ponieważ jeśli możesz sobie pozwolić na zakup tej książki zamiast rządzić klawiaturą, tak jak ja tylko po to, aby stworzyć książkę, prosząc pieniądze W tym celu masz zasoby, które potrzebujesz, aby odnieść sukces w swoim życiu. Miałem różnego rodzaju problemy z dorastaniem rodziny, warunkami zdrowotnymi, lekarzami, mediami i prawem, a mój kod głęboko odzwierciedla walkę, jaką jest feminizm i kobieca natura w podzielonym i sfrustrowanym świecie. Jednak ta książka jest czymś, na czym mnie bardzo zależy, moje dziecko, moje portfolio i moje utrzymanie, więc doceniam twoje rozważanie, gdy zabierasz SMS -a do domu i starannie nad nią uczą się ode mnie. Pamiętaj, że nie jestem doskonały,Książka będzie miała błędy, poprawki i nowe wydania, a będziesz musiał pomyśleć o swoim logicznym mózgu najlepiej jak potrafisz, aby mieć udane doświadczenie z moim pisaniem. Zrozum również, że mam na myśli dobrze dla ciebie, nawet jeśli napotykasz wyzwania podczas pisania. Pomyśl o tym w ten sposób: kiedy możesz po prostu wynająć system komputerowy, aby zrobić wszystko, co możesz sobie wyobrazić w przestrzeni cyfrowej, przechowywać wszystkie napotkane informacje, #$%! Yze i zorganizuj je i przyjdź, aby to zrozumieć, będziesz Nieuchronnie napotykają trudności z informacjami, które spożywasz, a nawet publikujesz. Mówię ci to, ponieważ napotykam te same trudności. Skorzystaj z tej książki na własne ryzyko, pracuj ze swoją społecznością i społecznościami dostępnymi, aby tworzyć oprogramowanie w bezpiecznym otoczeniu, i nie bierz rzeczy osobiście, gdy nie udajesz się, a nawet odniesiesz sukces: w ten sposób dotarłem tak daleko i dlaczego mogę przynieść ci ten tekst i pomóc ci odnieść sukces bez rozbieżności na ścieżce szaleństwa, które odchodziZrujnowałem, rozdarłem i strzępiłem, podczas gdy ja napotykam zwykłe problemy, które wszyscy robią w skali globalnej dzięki paralelistycznej skali globalnej sieci, nad którą będziemy pracować, Internet. Być może nie znasz tego, kim jestem z kilkoma słowami, ale zachęcam do czytania, poznajesz mnie, gdy nadal czytasz i rozumiesz, budując własne projekty, aby ukończyć swoją pracę. Z tą książką nie będzie pracy domowej, o ile twoi profesorowie lub nauczyciele nikt cię nie przypisuje, ale gorąco zachęcam do samodzielnego zbudowania portfela projektów, a także projektu Capstone, który pokazuje, jak możesz Zastosuj to, czego się nauczyłeś. Mój projekt Capstone jest podstawą większości tego, co przeczytasz w tej książce, ponieważ zawiera kod z moich poprzednich projektów, kod, który stworzyłem i nauczyłem się pisać metodycznie ręcznie, oraz szeroki zakres pomysłów i wskazówek, które mi pomogły odnieść sukces do tego stopnia, że ​​mogę zwrócić się do prostej aplikacjiWYKORZYSTANIE, Wygląd i zachowuje się jak popularna aplikacja, którą możesz zobaczyć, jak twój przyjaciel lub rodzina korzysta w Internecie, reklamowana lub w wiadomościach. Jaka jest ta książka: Ta książka jest samouczkiem według przykładu. Możesz znaleźć kod tutaj, instrukcje nauki kodu, informacji na temat debugowania kodu i błędów ustalania, kroków rozwiązywania problemów, instrukcje dotyczące tworzenia kopii zapasowych i zapisywania kodu, ponownego wdrożenia, jeśli ktoś złamie kod, zabezpieczyć kod, wdrożyć, wdrożyć Twój kod, buduj interaktywne strony internetowe, które są zabawne, angażujące i uzależniające, a zrozumiesz, kim jestem, dlaczego jest to ważne i jak przedstawić siebie, swoją aplikację i wizerunek firmy, a także oprogramowanie, które budujesz W absolutnie najlepszym świetle jest najbardziej atrakcyjne dla użytkowników końcowych, odwiedzających witrynę. W tej książce zademontuję szereg prz...
Praktyczne głębokie uczenie się i bezpieczeństwo w oparciu o Internet na przykładzie

Praktyczne głębokie uczenie się i bezpieczeństwo internetowe według przykładu Trzecie wydanie Charlotte Harper 3 lipca 2024 r Przedmowa: Rozważania dotyczące bezpieczeństwa w budowaniu oprogramowania dla sieci są ważną częścią każdego planu i realizacji programisty internetowych podczas inżynierii prototypu, który jest niezawodny, stabilny i przydatny do celów praktycznych. DOM (znaczniki obiektu Dokument), wraz z jego wdrożeniem HTML, JavaScript i CSS, a także oprogramowaniem zaplecza wdrażającego Python, C/C ++, Java i Bash, daj programistom internetowym swobodę i władzę do tworzenia wielu różnych projektów, które wyrażają Kreatywność, zapewnij łatwość użytkowania i funkcjonalności, przedstawić pokorę i charakter oraz zapewnić łatwość użytkowania, a także wygodę i ważne usługi, które są atrakcyjne dla przeciętnego Joe, użytkownika końcowego, który chce zabić czas lub coś zrobić w Internecie, Zwykle na urządzeniu do smartfona z ekranem dotykowym. Większość ludzi nawet nie wiedziałaby, od czego zacząć, kiedy chcą zbudować stronę internetowąScratch, mają tendencję do zaczynania na stronie innej osoby i budują coś ograniczonego pod względem funkcjonalności, niezawodności, łatwości użytkowania, a zwłaszcza kreatywności, gdy mogliby mieć do dyspozycji wszystkie najnowsze potężne narzędzia, aby zbudować coś przydatnego bez marnowania czasu naciskania przycisków , a zwłaszcza marnowanie pieniędzy płacących za drogie subskrypcje oprogramowania, które niewiele osób chciało skorzystać, biorąc pod uwagę jego ograniczenia w łatwości użytkowania i elastyczności. Jeśli masz kilka minut na przeczytanie tej książki i dowiedz się, czego chcę cię nauczyć, a nawet porozmawiać ze mną osobiście o swoich celach i uzyskać wskazówki we właściwym kierunku, i jesteś zmotywowany do nauki kodowania i pisania własnego oprogramowania , Zabierz tę książkę do domu i odłóż trochę czasu, aby nauczyć się budować następną wpływową, potężną, usprawnioną i ważną aplikację internetową, witrynę, która jest na tobie i robi dokładnie to, czego chcesz i spełnia potrzeby twoich odbiorców. O mnie: Jestem programistą z oprogramowaniemZakres doświadczenia w C/C ++, Java, Python, HTML, CSS i JavaScript. Buduję strony internetowe, które ludzie chcą korzystać, chcą odwiedzić, a nawet uzależnić się od używania, aby uczyć się, odtwarzać i zabijać czas, a co najważniejsze, sprzedaję oprogramowanie. Jeśli miałeś pomysł na to, jak chcesz wyglądać i funkcjonować witryny, byłeś gotów mnie wspierać, abym mógł zaspokoić własne potrzeby, gdy spotykam twoje, i jesteś gotów pokryć koszty uruchomienia witryny, samodzielnie, Zbudowałbym Cię następnego YouTube, Tiktok, Twittera, Google, a nawet zaawansowanej technologii bezpieczeństwa, który możesz uzyskać dostęp. Zamiast próbować sprzedać ci mój czas, próbuję kupić twoje: chcę sam porozmawiać o budowie aplikacji (strony internetowej) z informacjami, które już istnieją, i nauczyć, czego potrzebujesz, aby być niezależnym programistą, Przedsiębiorca, prowadzący udaną karierę w dowolnej dziedzinie. I pozwól, że wyjaśnię, edukacja, którą ci daję, będzie nieformalne. Możesz iść do szkoły i nauczyć się tego wszystkiego zFormalna edukacja, a nawet przeczytaj tę książkę w szkole, wypełnij swoje zadania i odbierz wiele z edukacji, ale formalnie nie postawię cię na gorąco i nie poprosisz o wykonanie zadań. Nie jestem twoim profesorem, możesz pomyśleć o mnie jak o przyjacielu, który chce cię poprowadzić w kierunku kariery prowadzonej przez twój osobisty sukces. I też nie sprzedaję ci sukcesu, będziesz musiał go kupić wraz z czasem. Nauka kodu ma stromą krzywą uczenia się i nigdy nie była łatwa, a nawet nie powinna być. Musisz pracować tak ciężko, jak to możliwe, i nadal próbować porażić się i próbować ponownie, nawet jeśli jesteś sfrustrowany, aby samodzielnie uczyć się i budować aplikacje. To ma charakter samego kodu. Kod jest prowadzony przez kompilator, który ma na celu przekazanie komunikatów o błędach programisty, które nauczy Cię, jak kodować, nawet jeśli po prostu kopiujesz błąd w wyszukiwarce i czytasz przykłady innych osób. I muszę powiedzieć, że nie musisz być niezwykle bogaty, mądry,Essful, a nawet zorientowany na szczegóły lub zorganizowany w celu zbudowania aplikacji. Komputer opiekuje się tą organizacją. Musisz tylko wytrwać przez próbę i błędy, koncentrować się i ciężko pracować nad tym, co robisz, a będziesz miał bardzo udaną karierę w całości tego, co robisz. Kim jestem: Zdaję sobie sprawę, że ostatnia sekcja była bardziej na temat nauki i przechodzisz z tej książki. Kim dokładnie jestem? To skomplikowane pytanie. Nie jestem jasny, że sam, ponieważ cierpię na schorzenia, które mogą mi utrudniać nawet kodowanie lub pisanie tej książki, jednocześnie prezentując wyzwania związane z socjalizacjami i tożsamością, które utrudniają moje życie, jeśli chodzi o wprowadzenie siebie . Krótko mówiąc, jeśli czytasz tę książkę, przyniósł ją do domu, ponieważ przerzuciłeś ją i myślałeś wszystko, co robisz. Sam jestem inżynierem,Deweloper i student, a ja piszę tę książkę dla innych studentów, którzy chcą ułatwić swoje życie, mając podręcznik oprogramowania, którego potrzebują, ułatwiając swoje życie, podając przykłady do kopiowania, które pasują do siebie jak duża łamigłówka do pracy , Przydatna, duża, funkcjonalna, spójna i angażująca aplikacja, która może zwiększyć sukces bez względu na linię biznesu. W dużej mierze to właśnie robię: buduję aplikacje, aby pomóc sobie i innym ludziom odnieść sukces. Jestem również autorem, choć jest to moja pierwsza publikacja, którą zamierzam ukończyć, aby połączyć moje portfolio w użyteczny dokument, a także artysta. Przyznaję ci to, jestem trochę dziwną osobą. Nie jestem doskonały, biegałem INS z prawem, nawet prowadząc mnie do opuszczenia uczelni i uniwersytetów i opuszczenia stanów, aby spróbować nadać sobie markę z większym sukcesem. Jestem kobietą z urodzenia, noszę makijaż, robię sobie zdjęcia, noszę sukienki i inne odzież damskie, a ja jestem świadomy siebie jakoKobieta z natury. W przeszłości miałem problemy z innymi ludźmi, które doprowadziły do ​​walki z pisaniem i budowaniem WebApps, i przepraszam, że nie byłem w stanie wcześniej dostać tej książki w twoich rękach: potrzebujesz tego. Będziesz chciał przeczytać i napisać kod, który wygląda jak mój i działa jak moje i robi to samo, ale jeszcze lepiej, ponieważ jeśli możesz sobie pozwolić na zakup tej książki zamiast rządzić klawiaturą, tak jak ja tylko po to, aby stworzyć książkę, prosząc pieniądze W tym celu masz zasoby, które potrzebujesz, aby odnieść sukces w swoim życiu. Miałem różnego rodzaju problemy z dorastaniem rodziny, warunkami zdrowotnymi, lekarzami, mediami i prawem, a mój kod głęboko odzwierciedla walkę, jaką jest feminizm i kobieca natura w podzielonym i sfrustrowanym świecie. Jednak ta książka jest czymś, na czym mnie bardzo zależy, moje dziecko, moje portfolio i moje środki utrzymania, więc doceniam twoje rozważanie, gdy zabierasz SMS -a do domu i starannie nad nią uczą się ode mnie. Pamiętaj, że nie jestemECT, ta książka będzie miała błędy, poprawki i nowe wydania, a będziesz musiał pomyśleć ze swoim logicznym mózgiem najlepiej jak potrafisz, aby mieć udane doświadczenie z moim pisaniem. Zrozum również, że mam na myśli dobrze dla ciebie, nawet jeśli napotykasz wyzwania podczas pisania. Pomyśl o tym w ten sposób: kiedy możesz po prostu wynająć system komputerowy, aby zrobić wszystko, co możesz sobie wyobrazić w przestrzeni cyfrowej, przechowywać wszystkie napotkane informacje, #$%! Yze i zorganizuj je i przyjdź, aby to zrozumieć, będziesz Nieuchronnie napotykają trudności z informacjami, które spożywasz, a nawet publikujesz. Mówię ci to, ponieważ napotykam te same trudności. Skorzystaj z tej książki na własne ryzyko, pracuj ze swoją społecznością i społecznościami dostępnymi, aby tworzyć oprogramowanie w bezpiecznym otoczeniu, i nie bierz rzeczy osobiście, gdy nie udajesz się, a nawet odniesiesz sukces: w ten sposób dotarłem tak daleko i dlaczego mogę przynieść ci ten tekst i pomóc ci odnieść sukces bez rozbieżności na ścieżce szaleństwaAves Me Zrujnowany, rozdarty i strzępiony, podczas gdy ja napotykam zwykłe problemy, które wszyscy robią w skali globalnej dzięki paralelistycznej skali globalnej sieci, nad którą będziemy pracować, Internet. Być może nie znasz tego, kim jestem z kilkoma słowami, ale zachęcam do czytania, poznajesz mnie, gdy nadal czytasz i rozumiesz, budując własne projekty, aby ukończyć swoją pracę. Z tą książką nie będzie pracy domowej, o ile twoi profesorowie lub nauczyciele nikt cię nie przypisuje, ale gorąco zachęcam do samodzielnego zbudowania portfela projektów, a także projektu Capstone, który pokazuje, jak możesz Zastosuj to, czego się nauczyłeś. Mój projekt Capstone jest podstawą większości tego, co przeczytasz w tej książce, ponieważ zawiera kod z moich poprzednich projektów, kod, który stworzyłem i nauczyłem się pisać metodycznie ręcznie, oraz szeroki zakres pomysłów i wskazówek, które mi pomogły odnieść sukces do tego stopnia, że ​​mogę zwrócić się do prostej aplikacjiW pełni wyróżniony, wygląd i zachowuje się jak popularna aplikacja, którą możesz zobaczyć, jak twój przyjaciel lub rodzina używa w Internecie, reklamowana lub w wiadomościach. Jaka jest ta książka: Ta książka jest samouczkiem według przykładu. Możesz znaleźć kod tutaj, instrukcje nauki kodu, informacji na temat debugowania kodu i błędów ustalania, kroków rozwiązywania problemów, instrukcje dotyczące tworzenia kopii zapasowych i zapisywania kodu, ponownego wdrożenia, jeśli ktoś złamie kod, zabezpieczyć kod, wdrożyć, wdrożyć Twój kod, buduj interaktywne strony internetowe, które są zabawne, angażujące i uzależniające, a zrozumiesz, kim jestem, dlaczego jest to ważne i jak przedstawić siebie, swoją aplikację i wizerunek firmy, a także oprogramowanie, które budujesz W absolutnie najlepszym świetle jest najbardziej atrakcyjne dla użytkowników końcowych, odwiedzających witrynę. W tej książce zademontuję szereg przykładów projektowania oprogramowania, koncentrując się na sieci jako platforma, a także bezpieczeństwo. Zainicjujemy doświadczenie edukacyjne, budując podstawowyOject za pomocą powłoki UNIX z funkcjami tworzenia kopii zapasowych i skryptowych. Następnie przeanalizujemy podstawową stronę blogu, zaktualizujemy nasz blog o funkcjach fotograficznych i wideo, a także skorzystamy z tych funkcji do zastosowania rozwiązań bezpieczeństwa za pomocą bezpłatnego oprogramowania, i zabezpieczyć nasz serwer za pomocą modułu uwierzytelniania wtyczki (PAM). Następnie przeglądamy obsługę i przetwarzanie plików, eksplorując edycję wideo, darowiznę głosową, skanowanie kodów kreskowych i rozpoznawanie znaków optycznych, między innymi. Po drodze zbadamy interfejsy API, które pomogą nam uczynić nasze oprogramowanie bardziej użytecznym i bezpiecznym, z bezpłatnymi i płatnymi opcjami. Po drodze zbadamy fizyczne bezpieczeństwo i bojowe narzędzia, takie jak projektowanie i produkcja broni palnej i amunicji, w tym projektowanie beczek i repeater, projektowanie wieży i dronów oraz innych dyrektorów zintegrowamy się z naszym oprogramowaniem w istniejącej sieci w celu ochrony naszego oprogramowania i zademonstruj samoobronę i odporność. Zrobimy przerwy po drodze do budowania gier, 2D i 3DEndering Silny i pracują z osadzonym sprzętem w przykładach studium przypadku podstawowego oprogramowania do renderowania wymiarów i elektronicznego wibrującego masażera odlewanego odpowiednio w gumy silikonowej. Po drodze będziemy również dostępne rozwiązania uczenia maszynowego, aby lepiej zabezpieczyć nasze oprogramowanie. Będziemy również zastosować narzędzia magazynowe dostępne dla Internetu w celu usprawnienia i zabezpieczenia procesu. Ta książka jest przewodnikiem po twoim sukcesie w budowaniu aplikacji internetowej i integracji z profesjonalną siecią komputerów i wbudowanych systemów mechanicznych oraz ogólnie przewodnikiem po budowaniu oprogramowania i osadzonego sprzętu bez wiedzy w tle lub wcześniejszych doświadczeniach. Czym nie jest ta książka: Jeśli naprawdę chcesz mieć stronę internetową, możesz po prostu skonfigurować prosty sklep i sprzedać to, czego potrzebujesz, opublikować blog, publikować zdjęcia lub filmy lub inaczej bez pisania jednej linii kodu. Ta książka nie jest taka. Ta książka nauczy Cię, jak budować oprogramowanie, które jest bardziej przydatne, w pełniPolecane, funkcjonalne i bezpieczne niż jakiekolwiek oprogramowanie, które już możesz znaleźć, ponieważ wdraża najnowsze oprogramowanie, które nadal jest prototypami, może być drogie w obsłudze w skali, w której działają starsze firmy i nie odwołują się do wstecz, zawijanych firm ustanowionych Zarabiaj pieniądze dla ludzi, którzy tak naprawdę nic nie robią. Jeśli uważnie śledzisz tę książkę, będziesz chciał napisać kod, kod zbadania, zbudować własne aplikacje i zarabiasz na tym, co robisz. Zarabiam na tej książce, nawet na wczesnych etapach, ponieważ zawiera ona informacje, które ludzie potrzebują i chcą czytać, i już kupują, gdy kupują lub korzystają z moich aplikacji. Ta książka nie zbuduje dla ciebie aplikacji, ale wskazuje ci właściwy kierunek i uzbiera Cię w potrzebne narzędzia oraz umiejętności i wskazówki, które ułatwią Twojego sukcesu w tworzeniu oprogramowania do sieci, z każdą linią kod, który będziesz musiał napisać jako przykład, gotowy do złożenia w oprogramowaniu Ty i Twoich kibiców, gości, klientele,Rodzin, rodzina, odwiedzający, kontrahenci i mieszkańcy Internetu chcą korzystać i wspierać. Czego się nauczysz: Ta książka nauczy Cię, jak tworzyć i sprzedawać oprogramowanie, naprawdę funkcjonalne, przydatne oprogramowanie, nagrywanie mediów, funkcje bezpieczeństwa, takie jak rozpoznawanie twarzy, skanowanie kodów kodów odczytu odczytu maszynowego, interfejsy internetowe do uwierzytelniania, nagrywania i renderowania wideo i zdjęć oraz wymiany wiadomości takich jak Bluetooth oraz komunikacja w pobliżu Field (NFC). Ta książka nauczy Cię, jak korzystać z komputera sieciowego, koncentrując się na Debian Linux, jak zbudować kod BASH, aby instalować i tworzyć kopie zapasowe oprogramowania bezproblemową, zautomatyzowaną bryza, jak budować kod Pythona jako zaplecza do obsługi dynamicznych wiadomości, styl, styl, styl, styl, styl, Rzeczy ładnie przy użyciu stylów CSS z bootstrapem, włącz logowanie użytkowników i interaktywność za pośrednictwem urządzeń sieciowych, buduj interaktywne media i sieć z innymi stronami internetowymi, aby oferować funkcje bezpieczeństwa, takie jak wiadomości tekstowe do weryfikacji lub inne cele, skanowanie identyfikatorów, moderacja obrazu i wideo, moderacja danych, dane danychOkup, aby zapewnić bezpieczeństwo oprogramowania, przetwarzanie płatności, handel kryptowalutami, zadania asynchroniczne i wiele innych. Dowiesz się, jak budować własne urządzenia Bluetooth, z akumulatorami, ładowarkami, mikrokontrolerów, obwodami, silnikami i czujnikami, używając lutu, drutu i 3D, a także odlewane materiały. Wykazam dyrektorów projektowania 3D zastosowanych do produkcji addytywnej oraz produkcji narzędzi i matrycy, dzięki czemu możesz wyprodukować własne wbudowane urządzenia sprzętowe ze zintegrowanymi bateriami, ładowarkami, obwodami elektronicznymi i wyjściami funkcjonalnymi. I połącz je z Bluetooth i Internet. W szczególności zbadamy dwa studia przypadków, wibrujący masażer i domową broń palną, oba zaprogramowane w Openscad, które jest dostępne jako interfejs graficzny lub narzędzie linii poleceń i może być zintegrowane z siecią dla szybszych wyników. Dowiesz się, jak budować i wdrażać stronę internetową od podstaw bez wcześniejszego doświadczenia, sprawić, że jest funkcjonalna, bezpieczna, piękna, przydatna i większośćMimortycznie praktyczne. Dowiesz się, jak korzystać z uczenia maszynowego i wizji komputerowej, aby witryna była bezpieczna i bardziej praktyczna, nagrywać wideo i audio ze swojej witryny, przekazać głos, tworzyć muzykę i modulować dźwięk, aby tworzyć przydatne próbki oraz jak przełamać szum według Wykorzystując inne strony internetowe, aby zbudować najlepszą możliwą sieć stron internetowych, które możesz połączyć bezpośrednio do twojej, aby udostępnić wszystkie przydatne informacje, które masz do zaoferowania, a co ważniejsze, sprowadzić ludzi do Twojego oprogramowania i biznesu. Ta książka zostanie najbardziej skoncentrowana na mediach, bezpieczeństwie i uczeniu maszynowym, które są głównymi trzema komponentami, które pomogą Ci zbudować użyteczne oprogramowanie dla sieci, angażując odpowiednich użytkowników i rozłączając niewłaściwe w sposób realistyczny, praktyczny, Ręce i angażowanie się, a także automatyczne i solidne. Ta książka uczy UNIX, szczególnie Debiana (Ubuntu), Bash Shell, Python, HTML, CSS, JavaScript i wielu przydatnych pakietów oprogramowania dlaN Podoba mi się żądania, a także przydatne oprogramowanie Bash, takie jak GIT i FFMPEG. Nauczę cię również, jak automatycznie handlować kryptowalutą i przyjmować płatności w kryptowalutach lub z regularnych kart debetowych, a nawet wypłacając odwiedzającym udział twoich przychodów, jeśli zdecydujesz się to zrobić. Nauczę cię również zarabiać na swojej stronie internetowej poprzez reklamę, jak przygotować aplikację do wyszukiwarek i uczynić ją szybką, rankingiem w pierwszym rankingu tego, co Twoi klienci będą szukać, aby cię znaleźć, i ranking w tylu popularnych Wyszukuje, jak to możliwe. Nauczę cię, jak sprzedawać swoje oprogramowanie, reklamować je, odwoływać się do klientów szukających twoich usług i nadawać sobie nazwę w Internecie za pośrednictwem możliwości, które już istnieją, są niedrogie i dobrze działać. Nauczę Cię, jak zapisywać dane na komputerach w chmurze, które działają dla Ciebie i tanio zapisać dane, jak planować i budować witrynę, która robi to, czego chcą twoi użytkownicy i co chcesz, i jak utrzymać zaangażowanie użytkownikówW przypadku witryny dotknij swoich telefonów z powiadomieniami, e -mailem, wiadomościami tekstowymi, połączeniami telefonicznymi i kolejnymi możliwościami, aby sprowadzić użytkowników z powrotem do witryny do dyspozycji za kliknięciem przycisku zabezpieczonego tylko do Ciebie. Ta książka koncentruje się na praktyczności publikowania i dystrybucji mediów w dużych ilościach, od tekstu, zdjęć, filmów po audio, wyrobu dobrego wrażenia dla użytkowników końcowych (klientów) i sprzedaży w dowolny sposób, aby stworzyć, aby stworzyć Witryna, aplikacja, która jest reprezentatywna tylko dla Ciebie i Ciebie, i sprawia, że ​​twoje oprogramowanie i Twoja firma wyglądają dobrze w najlepszym możliwym sposobie. Nauczysz się także kilku wskazówek i wskazówek, od wskazówek kodowania, próżnej próżności, takich jak makijaż i fotografia, modelowanie i aktorstwo, a więcej, co będzie ważne dla przedstawiania siebie i Twojej firmy w najlepszym możliwym świetle, korzystając z wszystkich dostępnych narzędzi Dystrybuując tyle treści, ile potrzebujesz na zdrowej równowagi platform, aby przynieść swojee, aby zrealizować bez większego wysiłku, pracy lub pieniędzy, niż jest to konieczne. Ta książka nazywa się „praktyczne głębokie uczenie się i bezpieczeństwo internetowe według przykładu” z jakiegoś powodu: zajmuje się uczeniem się kodowania, szczególnie dla Internetu, szczególnie z naciskiem na bezpieczeństwo, z praktycznego punktu widzenia, z przykładami kodu roboczego, który obsługuje kod, który obsługuje Praktyczne cele przedstawione w tekście. Komponent uczenia się tego tekstu obejmuje również uczenie maszynowe, kod, który pokażę, jak uruchomić w Internecie, który obsługuje wizję komputerową, rozpoznawanie twarzy, moderację obrazu i wideo, ulepszenie obrazu, ulepszenie rozdzielczości, podpis obrazu i inne zadania, takie jak Wskaźniki prognozowe pochodzące z obrazów, takie jak charakter obrazu jako autentyczny, przenoszony komputerowo obraz lub kopia optyczna (zdjęcie obrazu lub wydrukowane zdjęcie). Uczenie maszynowe jest bardzo ważne, jeśli chodzi o bezpieczeństwo internetowe i bezpieczeństwo oprogramowania, ponieważ może ono preformować zadania, które w przeciwnym razie były niemożliwe. Twój komputerZaloguj się za pomocą kodu pasów, ale może być bezpieczniejsze, jeśli zaloguje się z twarzą. Możesz stworzyć komputer serwerowy ten bezpieczny, komputer, który normalnie poprosiłby Cię o nazwę użytkownika i kod pasów i zalogować się, być może za pomocą tokena potwierdzającego dla każdego nowego logowania lub nowego adresu IP, ale jeśli budujesz dużą skalę, łatwe, łatwe do tego Używanie, zasadniczo bezpieczne i potężne oprogramowanie, może to wystarczyć. Zbyt ścisłe powiązanie oprogramowania z oprogramowaniem innej osoby, takie jak usługa e -mail lub usługa wiadomości tekstowych, nie wystarczy, aby Twoje oprogramowanie były bezpieczne lub inna (jakąkolwiek witrynę, której używasz). Każdy, kto buduje oprogramowanie, które jest nienagannie bezpieczne, ma pewne pojęcie o tym, co to implikuje. Oprogramowanie jest z natury niepewne, ponieważ urządzenia i konta, których używamy do dostępu do niego, nie zawsze są do naszej dyspozycji, mogą być w rękach każdego, kto ma źle zamierzony oprogramowanie, a zatem mogą stanowić zagrożenie dla samego oprogramowania. To jest w centrum tej książki. Komputer sieciowy jest domyślnieZabezpieczony długim tokenem klucza, nazywanym i SSH lub Secure Shell Key, a poza tym najlepiej jest zabezpieczyć serwer WWW, ponieważ serwer WWW zapewnia otwarty dostęp, a także najnowocześniejsze narzędzia bezpieczeństwa działające na samym serwerze. Serwer WWW ma dostęp do przeglądarki internetowej użytkownika, która jest prawdopodobnie najpotężniejszą częścią urządzenia użytkownika, ponieważ jest to miejsce, w którym użytkownik może uzyskać dostęp do oprogramowania sieciowego. Ten zestaw narzędzi może renderować tekst, strony, które widzisz, a także rejestrować obrazy, audio i wideo (jak zdjęcie twarzy lub identyfikatora stanu), może odczytać i pisać na urządzeniach radiowych Bluetooth oraz może czytać i pisać w Blish Field Tagi transpondera, niedrogie karty kluczowe, FOB, naklejki, pierścienie, a nawet implanty chipowe z unikalnymi numerami seryjnymi, które można odczytać i zapisać z wygenerowanymi danymi i sprawdzaniem danych przez serwer WWW powiązany z witryną internetową. Korzystając z wszystkich narzędzi do Twojej dyspozycji, dzięki tej książce wyposażysz się w wiedzę, aby zbudować bezpieczną stronę internetową i ogólnieSystem komputerowy URE, który działa dla Ciebie, wykonuje licytację, wygląda i czuje się dobrze. Od czego zacząć: Zapraszamy do pominięcia sekcji, z którą zaczynam tę książkę lub dowolną sekcję, do dokładnego potrzebnego kodu, zwłaszcza jeśli masz doświadczenie w kodowaniu wcześniej lub dowolnym z wyżej wymienionych narzędzi, które szczegółowo opisam w tej książce jako Jak dokumentuje przypadki użycia i ich praktyczne przykłady. Jeśli nie masz doświadczenia w pisaniu kodu, zdecydowanie polecam przeczytanie całej tej książki, a zwłaszcza polecam przeczytanie poprzednich sekcji, aby upewnić się, że ta książka jest dla Ciebie odpowiednia. Jeśli ta książka nie jest dla Ciebie odpowiednia, rozważ obdarowanie jej przyjaciela lub krewnego, który może być zainteresowany samodzielnym uczeniem się o rozwoju stron internetowych, a nawet rozważ pożyczenie jej i uczenie się od nich, aby wypełnić luki, w których zawiodłem jako Nauczyciel lub inni nauczyciele zrobili przede mną. Zacznij tam, gdzie chcesz, każda część tej książki będzie przydatna, jeśli zamierzasz zbudować przydatnePP i zastanów się, że najlepsze aplikacje są budowane z myślą o użytkowniku końcowym: Poznaj swojego klienta. Teraz mnie znasz, znasz tę książkę i jesteś gotowy do rozpoczęcia. Aby rozpocząć, weź komputer (nawet najtańszy laptop ze sklepu z pudełkami, Amazon lub stary komputer stacjonarny i skonfiguruj go w sposób, który działa dla Ciebie. Jak przeczytać tę książkę: Podświetlony tekst oznacza, że ​​tekst należy do wiersza polecenia, w którym napiszesz uruchomiony kod. Pojownik polecenia jest mocno skupiony na klawiaturze i wymaga niewielkiego lub żadnego kliknięcia, przyspieszania przepływu pracy i ułatwiania ci rzeczy. Pierwsze kroki: Zanurzmy się w środku. Zaczniemy od budowy kodu na lokalnym komputerze i zaczniemy bez budowania strony internetowej podłączonej do Internetu. Jest to bezpieczniejsze na początek, nic nie kosztuje i jest dla ciebie łatwe. W zależności od systemu operacyjnego wejście do skorupy bash będzie nieco inne. W przypadku Mac OS zalecam zainstalowanie maszyny wirtualnej w tym momencie, ponieważ uzyskasz największą kompatybilnośćmaszyna wirtualna. Różni dostawcy, tacy jak VirtualBox i Paralells, mogą uruchomić dla Ciebie maszynę wirtualną, choć możliwe jest również zainstalowanie Ubuntu bezpośrednio na komputerze, jeśli wolisz korzystać z natywnego środowiska, które jest zalecane w celu stworzenia szybkiego, usprawnionego doświadczenia. Jeśli używasz Linux lub Windows, co polecam, utworzenie projektu powinno być dość łatwe. Otwórz terminal, dostosuj rozmiar, jak postrzegasz dopasowanie, i zacznij następnego kroku 2. Jeśli korzystasz z systemu Windows, wykonaj krok 1. Krok 1: - Tylko użytkownicy Windows W systemie Windows otwórz wiersz polecenia jako administrator i wpisz WSL - Instalul Krok 2: - Kontynuuj tutaj lub przejdź do kroku 1 do tutaj, jeśli nie używasz systemu Windows W otwartym terminalu (w zależności od systemu operacyjnego, o nazwie Ubuntu w systemie Windows, Terminal w Mac lub Linux lub podobnej nazwie), zacznij od utworzenia projektu. Robimy to z poleceniem MKDIR, które tworzy katalog. Jeśli chcesz utworzyć katalog do przechowywania projektu, który jest zalecany, użyjpolecenie CD, aby zmienić się w katalog i i CD/ścieżka/do/Directory - ścieżką to foldery (pliki) poprzedzające katalog docelowy, domyślną ścieżką jest ~ lub/home/nazwa użytkownika (gdzie nazwa użytkownika jest twoją nazwą użytkownika). Aby zmienić na domyślny katalog, wpisz CD lub CD ~ Przykład MKDIR - Zastąp „przykład” na nazwę katalogu Teraz masz działający katalog do swojego projektu. Będąc tak ważne, aby ten katalog został zapisany na wypadek, gdybyś musiał przejść na inny komputer lub wdrożyć kod, który piszesz, aby był gotowy do sieci, zbudujemy skrypt, aby utworzyć kopię zapasową katalogu w następnych kilku krokach. Ale zbudowanie skryptu wymaga odrobiny kodu, a kod musi być zautomatyzowany, aby był jak najbardziej przydatny. Zbudujmy więc skrypt, aby najpierw zbudować skrypty. Zacznijmy od utworzenia skryptu i uczynienia go wykonywaniem. Użyjemy do tego sudo, chmod i dotyk i nazwiemy skrypt


sudo touch /usr/bin/ascript
sudo chmod a+x /usr/bin/ascript
sudo nano /usr/bin/ascript
Teraz utworzyliśmy skrypt, uczyniliśmy go wykonywaniem i jesteśmy gotowi go edytować. Nano to edytor tekstu, który pozwoli edytować tekst bez klikania, co jest znacznie łatwiejsze niż użycie graficznego interfejsu użytkownika. Aby edytować plik z Nano, użyj Nano, a następnie ścieżka do pliku. Aby zrobić scenariusz, który tworzy scenariusz, jest to dość podobne do tworzenia naszego scenariusza. Użyjemy tego samego kodu co powyżej, zastępując nazwę skryptu „Ascript” parametrem argumentu, 1 USD. To pozwala nam nazwać skrypt, wpisując po prostu Sudo Ascript Newscript, w którym to momencie możemy utworzyć każdy nowy skrypt, zastępując „Newscript” nazwą twojego skryptu. Kod w Nano powinien wyglądać:

sudo touch /usr/bin/$1
sudo chmod a+x /usr/bin/$1
sudo nano /usr/bin/$1
Aby zamknąć Nano, możemy przytrzymać klawisz kontrolny i nacisnąć x, a następnie Y, aby oznaczyć, że zapisujemy plik i nacisnąć powrót. Teraz zamiast wpisywać te trzy polecenia w celu edytowania skryptu, będziemy mogli wpisać Ascript Ascript, aby ponownie edytować skrypt. To działa! I każdy nowy skrypt można łatwo uruchomić, nazywając go w skorupce. Zapiszmy naszą pracę teraz: napiszmy skrypt kopii zapasowej, aby zapisać nasz nowy skrypt, a następnie poprzeć go w naszym katalogu projektu, jednocześnie tworząc kopię zapasową skryptu kopii zapasowej.

sudo ascript backup
Teraz w Nano:

sudo cp /usr/bin/backup /path/to/directory/
sudo cp /usr/bin/ascript /path/to/directory/
Gdzie/ścieżka/do/katalog jest ścieżką do projektu utworzonego za pomocą mkdir. Później dowiemy się, jak kopiować takie powtarzające się ścieżki z pętlą i listą, która jest mniej kodem, ale na razie zachowajmy to proste i miej kilka wierszy. Aby uruchomić ten skrypt i wykonać kopię zapasową kodu, zapisz plik w Nano z Control+X, Y i zwróć i wpisz poniżej w skorcie

backup
Jeśli w ogóle otrzymujesz monit o hasło podczas czytania tej książki i śledząc w powłoce, prawidłowo wprowadź hasło użytkownika, będziesz mieć trzy próby przed ponownym uruchomieniem polecenia. Możesz użyć strzałek w górę i w dół, aby ponownie je powtórzyć i edytować je, jeśli będziesz musiał uruchomić coś dwa razy. Proste naciśnij w górę i w dół, aby wybrać polecenie, przed edycją polecenia z prawą, lewą strzałką i usuwanie klawisza, a także klawiatury, i uruchamianie go z powrotem. Gratulacje! Udało ci się stworzyć niesamowity skrypt kopii zapasowej, który tworzy kopię zapasową dwóch ważnych skontleitów w swoim katalogu roboczym. Możemy się poruszać później, gdy projekt staje się większy, ale na razie działa. Przejdźmy do tworzenia kopii zapasowych w chmurze, użyjemy do tego GitHub (choć istnieje wiele innych rozwiązań git do tworzenia kopii zapasowych, wszystkie są mniej więcej takie same.) Git to oprogramowanie do kontroli Verision, które umożliwia tworzenie kopii zapasowych edycji do twoich oprogramowanie, gdy dotrzesz do serwera, aUmożliwiając także pobieranie całego kopii oprogramowania za hasłem lub kluczem. Przyczynia się do zapisywania oprogramowania, zwłaszcza gdy migrujemy do zabezpieczonych instancji Linux, które czasami pękają, gdy jedna linia kodu się nie powiedzie, pozostawiając cię zablokowaną, gdy kod może nie zostać utworzony, jeśli nie będziesz miał okazji go poprzeć Automatycznie, co obejmiemy. Jeśli w tym momencie nie korzystasz jeszcze z maszyny wirtualnej Ubuntu, polecam korzystanie z maszyny wirtualnej Ubuntu w tym momencie, ponieważ ułatwi to życie podczas instalowania wszystkich pakietów niezbędnych do zbudowania działającej strony internetowej i wstępnej nauki głębokiego Operacje na twoim komputerze. W najbliższej przyszłości przeniesiemy kod na serwer WWW, ale chcemy upewnić się, że za naszym serwerem WWW jest co najmniej kilka warstw bezpieczeństwa, które są odporne na phishing, i zastosować szereg pakietów Linux w celu uzyskania do zrobienia Ten. Jeśli nadal chcesz korzystać z systemu operacyjnego Mac, możesz wyszukać i zainstalowaćE niezbędne pakiety online, ale dla każdego pakietu może nie istnieć alternatywy dla każdego pakietu. Dodajmy kilka poleceń, aby popełnić naszą pracę ze skryptem kopii zapasowej, uruchamiając polecenie Sudo Ascript

# …
git add –all
git commit -m “backup”
git push -u origin master
Jeszcze raz kontroluj X, aby zapisać. Teraz musimy zrobić jedną konfigurację dla tego projektu. Ponieważ wkrótce będzie to projekt GIT, nie musimy pisać każdego polecenia za każdym razem, gdy wdrażamy z repozytorium GIT, ale otrzymamy to, kiedy piszemy nasze skrypty wdrażania. Na początek upewnijmy się, że jesteśmy we właściwym katalogu i zainicjujemy repozytorium GIT i generujemy klucze SSH.

cd /path/to/directory
git init
git branch -m master
ssh-keygen
Po wpisaniu SSH-KeyGen nowy klucz powinien zostać zapisany w folderze domowym pod folderem o nazwie .ssh. Nazywa się to id_rsa.pub. Znajdźmy ten klucz i skopiuj go. Aby to zobaczyć,

cd ~
cat .ssh/id_rsa.pub
Skopiuj tekst zwracany przez ostatnie polecenie, i utwórz konto u swojego dostawcy GIT (idealnie Github), przed dodaniem klucza SSH do konta. Po uzyskaniu konta kliknij prawe górne menu i wprowadź ustawienia, przed dodaniem klawisza SSH w klawiszach SSH i GPG w menu w menu. Wybierz Dodaj klawisz SSH i dodaj swój, wklejając go i nadając mu tytuł, zanim zapisasz i wróć do GitHub, aby utworzyć nowe repozytorium. Jest to podobne dla innych dostawców GIT, musisz przeczytać ich dokumentację. W nowej konfiguracji repozytorium podaj repozytorium opisową nazwę i zdecyduj, czy chcesz je opublikować, i upewnij się, że nie konfigurujesz żadnych plików do włączenia. Po utworzeniu repozytorium skopiuj klon za pomocą URL SSH i wklej go do następującego polecenia.

git remote add git://… (your remote URL)
Teraz możesz wrócić do repozytorium za pomocą CD, będziesz to znany. Wypróbuj skrypt kopii zapasowej teraz z kopią zapasową Świetnie! Teraz naprawdę możemy uzyskać kodowanie. Zainstalujmy Django teraz, kiedy mamy dobre zrozumienie Bash i Git. Django pozwoli nam automatycznie utworzyć kopię zapasową naszego oprogramowania, Bash też może to zrobić, ale Django powinien mieć prostszą bezpieczniejszą implementację (można go łatwiej wyłączyć i łatwiej skonfigurować). Aby zainstalować oprogramowanie w Ubuntu, użyjemy polecenia sudo apt-get. Najpierw zaktualizujmy i zaktualizujmy oprogramowanie, które już mieliśmy. Można to zrobić za pomocą aktualizacji sudo apt-get i sudo apt-get aktualizację -y. Następnie zainstalujmy Python i nasze wirtualne środowisko, dom naszego kodu, z następującym poleceniem: sudo apt-get instaluj Python-IS-Python3 Python3-venv To wszystko, czego potrzebujesz z Django pod względem instalacji oprogramowania w instancji Ubuntu. W przypadku systemu Windows i Linux powinno to być dość proste, ale w przypadku komputerów Mac możesz chcieć zainstalować maszynę wirtualną iLinux na IT przy użyciu bezpłatnego lub płatnego środowiska wirtualnego, takiego jak VirtualBox lub Paralells Desktop i odtwarza powyższe kroki w celu skonfigurowania środowiska Ubuntu. Ubuntu ma kluczowe znaczenie w tym przypadku, ponieważ jest to oprogramowanie prowadzone przez strony internetowe i umożliwia im obsługę stron internetowych ze wszystkimi wspomnianym oprogramowaniem. Zagłębmy się w Django. Ponownie w naszym katalogu, z

python -m venv venv # Tworzy wirtualne środowisko, w którym kod jest przechowywany
source venv/bin/activate # Aktywuje środowisko wirtualne
pip install Django
django-admin startproject mysite . # Gdzie Mysite to projekt, który zaczynam w moim obecnym katalogu.
Django dopiero nas zaczyna, ponieważ Django hostuje serwer WWW i robi wszystko, czego potrzebujemy, aby uruchomić podstawową lokalną stronę internetową. Teraz, gdy zainstalowaliśmy Django, edytujmy ustawienia trochę, aby działało, jak potrzebujemy. Najpierw utwórzmy nową aplikację

python manage.py startapp feed
Zauważysz, że pierwsza aplikacja nazywa się Feed. Aplikacja powinna być nazywana, jakkolwiek chcesz, a my utworzymy nowe aplikacje, ale nazwa każdej aplikacji musi być spójna za każdym razem, gdy aplikacja jest odwoływana w kodzie. Aby dodać nową aplikację, zawsze będziemy edytować setting.py w drugim katalogu utworzona aplikacja, wymieniona w StartProject, dalej aplikacji. Używając nano,

nano app/settings.py
W ustawieniach znajdź zainstalowane_apps i oddziel [] na 3 linie. Za pomocą czterech przestrzeni na pustej linii środkowej dodaj „Podaj” lub nazwę swojej aplikacji. Ta sekcja Settings.py powinna wyglądać:

INSTALLED_APPS = [
    'feed',
]
Zanim zapomniemy, sprawdźmy, że Django działa. Korzystając z poleceń Python Manage.py Runserver 0.0.0.0:8000, możemy uruchomić serwer, a następnie nawigować w przeglądarce internetowej na komputerze, uruchamiając kod do http: // localHost: 8000 i zobacz przykładową stronę (to działa!) Wyjdź serwer z Control C, tak samo jak każde inne polecenie. Teraz zacznijmy pisać jakiś kod Pythona. Django ma trzy główne komponenty, wszystkie z nich są całkowicie uruchomione kodem. Komponenty nazywane są modelem, widokiem i szablonem, a każdy z nich jest odpowiednio na wyższym i niższym poziomie przed dostarczaniem strony internetowej. Model to kod, który przechowuje informacje w bazie danych do pobierania, sortowania i renderowania. Widok decyduje, w jaki sposób model jest renderowany, manipulowany i modyfikowany, prawie każdy widok będzie bezpośrednio użyć modelu. Szablon jest kodem HTML z dodatkowymi dzwonkami i gwizdkami o nazwie Język szablonu. Szablon jest renderowany przez widok, w którym jest wypełniony kodem Pythona iKontekst, taki jak modele i informacje (ciągami i liczb całkowitych) z widoku. Django ma również inne komponenty, w tym między innymi: Ustawienia, które konfigurują aplikację podczas dyskusji. URL, które są wzorami, które użytkownik podąża, aby uzyskać dostęp do określonych części aplikacji internetowej. Formularze, które określają, w jaki sposób informacje wysyłane do serwera są obsługiwane i renderowane do bazy danych, a także do użytkownika. Są to podstawa informacji przetwarzania po stronie serwera i mogą akceptować dowolny rodzaj informacji, które przechowuje komputer, w szczególności struny tekstowe, liczby i prawdziwe/fałszywe boolean (zwykle pola wyboru). Szablony, które są kodem i szablonem HTML oraz mostkiem luki między Python i HTML, co oznacza, że ​​informacje Python mogą być obsługiwane jako kod HTML, do którego każdy może uzyskać dostęp i może zabezpieczyć witrynę z ograniczonym dostępem, jednocześnie udostępniając kod Python do sieci i przydatne do różnych celów na zdalnym urządzeniu, które nieEED, aby być w pobliżu serwera. Pliki statyczne, które zwykle są JavaScript i jego biblioteki, które serwer obsługuje i są połączone z szablonem. Pliki multimedialne, które serwer obsługuje lub są hostowane zewnętrznie, lub po prostu zapisane na serwerze przed przetworzeniem i opublikowaniem na innym serwerze (wiadro) w celu hostingu. Oprogramowanie pośrednie, które są elementami kodu, które są uruchamiane w tym samym czasie, co każdy widok i są uważane za „uwzględnione” w widoku. Procesory kontekstowe, które przetwarzają kontekst każdego widoku i są używane do dodania dodatkowego kontekstu. Testy, które potwierdzają, że użytkownik lub żądanie przekazuje określone wymagania przed renderowaniem widoku. Konsumenci, którzy decydują o tym, w jaki sposób WebSockets radzą sobie i reagują na komunikację. Administrator, który służy do rejestrowania modeli, aby można je było szczegółowo manipulować na stronie administratora Django, gdzie bazę danych może być administrowana za pośrednictwem interfejsu graficznego. Seler, który definiuje zadania asynchroniczne części kodu django, mogą rozpocząćNning przed natychmiastowym przejściem do następnego zadania lub wiersza kodu. Django może mieć wiele innych komponentów, które szczegółowo omówimy tutaj. Istnieje wiele sposobów, aby Django był bardziej funkcjonalny, dodając WebSockets, które są szybkimi, usprawnionymi kanałami komunikacyjnymi, selerem, które wykonują zadania asynchroniczne i wiele innych oprogramowania do rozszerzenia Django, szczególnie w funkcjach widoku, gdzie większość z funkcji, gdzie większość z funkcji, gdzie większość z funkcji widoku, gdzie większość z funkcji widoku, gdzie większość kod jest wykonywany. Funkcje widoku są kluczowe, ponieważ zwykle deklarują każdy element kodu specyficzny dla określonego wzoru adresu URL lub sekcji serwera. Najpierw zbadajmy funkcje widoku. Funkcje widoku zaczynają się od importu oznaczającego kod, który będzie używany w widoku i są zdefiniowane przy użyciu regularnych definicji lub klas funkcji. Najprostsze poglądy są zdefiniowane przez definicję funkcji def i zwracają HTTPRESPONE z podstawowym szablonem. Zacznijmy od zdefiniowania podstawowego poglądu, aby zwrócić tekst „Hello World”. Pamiętaj, że za każdym razem, gdy dodaszPo stwierdzeniu takim jak def, jeśli, podczas gdy, dla itp., Musisz dodać 4 przestrzenie dla każdej z predyskalowych definicji, które chcesz zastosować do swojej funkcji. Wkrótce wejdziemy w to, co każdy z nich oznacza. Z katalogu naszej witryny edytuj plik Feed/Views.py za pomocą Nano i dodaj następujące wiersze na koniec

from django.http import HttpResponse

def hello(request):
    return HttpResponse('hello world')
HTTPResponse Django odpowiada ciągem tekstowym, oznaczonym otwieraniem i zamykaniem ”. Za każdym razem, gdy przekazujesz informacje do funkcji lub klasy, na przykład żądanie lub ciąg, musisz użyć nawiasu (otwieranie i zamykanie). To nie wszystko, co musimy jeszcze zobaczyć. Oczywiście nie powiedzieliśmy serwera, gdzie jest dokładnie widok, nadal musimy zdefiniować ścieżkę, za pomocą której widok powinien renderować. Zacznijmy od zdefiniowania podstawowej ścieżki w app/urls.py, a później przejdziemy do grup ścieżek. W app/urls.py dodaj wiersz po instrukcjach importu po rozpoczęciu importu, który właśnie utworzyliśmy.

from feed import views as feed_views
Teraz zdefiniujmy wzór widoku. Wzorce widoku mają trzy komponenty, komponent ścieżki, który mówi serwerowi, gdzie widok istnieje na serwerze (ścieżka URL, którą użytkownik wpisuje na pasku nawigacji, aby wprowadzić stronę internetową), komponent widoku, w którym widok jest określony, oraz a Przyjazna nazwa widoku, dzięki czemu jest łatwy do odzyskania wzoru podczas pracy z szablonem, zwłaszcza, że ​​nazwa można go zmienić i zaktualizować, jeśli to konieczne, aby zrobić miejsce na inny widok lub przyjąć bardziej logiczną nazwę. Sensowne jest robienie rzeczy w ten sposób i być elastycznym, ponieważ baza kodowa będzie ciągle zmieniającym się środowiskiem, które wymaga elastyczności i improwizacji, aby być cennym i łatwym w obsłudze. Oto, jak będzie wyglądał twój widok, możesz to dodać do urlpatterns = [sekcja app/urls.py. Wzór widoku jest zdefiniowany z trzema opisanymi powyżej komponentami i funkcją zwaną ścieżką. Twoje wzorce adresów URL są listą, więc zawsze kończ każdy element w nichz przecinkiem, ponieważ to oddziela każdy z nich. Każdy element powinien również trafić na nową linię, ponownie z czterema przestrzeniami przed nią, tak jak aplikacja w Settings.py. Zdefiniujemy pierwszy element widoku z funkcją pustego ciągu, aby utworzyć widok działający w katalogu głównym serwera WWW. Twoje adresy URL.py powinno teraz wyglądać

from feed import views as feed_views

urlpatterns = [
    path('', feed_views.hello, name='hello'),
]
Jest to podstawa do tworzenia strony internetowej z Django, która jest całkowicie statyczna. Aby stworzyć bardziej dynamiczną stronę internetową, na której możemy rozpocząć buforowanie informacji, takich jak obrazy, filmy, audio i wiele innych, będziemy musieli użyć modeli, które zbadamy następne. Na razie sprawdźmy nasz kod i uruchommy serwer. Aby sprawdzić kod błędów, uruchom:

python manage.py check
Jeśli istnieją jakieś komunikaty o błędach, powinieneś dokładnie przejrzeć zmiany wprowadzone w aplikacji i sprawdzić, czy jest coś, co należy naprawić, na przykład obce lub pozbawione miejsca, dodatkowy znak, nieostronny ciąg, dowolne literówki, dowolne przypadkowo usunięty charakter lub cokolwiek innego. Czytając komunikat o błędzie (jeśli go masz), powinieneś być w stanie zobaczyć ścieżkę do utworzonego lub edytowanego pliku wraz z numerem linii, więc spójrz na ten plik i wiersz i sprawdź, czy możesz naprawić coś, co tam jest . Jeśli naprawiłeś problem, uruchom powyższe polecenie ponownie. Kiedy oprogramowanie jest gotowe do uruchomienia i działa, zobaczysz wyjście „Kontrola systemu zidentyfikowana bez problemów”. Teraz jesteś gotowy. Uruchom serwer z:

python manage.py runserver 0.0.0.0:8000
Teraz otwórz przeglądarkę internetową i przejdź do http: // localhost: 8000. Powinieneś zobaczyć tekst zwrócony w nawiasie i cytatach funkcji HTTPRESPONE w swoim zdaniu. To tylko podstawowy przykład, ale jeśli dotarłeś tak daleko, rozumiesz podstawy pracy Linux, Bash, Python i Django. Zagłębiajmy się w modelowanie bazy danych i zbadajmy moc klasy Python w przechowywaniu informacji. Następnie zaczniemy chwycić HTML i CSS, zanim uczynimy naszą witrynę w pełni wyróżnioną, elastyczną i bezpieczną za pomocą JavaScript i Machine Learning. Zajęcia są przechowywane w modelach. Syp. Za pomocą nano, edytuj app/modele.py i dodaj nową klasę. Klasa jest zdefiniowana w definicji klasy i jest przekazywana nadklasą, od której dziedziczy, w tym przypadku modele.Model. Nazwa klasy następuje po definicji klasy, a po definicji klasy A: (Colon) jest używana, zanim atrybuty i definicje funkcji powiązane z klasą zostaną oznaczone poniżej. Nasza klasaPotrzebuje identyfikatora, którego możemy użyć, aby go odzyskać i utrzymać wyjątkowe, a także potrzebuje pola tekstowego do przechowywania niektórych informacji. Później możemy dodać znacznik czasu, pliki, booleans (prawdziwe lub fałszywe definicje, które mogą pomóc naszemu kodowi podejmować decyzje dotyczące tego, co zrobić z modelem, i może być używany do jego sortowania), instancję do powiązania modelu z zalogowanym użytkownikiem na serwer i więcej. Rozpakujmy kod

from django.db import models # Import używany do definiowania naszej klasy i jej atrybutów

class Post(models.Model): # Definicja samej klasy
    id = models.AutoField(primary_key=True) # Identyfikator naszego modelu, automatycznie wygenerowany klucz, który pozwoli nam zapytać o model, zachować wyjątkowy i jest przydatny, gdy musimy wchodzić w interakcje z modelem po jego utworzeniu.
    text = models.TextField(default='') # Atrybut naszych klas przechowuje w tym przypadku tekst, domyślnie do pustego ciągu.
Zamknij i zapisz plik tak jak wcześniej, aby zakończyć. Istnieje wiele innych dziedzin i opcji, które zbadamy, kiedy aktualizujemy tę klasę w miarę ewolucji naszej aplikacji, ale jest to podstawowa potrzeby tworzenia aplikacji do opublikowania tekstu. Jednak ten model nie będzie działał sam. Jak opisano wcześniej, będziemy potrzebować niestandardowego widoku i niestandardowego wzoru URL, aby ten model działał, a także będziemy potrzebować formularza wraz z szablonem. Najpierw zbadajmy formularz. Aby zdefiniować formularz, edytuj app/forms.py z nano i dodaj następujące wiersze. Będziemy potrzebować dwóch importów, naszej klasy formularzy, a także modelu, który stworzyliśmy (Feed.models.post), definicja klasy podobnej do modelu, oraz pola wraz z podklasą o nazwie Meta, która zdefiniuje model, który formularz oddziałuje z. Formularz może również mieć funkcję inicjalizacyjną, która ustawia ją na podstawie informacji w żądaniu, modelu lub w inny sposób, zbadamy to później. Formularze modelu są bardzo przydatne, ponieważ mogą tworzyć model lub edytować model,Więc użyjemy ich dla obu. Zdefiniujmy jeden w formacie

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',)
To są podstawy tego, jak wygląda forma i model. Ten formularz modelu może być używany do tworzenia instancji lub edytowania postu, zmieniając zawarty tekst. Następnie spojrzymy na zintegrowanie tego formularza z widokiem. Najpierw spraw, aby migracje i migrację bazy danych, aby nasz kod mógł oddziaływać z modelem podczas jej działania. Aby to zrobić, uruchom następujące polecenia:

python manage.py makemigrations
python manage.py migrate
Wykonanie zajmie to minutę, ale kiedy to zrobi, pozwoli ci uzyskać dostęp do modelu w widokach, oprogramowaniu pośredniego lub gdziekolwiek indziej w oprogramowaniu. Kontynuujmy widok, w którym możemy zobaczyć nasz model. Edytuj Feed/Views.py i dodaj następujący kod, jak wspomniano. Nie musisz niczego dodawać po znaku #, ten kod to komentarze, które służą do oznaczania informacji o kodzie. Zaczniemy od zaimportowania naszego modelu w widokach i dodania go do kontekstu, w którym możemy renderować go w szablonie jako lista wyświetlania. Następnie dodamy szablon, w którym możemy renderować formularz i model z przyciskiem, aby utworzyć nowy obiekt na podstawie modelu i opublikować go na serwerze. To brzmi skomplikowane, więc zróbmy to krok po kroku. Zanim zakończymy widok, utwórzmy szablon, który po prostu renderuje model i upewnij się, że możemy go zobaczyć, tworząc nowy post w skorupce. Oto jak powinien wyglądać ten pogląd:

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

def feed(request):
    posts = Post.objects.all() # Zapytaj wszystkie posty w bazie danych
    return render(request, 'feed/feed.html', {
        'posts': posts,
    })
Wszystko to wygląda dość prosto, dopóki nie dojdziemy do dna. Render, wartość zwrócona przez funkcję zamiast w odpowiedzi HTTP, takiej jak poprzedni przykład, zawsze przyjmuje żądanie jako pierwsze wejście, akceptuje kontekst (w tym przypadku słupki w bazie danych), które można teraz renderować w szablonie i zwraca szablon zdefiniowany w funkcji. Szablon będzie dokumentem HTML z odrobiną języka o nazwie Jinja2, który przekazuje informacje Pythona w HTML. Aby rozpocząć tworzenie szablonów, zrób dwa katalogi w kanale.

mkdir feed/templates
mkdir feed/templates/feed
Następnie edytuj szablon w powyższym katalogu, pasze/szablony/paszę i dodaj kod dla tego przykładu. Spójrzmy na szablon tego przykładu.
 
<!doctype HTML>
<html>
<body>
<legend>Feed</legend>
<hr>
{% for post in posts %}
<p>{{ post.text }}</p>
{% endfor %}
</body>
</html>
 
To bardzo prosty szablon. Definiuje otwieranie i zamykanie tagów HTML, znacznik typu dokumentu, tag nadwozia z tytułem legendy, znacznik przerwy, który dodaje małą linię na ekranie, oraz pętla dla każdego postu na liście postów jako akapitu w szablon. To wszystko, czego potrzeba, aby renderować posty, ale w bazie danych nie ma jeszcze żadnych. Stwórzmy trochę z powłoką. Możemy uruchomić skorupę z zarządzaniem.py

python manage.py shell
Teraz zaimportujmy nasz model post

from feed.models import Post
Następnie utworzymy prosty post z ciągiem i wyjdziemy z powłoki. Ciąg może być wszystkim, o ile jest to prawidłowy tekst.

Post.objects.create(text='hello world')
exit()
Na koniec będziemy musieli dodać wzór adresu URL do naszego kanału. Ponieważ nasza aplikacja do kanału będzie korzystać z wielu adresów URL i chcemy, aby rozmiary plików były małe, utwórzmy lokalny adres URL.py w naszej aplikacji kanałowej, która wygląda tak:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.feed, name='feed'),
]
Będziemy również musieli edytować adres URL.py w aplikacji podstawowej, jakkolwiek postanowiliśmy to nazwać, był to pierwszy katalog, który stworzyliśmy. Edytuj app/app.py i dodaj następujące do wzorów adresów URL

from django.urls import include # na górze

urlpatterns = [
    # ... poprzedni kod tutaj
    path('feed/', include(('feed.urls'), namespace='feed')),
]
Teraz, kiedy uruchamiamy serwer z Python Manage.py Runserver, zobaczymy stronę, którą utworzyliśmy, ponieważ mamy model, widok i szablon, a także wzór adresu URL, wraz z elementami w bazie danych. Następnie zaimplementujmy formularz, który stworzyliśmy i zacznij tworzyć własne posty. Ale zanim napiszemy zbyt dużo kodu, wykonajmy kopię zapasową za pomocą skryptu, który napisaliśmy wcześniej, tworzenie kopii zapasowych. Uruchom ten skrypt w powłoce, poczekaj kilka chwil, a cały kod zostanie poparty do naszego repozytorium Git.

backup
Wdrożenie formularza jest stosunkowo proste. Zaimportujemy nasz formularz, dodamy obsługę żądania postu do widoku i zapiszemy post w bazie danych przed przekierowaniem do tego samego widoku. Możemy użyć funkcji przekierowania, którą już zaimportowaliśmy, a inna funkcja nazywała się odwrotną, aby uzyskać adres URL dla wzoru widoku. Zapytamy o to za pomocą ciągu „Feed: Feed”, ponieważ przestrzeń nazw zawodowego wzoru to pasek, a widok nazywany jest również paszem.

from feed.forms import PostForm

def feed(request):
    posts = Post.objects.all() # Zapytaj wszystkie posty w bazie danych
    if request.method == 'POST': # Obsługuj żądanie pocztów
        form = PostForm(request.POST) # Utwórz instancję formularza i zapisz dane
        if form.is_valid(): # Potwierdzić formularz
            form.save() # Zapisz nowy obiekt
        return redirect(reverse('feed:feed')) # Przekieruj do tego samego adresu URL z żądaniem GET
    return render(request, 'feed/feed.html', {
        'form': PostForm(), # Pamiętaj, aby przekazać formularz do kontekstu, abyśmy mogli go renderować.
        'posts': posts,
    })
Teraz będziemy musieli zaktualizować szablon, aby uwzględnić nowy formularz. Możemy to zrobić za pomocą
Tag w HTML i renderowanie formularza w szablonie HTML za pomocą przycisku przesyłania. Będziemy również potrzebować tokena CSRF, tokena, który zapobiega publikowaniu stron zewnętrznych do formularza bez uprzedniego ładowania strony.
 
<!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>
 
Rozbijmy to. Istnieje nowa klasa formularza, token, sam formularz i przycisk Przesyłania. Całkiem proste, ale kiedy patrzymy na to, możemy chcieć sprawić, by wyglądało to lepiej. Działa, możemy publikować nowe posty z formularzem i są one zapisane w bazie danych. Dzieje się tutaj kilka rzeczy. Używamy tagów HTML, aby oświadczyć, że dokument jest dokumentem HTML, używamy znacznika szablonu ({ %… %}), aby renderować token dla formularza, a drugi, {{…}} do renderowania formularza. Mamy również pętlę renderowania tekstu za pomocą znaczników blokowych i znacznika szablonu. Tagi blokowe są naprawdę ważne, ponieważ możemy zdefiniować, w jaki sposób sekcje szablonu są z nimi renderowane, a znaczniki szablonów są podstawą tego, jak umieszczamy zmienne w naszym kodzie. Teraz musimy sprawić, by nasza aplikacja wyglądała lepiej, ponieważ na razie wygląda naprawdę podstawowo. Możemy to zrobić, używając CSS, one lub w klasach związanych z każdym obiektem w dokumencie. CSS jest naprawdę fajny, ponieważ mówi wszystko na stronie, jak powinno wyglądaći może sprawić, że wygląda naprawdę dobrze. Istnieje kilka bibliotek, które mogą to zrobić, ale mój osobisty przejdź do bootstrap. Bootstrap można pobrać z ich strony internetowej,Getbootstrap.com/. Tam naciśnij przycisk, aby odczytać dokumenty instalacyjne, i skopiuj kod z sekcji Aluxing za pośrednictwem CDN. Będziesz potrzebował tego kodu u góry dokumentu HTML, w znaczniku o nazwie Head. Przejdźmy też i utwórzmy szablon podstawowy, abyśmy nie musieli odtwarzać tych linków w każdym szablonie. Zrób nowy katalog zwany szablonami z szablonami MKDIR, a następnie edytuj szablony/base.html. Powinno to wyglądać:
 
<!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>
 
Pamiętaj, aby skopiować pliki CSS i JavaScript,. Wróćmy teraz do powłoki bash i uruchommy szybkie polecenie. Pamiętaj, jeśli kiedykolwiek potrzebujesz uzyskać dostęp do środowiska wirtualnego, wpisz źródło Venv/Bin/Aktywuj. Pozwoli ci to instalować pakiety Python lokalnie w sposób, który pozwala Django uzyskać do nich dostęp. Aby zapewnić nasze formularze generowane przez klasy Bootstrap Django, użyjemy pakietu Python o nazwie Crispy Forms. Możemy to pobrać za pomocą następującego polecenia

pip install django-crispy-forms
Po zainstalowaniu dodaj go do settings.py

INSTALLED_APPS = [
    # … Poprzedni kod tutaj
    'crispy_forms',
]
Teraz, w naszym szablonie kanału, możemy usunąć niektóre rzeczy. Usuńmy początek i koniec dokumentu i zastąp go dziedzictwem z naszego szablonu podstawowego, za pomocą rozszerza i definicji bloku. Ponadto dodamy filtr szablonu import z ładowaniem i filtr szablonu do formularza. Na koniec dodajmy klasę bootstrap do przycisku na formularzu, aby wyglądał bardziej jak przycisk. To powinno wyglądać tak:
 
{% 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 %}
 
Piękny! To już sporo kodu. Następnie powinniśmy to przetestować i upewnić się, że możemy zobaczyć, że wszystko wygląda ładnie, a także upewnij się, że wszystko działa poprawnie. Uruchom serwer zgodnie z poprzednimi instrukcjami i upewnij się, że strona wygląda i działa dobrze. Świetna robota! Jesteś gotowy przejść do następnego kroku, w którym dodamy funkcję logowania użytkowników za pomocą podobnych adresów URL, formularzy, widoków i szablonów. Podstawowy szablon jest ważny i będziemy go nadal modyfikować i wprowadzać zmiany w razie potrzeby, ale na razie skupmy się na zwiększeniu bezpieczeństwa naszej witryny, umożliwiając użytkownikom zalogowanie się za pomocą nazwy użytkownika i kodu pasów, a ostatecznie jeszcze ważniejszych informacji, które, że informacja, która jest Pomoże utrzymać bezpieczną aplikację, a własne konto dostępne tylko przez Ciebie. Aby to zrobić, będziemy musieli użyć modelu użytkownika wbudowanego w Django. Model użytkownika to model bazy danych, podobnie jak nasz post, który można renderować, aby zalogować użytkownika do witryny. W przyszłości, zanim wdrożymy witrynę w Internecie, będziemyRozszerz ten model o przypisane mu inne modele i zbuduj dodatkowe środki bezpieczeństwa dla logowania odpornego na phishing. Zaczniemy od użycia wbudowanych formularzy logowania, które zapewnia Django. Najpierw utwórzmy nową aplikację, której użyjemy do renderowania szablonów i widoków dla podstawowej strony logowania. Utworzymy także inne aplikacje, aby reprezentować ciągłe wyzwania logowania w celu zabezpieczenia aplikacji, w tym pincode, rozpoznawania twarzy, komunikacji w pobliżu pola, urządzeń zewnętrznych, uwierzytelniania wielowokadresowego i rozpoznawania odcisków palców. Rozmawialiśmy już o założeniu aplikacji. Z naszego katalogu, wewnątrz środowiska wirtualnego, przejdź zarząd

python manage.py startapp users
Teraz powinniśmy mieć katalog nowej aplikacji. Zacznijmy od utworzenia widoku w tym katalogu, który odpowiada loginowi użytkownika. Django ma wbudowane widoki loginów użytkowników, ale nie będą dla nas odpowiednie, ponieważ potrzebujemy niestandardowego widoku, który najlepiej jest wykonany z definicją. W tym widoku zaczniemy od sprawdzania żądania postu, przejdź do żądania. Post do loginoru zaimportowanego z Django, uwierzytelnianie konta użytkownika i zaloguj się użytkownik przed przekierowaniem ich do naszej aplikacji kanałowej. W użytkownikach/widokach dodaj następujący kod

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'] # Uzyskaj nazwę użytkownika i hasło z żądania pocztowego
        password = request.POST['password'] # Uwierzytelnij użytkownika
        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()})
To wszystko, czego potrzebujesz do podstawowego widoku logowania. Teraz utwórzmy formularz widoku, rozszerzając szablon podstawowy. Zaczniemy od utworzenia nowego katalogu szablonów w folderze użytkowników.

mkdir users/templates
mkdir users/templates/users
Teraz powinniśmy być w stanie edytować użytkowników/szablony/Users/login.html. Gdy jesteśmy przy tym, utworzymy szablon, który umożliwia również zarejestrowanie się użytkownika.

nano users/templates/users/login.html
Teraz w szablonie,
 
{% 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 %}
 
To są podstawy szablonu logowania. To naprawdę jak drugi szablon w strukturze, ale wygląda trochę inaczej, gdy jest renderowany. Możemy skopiować ten kod, aby zbudować kolejny bardzo podobny szablon o nazwie Register.html, w którym zmienimy sformułowanie i użyjemy nowego formularza, który budujemy. Zróbmy najpierw szablon. Edytuj użytkowników/szablony/Users/Register.html i dodaj następujący kod:
 
{% 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 %}
 
Teraz zbudujmy formularz rejestracji użytkowników i zwróćmy się do widoków, zanim uaktualnimy loginy naszych użytkowników za pomocą modelu. Na początek ten formularz będzie na początek, ale w przyszłości uwzględnimy więcej szczegółów i funkcji bezpieczeństwa, takich jak umowy i captcha. Edytuj formularze za pomocą nano Users/Forms.py i dodaj następujący kod.

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']
Mamy więc inną formę, która działa dość prosto. Jest to formularz rejestru użytkownika z nazwą użytkownika, e -mailem i hasłem, a także pole potwierdzają hasło. Zauważ, że ten formularz nie rozszerza zwykłej klasy. Jedno pole jest zdefiniowane tak samo, a meta klasy definiuje model, który formularz odpowiada reszcie informacji, które zostaną zapisane do formularza. Większość z nich istnieje już w wbudowanych tworzeniu użytkowników Django, więc wykorzystamy to jako podstawę klasy (przekazaną w nawiasach). Następnie zbadamy widok, aby zarejestrować użytkownika, teraz, gdy mamy formularz i szablon. To jest modele, podobnie jak ten w nowym widoku postu. Edytuj użytkowników/views.py i dodaj następujący kod:

# … Import
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})
To wszystko, czego potrzebujemy, aby zarejestrować użytkownika, ale powinniśmy mieć więcej informacji. Chcemy wiedzieć, kiedy użytkownik zarejestrował się, o której godzinie był ostatni na stronie, niektóre informacje o nich, takie jak biografia, strefa czasowa itp. Będziemy również musieli zaktualizować nasz model paszowy, opublikować, aby uwzględnić użytkownika Model i atrybut postów każdemu użytkownikowi. Aby to zrobić, zaktualizujemy modele.py w obu aplikacjach. Zacznijmy od edytowania modelu paszowego. Teraz powinno wyglądać tak:

from django.db import models # … Kwoty
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') # Dodaj tę linię
    text = models.TextField(default='')
Zwróć uwagę na drugą linię dodaną do pliku. Jest to klucz obcy, który przypisuje każdy post pojedynczego użytkownika na post, dzięki czemu możemy upewnić się, że zapisujemy posty na zasadzie użytkownika-użytkownika i nie można wykonać postu bez przypisywania go użytkownikowi. Definiujemy ten obcy klucz z reprezentowaną przez niego klasą, usuń argument, aby upewnić się, że posty są usunięte z użytkownikami, zerowe i puste argumenty, aby upewnić się, że możemy usunąć użytkownika w razie potrzeby i pomieścić brak użytkownika na postach utworzone i powiązana nazwa, której możemy użyć w celu odwołania się do obiektów postu, które utworzy użytkownik. Ta powiązana nazwa, w przeciwieństwie do Post.Author, autor postu, daje nam użytkownika, który sam opublikował post. Możemy teraz uzyskać posty, które uruchomił użytkownik, uruchamiając User.posts.all () lub autor.posts.all (). Teraz uczyńmy nasze loginy bardziej odporne. Możemy już uczynić naszą witrynę znacznie mniej podatną na phishing, po prostu ograniczając liczbę razy, kiedy pozwolimy zalogować się dostrona, to jest dość łatwe. Zacznijmy również przechowywać informacje o każdym użytkowniku wcześniej, gdy nadal rozwijamy naszą aplikację. Edycja użytkowników/modele.py, dodaj następujące

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='')
Zauważ, że ten model jest dość podobny do modelu post. Mamy dodatkowy import, stref czasowy, który pozwoli nam ustawić wartości domyślne na polach DATETIME, a także mamy charakterystyczny i tekstowy pole, takie jak post. Korzystanie ze wszystkich tych znaczników czasu pomaga nam zabezpieczyć witrynę i zrozumieć jej użycie, a pola tekstowe pozwalają nam informować o każdym użytkowniku lub autorze na stronie internetowej. OneToonefield powinien być jedynym niewielkim rozważaniem, zachowuje się dokładnie tak samo jak przedwcześnie, ale tylko jeden na kolejny model. W ten sposób użytkownik ma tylko jeden profil, podczas gdy może mieć wiele postów. Teraz poprawmy nasze logowanie i zarejestrujmy widoki, aby uwzględnić profil. Najpierw edytuj użytkowników/views.py i skup się na widoku rejestru:

# … Kwoty
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) # Pamiętaj, aby dodać ten wiersz, aby utworzyć profil dla użytkownika
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
To po prostu tworzy profil dla użytkownika, bez wypełniania żadnej informacji. Teraz chcemy upewnić się, że konta użytkownika nie można zalogować się zbyt często, a przynajmniej hasła nie można wypróbować zbyt często, więc zaktualizujmy widok logowania.

# … Kwoty
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(): # Zauważ, że teraz sprawdzamy, czy użytkownik może się zalogować
            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: # Jeśli login nie powiódł się,
            messages.warning(request, 'Username or password incorrect. Please try again.')
            user = User.objects.filter(username=username).first() # To jest część, w której aktualizujemy profil użytkowników
            if user: 
                profile = user.profile
                profile.can_login = timezone.now() + datetime.timedelta(seconds=15) # Więc nie mogą się ponownie zalogować przez kilka sekund
                profile.save()
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
Jest to podstawowa podstawowa bezpieczeństwa. Upewnij się, że strona nie jest podatna na kogoś po prostu wypróbowującą każdą możliwą kombinację haseł, a nawet kilku z nich jednocześnie. Nie będzie to frustrujące dla zwykłego użytkownika, który zna swój kod i po prostu loguje się na kilku urządzeniach, ale będzie trzymał wiele robotów phishingowych poza aplikacją. Zauważ, że dodaliśmy instrukcję IF ze zmienną, can_login, to powinien być czas w przeszłości, i zaktualizować ją przy każdym nieudanym logowaniu przy użyciu tej samej nazwy użytkownika. W ten sposób złośliwy użytkownik nie będzie w stanie odgadnąć hasła tak szybko. Liczba sekund w DateTime.timedelta () również może zostać zaktualizowana, a strona internetowa będzie bardziej odporna, ale nieco mniej użyteczna, a więcej sekund. Polecam 15 na początek. Pamiętaj, że zbudowaliśmy skrypt zapasowy, aby zapisać naszą pracę, więc przejdźmy do przodu i cofnijmy to, co mamy do tej pory, aby upewnić się, że wszystko zapisano. Uruchom polecenie:

sudo backup
Po raz kolejny zaoszczędzi to jak dotąd twoją pracę. Polecam uruchamianie częstych kopii zapasowych, aby zapisać swoją pracę, a możesz nawet automatycznie uruchomić zadanie tworzenia kopii zapasowych. Możesz to zrobić za pomocą narzędzia Unix o nazwie Cron. Aby aktywować to narzędzie, uruchom następujące polecenie i wprowadź hasło:

sudo crontab -e
Jeśli nie wybierzesz jeszcze opcji 1 dla Nano, edytor tekstu, który już powinieneś się zapoznać, i przewiń na dole pliku za pomocą klawiszy strzałek. Dodaj następujący wiersz:

0 * * * * sudo backup
Cron wykorzystuje format minuty, godzinę, dzień miesiąca, miesiąca, dzień tygodnia, gdzie * lub liczba reprezentuje, kiedy uruchomić polecenie. Używając 0 za minutę i * przez resztę opcji, możemy uruchomić polecenie w pierwszej minucie każdej godziny na początku minuty. To pozwala nam automatycznie tworzyć kopię zapasową kodu. Wszystkie zadania Cron po wykonaniu z sudo działają jako root, więc nie będziemy musieli pisać hasła co godzinę. Aby ułatwić tworzenie kopii zapasowych naszego kodu bez użycia hasła, wyłączmy hasło dla naszego polecenia tworzenia kopii zapasowych. Zrobimy to, wykonując następujące polecenie i wprowadzając hasło:

sudo visudo
Teraz przewińmy na dno pliku i dodajmy inną linię:

ALL ALL=NOPASSWD: /bin/backup
To pozwala nam uruchomić polecenie „tworzenie kopii zapasowych” jako każdego użytkownika, bez hasła. Format tego jest łatwy, po prostu poprzedzaj wiersz „all all = nopasswd:/bin/” i zakończ polecenie, na przykład/bin/kopia zapasowa, która istnieje w/usr/bin/. Teraz zacznijmy pracować z e -mailem. E -mail jest naprawdę ważny dla stron internetowych, ponieważ jest to sposób na utrzymanie witryny bezpieczniejszej, weryfikacja użytkowników to prawdziwi ludzie, a nawet produkty lub usługi rynkowe dla klientów. Wiele osób, które odwiedzają Internet codziennie, i otrzymują wszelkiego rodzaju e -mail marketingowy o produktach i usługach, które są zainteresowane. Istnieje kilka opcji, jeśli chodzi o włączenie wiadomości e -mail na stronie internetowej Django i możesz wybrać Niezależnie od tego, co będzie dla Ciebie najlepiej. Po pierwsze, możesz zapłacić za usługę e -mail, która umożliwi wysyłanie wiadomości e -mail z domeny i wymaga minimalnego kodu. Istnieje wiele usług, które to oferują, takich jak Google Workspace, SendInblue, Mailgun i wiele innych. W przeciwnym razie dobrze się budujeszTwoja własna usługa e -mail na serwerze od zera. Polecam tę opcję, mimo że jest to więcej kodu i może wymagać specjalnego hostingu. Najprawdopodobniej nie będziesz w stanie uruchomić serwera poczty z komputera domowego, więc przejdźmy dalej i zbadajmy konfigurację i kod, aby wysłać wiadomość e -mail, zanim uruchomimy serwer w chmurze i utworzyć własny serwer pocztowy. Najpierw edytuj Setting.py z następującymi

nano app/settings.py
Gdzie aplikacja jest nazwą aplikacji utworzonej z StartApp. Dodaj następujące wiersze:

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)
Zmień je, gdy będziesz gotowy do wdrożenia aplikacji, ponownie to ponownie. Ustawienie e -mail_address powinno być e -mailem, z którego chcesz wysłać, a hasło (e -mail_host_password) powinno być ustawione na hasło generowane dla serwera. Ładuję hasło z pliku konfiguracyjnego, aby trzymać go z dala od kodu za pomocą następującej logiki, powyżej tych wierszy w setting.py:

import os
import json
with open('/etc/config.json') as config_file:
    config = json.load(config_file)
Następnie skonfigurowałem plik JSON z Config in /etc/config.json za pomocą Nano w następujący sposób. Aby edytować plik:

sudo nano /etc/config.json
Dodaj następujące wiersze:

{
	“EMAIL_HOST_PASSWORD”: “<some password here>”
}
Będziemy nadal edytować plik konfiguracji i dodać wszystkie hasła i klawisze, których użyjemy w aplikacji. Na razie szybko sprawdźmy, jak wysłać e -mail za pomocą Pythona. Najpierw utwórzmy szablon wiadomości e -mail weryfikacji, którą możemy wysłać do naszych użytkowników, i umieść go w katalogu szablonów użytkowników. Ten szablon zostanie napisany w 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>
 
Ten e -mail jest dość prosty. Wymaga kontekstu użytkownika, podstawowego adresu URL witryny oraz identyfikatora użytkownika i tokena używanego do weryfikacji e -maila użytkownika. Pamiętaj, aby zdefiniować podstawowy adres URL w setting.py, zanim napiszemy kod Pythona, aby renderować szablon. Śmiało i dodaj następujące wiersze do app/settings.py, blisko początku.

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

BASE_URL = PROTOCOL + '://' + DOMAIN
W końcu, gdy Twoja witryna jest gotowa do Internetu i wdrożyłeś ją, będziesz chciał zdefiniować swoją domenę jako nazwę domeny, którą kupujesz, aby reprezentować witrynę. Jest to nazwa, którą wpiszesz w pasku NAV w celu uzyskania dostępu do Twojej witryny. Na razie możesz zostawić domenę pustą lub użyć symboli zastępczego. Będziesz także chciał zmienić nazwę Site_name na nazwę, którą chcesz podać swoją witrynę wyboru. Zanim wyślemy e -mail, utwórzmy generator tokenów, abyśmy mogli mieć token aktywacyjny konta, który nigdy nie wygasa. Możemy to zrobić, budując i importując token aktywacyjny konta, który wygląda jak następujące. Edytuj plik:

nano users/tokens.py
Dodaj następujący kod:

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()
Ten podstawowy generator tokenów generuje token, który możemy wysłać użytkownik w adresie URL, a użytkownik może użyć do weryfikacji ich wiadomości e -mail i aktywowania konta. Następnie zobaczmy, jak wysłać wiadomość e -mail. Za pomocą Nano, edytuj użytkowników/e -mail.py.

nano users/email.py
Wysyłanie weryfikacji e -mail HTML będzie wyglądał tak:

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)
To jest dość proste. Importujemy funkcje, które musimy wysłać wiadomość e -mail, renderować wiadomość e -mail z szablonami i naszymi ustawieniami, a następnie definiujemy wiadomość e -mail według nazwy szablonu i wysyłamy ją do użytkownika za pomocą funkcji. Zauważysz, że nie zdefiniowaliśmy funkcji, aby wysłać pocztę, wysłać_html_email, więc napiszmy to poniżej kodu, który już dodaliśmy do users/e -mail.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()
Jest to nieco bardziej złożone i nie jesteśmy jeszcze gotowi uruchomić cały ten kod. Zauważ, że definiujemy UNSUB_LINK, link, którego użytkownik może użyć do rezygnacji z subskrypcji z naszych e -maili. Jest to ważne, ponieważ użytkownicy będą musieli zrezygnować z naszych e -maili, chyba że chcą je zobaczyć w dowolnym momencie. Dodajemy również alternatywę tekstową do naszej wiadomości, która jest komunikatem HTML pozbawionym tagów HTML. Na koniec sprawdzamy, czy wiadomość e -mail wysłana, a jeśli nie, oznaczamy profil użytkownika, że ​​ich e -mail nie jest ważny. Wróćmy do modeli użytkowników, abyśmy mogli to wszystko zadziałało. Musimy zdefiniować funkcję, aby wygenerować link do rezygnacji z subskrypcji, i zdefiniować pole boolean, aby oznaczyć, że e -mail użytkownika jest nieprawidłowy. Najpierw dodaj następujący import na górze użytkowników/modeli.py

nano users/models.py

# …
from django.core.signing import TimestampSigner, BadSignature, SignatureExpired
from django.urls import reverse
Następnie dodajmy funkcje do modelu użytkownika, aby zrobić token i sprawdź token używany do aktywacji wiadomości e -mail, a także pole, aby zapisać, czy użytkownik z powodzeniem otrzymuje pocztę. W Users/Models.py Ponownie dodaj następujący kod do końca modelu (kod zintegrowany)

# …
    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) # Ważne przez 30 dni
        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,})
Jest to dość proste, używamy znacznika czasu, który jest podstawowym narzędziem kryptograficznym, aby utworzyć token, który wygasa po określonym czasie, a także używamy innej funkcji, aby sprawdzić, czy jest ważna. Używamy tych tokenów dwa razy, raz, aby zweryfikować wiadomość e -mail i raz na link do rezygnacji z subskrypcji. Teraz, gdy je mamy, ostatnią pracą, którą będziemy musieli wykonać, jest widoki. W ramach użytkowników/views.py dodajmy widoki, aby zweryfikować adres e -mail i zrezygnować z subskrypcji.

nano users/views.py
Najpierw dodaj następujące import. Wrzuciłem kilka dodatkowych, więc nie będziemy musieli ponownie importować więcej przedmiotów później.

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 # Pamiętaj, aby zaimportować funkcję wysyłania e -maila weryfikacji
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
Być może masz już niektóre z tych importów, ale powtórzenie ich nie zaszkodzi. Będziesz musiał zaimportować funkcję wysyłania e -maila weryfikacyjnego, a także konta_aktywacji_token od użytkowników.Tokens, między innymi import. Teraz, na dole pliku, dodaj następujący kod:

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)):
        # Odejść je
        profile = user.profile
        profile.subscribed = False
        profile.save()
        return render(request, 'users/unsubscribe.html')
    # W przeciwnym razie przekieruj na stronę logowania
    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()
# sendWelcomeEMail (żądanie, użytkownik)
        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})
To dużo kodu. Rozbijmy to. Pierwsza funkcja, czysta i prosta, rezygnuje z użytkownika z listy mailingowej. Druga funkcja aktywuje ich e -mail, a zauważysz, że dodałem komentowaną funkcję, SendWelcomeEutilail. Zapraszamy do użycia szablonu e -maila i definicji funkcji, aby wysłać wiadomość e -mail, po prostu jeszcze tego nie zrobiłem. Ostatnia funkcja, którą rzuciłem, jest ważna, ponieważ e -maile aktywacyjne wygasa. Dlatego będziemy musieli ponownie wysłać wiadomość e -mail z aktywacją. Możemy użyć do tego podstawowego formularza i wywołać funkcję, aby wysłać wiadomość e -mail weryfikacyjną. Zanim to zrobimy, upewnijmy się, że zostanie wysłany w pierwszej kolejności, dodając wywołanie funkcji do widoku rejestru. Dodaj ten wiersz tuż przed przekierowaniem w widoku rejestru, rejestr def, w użytkownikach/views.py.

nano users/views.py

# … (Po) rejestr def (żądanie):
            send_verification_email(user)
# … (Przed) przekierować (
Nie musisz dodawać pierwszych i ostatnich wierszy w tym fragmencie kodu, po prostu upewnij się, że widok rejestru wysyła e -mail weryfikacyjny do użytkownika. Powinno to wyglądać:

# … Kwoty
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) # Pamiętaj, aby dodać tę linię!
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
Teraz będziemy musieli dodać formularz, aby ponownie wysłać wiadomość e -mail aktywacyjną. W użytkownikach/forms.py dodaj następujący formularz:

# … (Kwoty)
class ResendActivationEmailForm(forms.Form):
    email = forms.EmailField(required=True)
Będziemy również potrzebować szablonu odpowiadającego niniejszego formularza aktywacji e -maila. Dodajmy ten szablon. Edytuj plik:

nano users/templates/users/resend_activation.html
Następnie dodaj następujący kod do pliku.

{% 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 %}
Uff, to dużo! Teraz, kiedy wdrażamy kod na naszym serwerze, będziemy mogli wysłać e -mail HTML i aktywować konta użytkowników za pomocą e -maila. Możemy również chcieć wysłać prosty e -mail powitalny, więc zobaczmy, jak to zrobić. Wróć do użytkowników/e -mail.py, dodaj następujący kod:

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)
Będziemy również potrzebować szablonu, aby przekazać wszystkie te informacje. Na mojej stronie szablon wygląda jak poniżej, ale możesz go sformatować, jak chcesz.
 
<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>
 
Pamiętaj, że nie mamy tagów zamykających ani tagów HTML, ponieważ dodajemy je, gdy dodamy link do rezygnacji z subskrypcji HTML. Są to ważne, ale nie chcemy ich definiować dwa razy. Więc co dalej? Przeszliśmy długą drogę. Naprawdę powinniśmy być gotowi wdrożyć witrynę na serwerze. Możemy dodać dekoratora @login_required i zapewnić bezpieczeństwo naszych widoków, przyjmować rejestracja użytkowników, wysłać dostosowane wiadomości e -mail i informacje o pamięci podręcznej, co jest podstawą tego, co musi zrobić witryna, aby zachować aktualność. Dodamy kilka bardziej przydatnych funkcji, a następnie zbudujemy podstawę do wdrożenia naszego kodu na zdalnym serwerze, konfigurowanie serwera poczty, konfiguracji domeny i filtry, aby nasza witryna była bezpieczna i odpowiednia. Potrzebujemy również widoku resetowania hasła, więc dodajmy to naprawdę szybko. Widok resetowania hasła Django jest rozbity w niektórych funkcjach, ale przyjrzymy się, jak napisać własny widok, szablon e -mail, formularze i wzorce URL. Oto, jak wygląda widok, w użytkownikach/views.py

# ... kwoty
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)
Ten formularz jest wbudowany w Django, ale będziemy potrzebować szablonu, aby potwierdzić resetowanie hasła, użytkowników/szablonów/użytkowników/hasło_set_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 %}
 
Mamy również szablon wysyłania wiadomości e -mail z resetowaniem hasła z prostym formularzem, w użytkownikach/szablonach/użytkownikach/hasło_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 %}
 
Szablon samego e -maila jest prosty, jest to podstawowy plik HTML, który renderuje link do zresetowania hasła, w użytkownikach/szablonach/Users/Password_Reset_Email.html. Django automatycznie zinterpretuje ten plik.
 
<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>
 
Potrzebujemy również dwóch kolejnych szablonów. Pierwszym jest potwierdzenie, że wiadomość e -mail została wysłana. Widoki na te są już w Django, więc musimy tylko zająć się nimi w URL.py. Ten szablon znajduje się w użytkownikach/szablonach/Users/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 %}
 
I na koniec, aby potwierdzić, że resetowanie hasła jest kompletne, użytkownicy/szablony/Użytkownicy/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 %}
 
Teraz potrzebujemy wzorców adresów URL dla tych widoków. W użytkownikach/urls.py dodaj następujące wzorce URL:

urlpatterns = [
    # ... poprzednie adresy URL tutaj
    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'),
]
Cztery szablony, to dużo! Ale teraz możemy być w stanie zresetować hasło użytkownika w dowolnym momencie, wszystko z przeglądarki internetowej. Rozumiem, że to dużo kodu. Jeśli wydaje się to trochę nad twoją głową, to jest w porządku. Poprawicie się, twoje zrozumienie poprawi się i wkrótce staniesz się znacznie bardziej kompetentny w kodzie. Jeśli jesteś całkowicie zagubiony, polecam powrót do tego oprogramowania po pracy nad pracą nad samozadowoleniem, naucz się kodować kurs online. Zwykle można je zacząć i poprowadzą Cię przez wszystko, czego potrzebujesz, aby odnieść sukces po powrocie do tego projektu. Jeśli czujesz, że jesteś gotowy, przeczytaj dalej, następnie omówimy wdrażanie kodu na zdalnym serwerze i konfigurację serwera poczty, a także automatyzację wdrożenia za pomocą BASH, aby zawsze możesz skonfigurować nowy projekt z kilka prostych poleceń. Ostatnią rzeczą, którą musimy zrobić przed wdrożeniem na zdalnym serwerze, jest sprawianie, że nasza witryna była nieco bezpieczniejsza. BędzieszZauważ, że widok logowania przyjmuje tylko nazwę użytkownika i hasło, a nie ma uwierzytelniania wielu czynników ani jednorazowego kodu. Jest to łatwa poprawka, a dzięki temu samemu kodowi możemy sprawić, by nasza strona wysyłała wiadomości tekstowe, a nawet reagować na wiadomości tekstowe wysyłane na serwer. Na początek wrócimy do modeli użytkowników i dodamy sygnatariusz znaczników czasu, który będzie reprezentował każdy login. Dodamy również unikalny, obrotowy identyfikator do modelu użytkownika, który zostanie użyty do dodania dodatkowego bezpieczeństwa do naszego logowania. Edycja modeli użytkowników, użytkowników/modeli.py, dodaj następujące

from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
# Pamiętaj, aby zaimportować UUID, sygnatariusz znacznika czasu i generator adresu URL (odwrotne)
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='')
    # Dodaj ten kod tutaj
    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)

    # I dodaj tę funkcję
    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) # Ważne przez 3 minuty
        except (BadSignature, SignatureExpired):
            return False
        return True
Upewnij się, że użytkownicy/modele.py wygląda tak, oprócz komentarzy (kod w wierszach z #). Rozbijając to, to proste. Mamy kilka importów, znacznik czasu, który jest użytecznością kryptograficzną, która może wygenerować bezpieczny kod i zweryfikować go, aby upewnić się, że jest on ważny, został użyty tylko raz i nie starszy niż określona liczba sekund. Używamy również UUID, który jest unikalnym identyfikatorem, który identyfikuje naszego użytkownika w podpisywaniu tokena, oraz w adresie URL, w którym token jest wysyłany do użytkownika. Użyjemy tej podstawowej kryptografii, aby zbudować widok uwierzytelniania dwóch czynników. Zanim zrobimy cokolwiek innego, uruchommy migracje, aby nasze modele użytkowników były aktualizowane. W katalogu z zarządzaniem.py uruchom następujące polecenia, aby wykonać i wypełnić migrację.

source venv/bin/activate
python manage.py makemigrations && python manage.py migrate
Jest to ważne, ponieważ za każdym razem, gdy wprowadzamy zmiany w modelach, będziemy musieli utworzyć tabele i zaktualizować bazę danych o wartości domyślne, zanim będziemy mogli skorzystać z modeli. Następnie zaimprowizujmy nasz pogląd logowania, aby przekierować wtórny widok uwierzytelnienia. W użytkownikach/views.py usuń funkcję logowania i przekieruj do adresu URL, który właśnie wygenerowaliśmy w modelach użytkowników.

# … Kwoty

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(): # Zauważ, że teraz sprawdzamy, czy użytkownik może się zalogować
            # Usuń funkcję auth_login, która tu była
            messages.success(request, 'Your password was accepted. Please continue.')
            if user.profile.mfa_enabled:
                return redirect(user.profile.create_auth_url()) # Zwróć uwagę na nowy adres URL
            else: # Jeśli użytkownik nie korzysta z uwierzytelniania wieloczynnikowego, po prostu zaloguj się.
                auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
                return redirect('feed:feed')
        else: # Jeśli login nie powiódł się,
            messages.warning(request, 'Username or password incorrect. Please try again.')
            user = User.objects.filter(username=username).first() # To jest część, w której aktualizujemy profil użytkowników
            if user: 
                profile = user.profile
                profile.can_login = timezone.now() + datetime.timedelta(seconds=15) # Więc nie mogą się ponownie zalogować przez kilka sekund
                profile.save()
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
Jest to więc dość proste, mamy teraz sposób na przekierowanie do widoku uwierzytelniania dwóch czynników podczas jego tworzenia. Mamy również awarię na wypadek, gdyby użytkownik nie dodał numeru telefonu. Dodamy podstawowy widok, aby wkrótce dodać numer telefonu i wkrótce zaloguj się za pomocą wiadomości tekstowej. Po pierwsze, potrzebujemy łatwego sposobu wysyłania wiadomości tekstowej z naszego kodu. Aby to zrobić, możemy wybierać spośród wielu interfejsów API, ale moim zdaniem najłatwiejszym jest Twilio. Oferują również dobre ceny za mniejsze projekty, a także zniżki masowe. Utwórz konto na twilio.com, wypełnij kilka szczegółów na temat swojego projektu, kup numer telefonu i skopiuj klucze API do swoich ustawień. Następnie dodaj ten kod w nowym pliku, Users/sma.py.

nano users/sms.py

# Zaimportuj wszystkie niezbędne pakiety
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

# Ten kod wysyła tekst z 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())

# Funkcja pomocnika, aby uzyskać liczbę z tak wieloma cyframi
def get_num_length(num, length):
    n = ''
    for x in range(length):
        n = n + str(num)
    return int(n)

# Wyślij tekst, aby zweryfikować użytkownika
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)))

# Wyślij użytkownika dowolny tekst z tą funkcją
def send_user_text(user, text):
    send_text(user.profile.phone_number, text)

# Sprawdź kod za pomocą tej funkcji
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

# Sprawdź czas
def check_verification_time(user):
    result = user.profile.mfa_code_expires > timezone.now()
    return result
Pamiętaj, aby odpowiednio zmienić swoje ustawienia, dodając te linie za pomocą klawiszy:

# Pamiętaj, aby skopiować je z pulpitu nawigacyjnego 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 # Liczba minut strona TFA jest aktywna po instancji
Po pierwsze, będziemy potrzebować formularzy dla naszych dwóch współczynników uwierzytelniania. Edycja użytkowników/forms.py, dodaj następujący kod.

# … Kwoty
from django import forms

# Formularz do wprowadzenia naszego numeru telefonu
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

# Formularz uwierzytelniania
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.'
    }
Następnie utwórzmy widoki w użytkownikach/views.py

# … Kwoty
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})
Będziemy również potrzebować szablonów obu tych poglądów. Najpierw dodajmy szablon MFA.

nano users/templates/users/mfa.html
Dodaj ten kod HTML do szablonu
 
{% 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 %}
 
To jest dość wyjaśniające. Formularz wysyła kod lub pusty kod, a zauważysz w widoku, wysyłamy kod, jeśli otrzymamy pusty kod. Następnie mamy tylko dwa przyciski przesyłania i w ten sposób możemy wysłać kod z dowolnym przyciskiem. Następnie dodamy prosty formularz, aby dodać numer telefonu.

nano users/templates/users/mfa_onboarding.html
Dodaj następujące 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 %}
 
Ten formularz jest o wiele prostszy, po prostu renderuje formularz numeru, który utworzyliśmy i pozwala użytkownikowi dodać numer telefonu. To wygląda naprawdę dobrze! Dopóki wszystko jest odpowiednio skonfigurowane, powinniśmy być w stanie wysyłać wiadomości i zalogować użytkownika za pomocą numeru telefonu, gdy tylko dodamy wzorce URL. Ostatnią rzeczą, którą musimy skonfigurować, jest widok profilu, abyśmy mogli upewnić się, że użytkownik może zmienić numer telefonu bez zalogowania się. W końcu będziemy chcieli dodać opcję „Zatrzymaj się”, aby użytkownik mógł napisać SMS -a „Zatrzymaj się”, aby zrezygnować z przyszłych wiadomości tekstowych. Dodajmy widok profilu do użytkowników/Views.py. Ten widok zaktualizuje biografię użytkownika, e -mail, nazwę użytkownika i numer telefonu, a także pozwoli nam włączyć uwierzytelnianie wieloletnie. Najpierw będziemy potrzebować dwóch kolejnych formularzy w użytkownikach/forms.py

# ... kwoty
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']
Następnie możemy utworzyć widok, aby użyć obu tych formularzy. Edytuj użytkowników/views.py i dodaj widok.

# Dodaj te import
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)
Potrzebujemy również szablonu tego widoku.

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 %}
 
Zauważysz, że jest to dość prosta formularz, ale ma w niej trochę JavaScript, który automatycznie publikuje zawartość formularza podczas ich aktualizacji. Jest to przydatne, więc możesz dokonywać edycji bez konieczności przesyłania przesyłania za każdym razem. Następnie potrzebujemy adresów URL reprezentujących wszystkie te poglądy w wzorach URL użytkowników. Edytuj użytkowników/urls.py i dodaj ten kod:

# … Poprzedni kod, import
from django.urls import path
from . import views

app_name='users'

urlpatterns = [
# … Wzory adresów URL, do których wcześniej wprowadziliśmy, dodaj kolejne trzy wiersze
    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'),
]
Teraz jest dobry moment na przetestowanie naszego projektu. Ale najpierw uruchommy kolejną kopię zapasową.

backup
I uruchom serwer. Zanim wdrożymy na serwerze Linux, warto włączyć uwierzytelnianie dwóch czynników na koncie. Zrobimy to na adres URL profilu,/Użytkownicy/Profil/i zaznaczamy pole, aby włączyć uwierzytelnianie po wprowadzeniu naszego numeru telefonu, a następnie przesłaniu formularza.

python manage.py runserver localhost:8000
Odwiedź stronę internetową, przechodząc do przeglądarki internetowej, używam Google Chrome w tym przykładzie i wpisując adres URL https: // localhost: 8000/konta/profilu// W razie potrzeby będziesz mógł zalogować się i włączyć uwierzytelnianie dwóch czynników. Ten projekt potrzebuje serwera do uruchomienia, aby mógł naprawdę wysłać pocztę. Ale najpierw potrzebujemy sposobu, aby zobaczyć błędy. Zauważysz, że jeśli uruchomisz serwer w trybie debugowania, z settings.debug równą true, serwer automatycznie wyświetla błędy. Aby pokazać błędy bez korzystania z trybu debugowania, który jest niebezpieczny na serwerze produkcyjnym, powinniśmy dodać do niego widok. Najważniejsze błędy, które musimy obsłużyć, to: Błąd 500 - Problem z naszym kodem Błąd 404 - Nie znaleziono strony (zepsuty adres URL) Błąd 403 - Błąd odmowy uprawnień Dodajmy nową aplikację do obsługi tych błędów, zwanych błędami.

python manage.py startapp errors
Dodaj to do settings.py tak jak wcześniej, w ustawieniu instalowanym_apps i zacznij od dodania odniesień do niektórych widoków w app/urls.py, gdzie aplikacja jest nazwą twojego projektu Django.

handler404 = 'errors.views.handler404'
handler500 = 'errors.views.handler500'
handler403 = 'errors.views.handler403'
To wszystko, czego potrzebujemy oprócz widoków błędów, szablonów i odrobiny oprogramowania pośredniego. Zdefiniujmy je jako:

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

# Utwórz swoje widoki tutaj.
@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.'})
Następnie zdefiniujmy oprogramowanie pośrednie, aby obsłużyć te błędy. Zrobimy to, najpierw dodając do Middleware_classes w Setting.py, z nazwą naszego oprogramowania pośredniego.

MIDDLEWARE_CLASSES = [
    # ... poprzednie oprogramowanie pośrednie
    'errors.middleware.ExceptionVerboseMiddleware,
]
Następnie dodajmy oprogramowanie pośrednie.

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.')
Dodajemy funkcję, aby uzyskać bieżący wyjątek za pomocą lokalnego gwintowania, który pomaga nam prześledzić wszelkie błędy w naszym kodzie. Jeśli chodzi o szablony, potrzebujemy tylko jednego, ponieważ dynamicznie definiujemy tytuł w widoku. Szablon musi po prostu renderować tytuł i „śledzenie”, nasza śledzenie błędów z kontekstu.

nano errors/templates/errors/error.html
 
{% extends 'base.html' %}
{% block content %}
<h1>{{ pagetitle }}</h1>
<p>{{ trace }}</p>
{% endblock %}
 
To jest nasz najprostszy szablon, ale tak łatwo jest zobaczyć błędy w naszym projekcie. Następnie wyłączmy debugowanie w ustawieniach.

nano app/settings.py
Znajdź ten wiersz, w którym jest ustawiony na true, i zmień ją na false

DEBUG = False
Śmiało teraz i wykonaj kopię zapasową aplikacji. Jesteśmy gotowi wdrożyć na zdalnym serwerze Linux i stamtąd dodawać funkcje.

sudo backup
Zanim opublikujemy ten kod na serwerze, powinniśmy rozważyć, że mogą wystąpić pewne problemy z kodem. W zależności od sprawy strony, które akceptują opublikowane w nich informacje, będą miały problemy z publikowaniem spamu i trudnościami w usunięciu spamu. Nie powinno się to zdarzyć od razu, ale jeśli tak się dzieje, później zbadamy, jak automatycznie modować spam na stronie i utrudnić robotom dostęp do witryny, wraz z dezaktywacją kont użytkowników i zweryfikowania tożsamości użytkownika za pomocą użytkownika za pomocą użytkownika z skan ich identyfikatora lub biometrycznego skanowania, jak odcisk palca lub rozpoznawanie twarzy. Patrząc na przykład uwierzytelniania wielu czynników, który zbadaliśmy w produkcji, rzeczy mogą być inaczej. Zwróć uwagę, w jaki sposób ograniczamy logowanie i wygasamy tokeny. Jeśli roboty uzyskują dostęp do witryny, uwierzytelnianie dwóch czynników może być trudniejsze, ponieważ mogą one wprowadzać kody w tym samym czasie. Aby to walczyć, użyjmy modelu w modelach użytkowników, deklarując, w jaki sposób wchodzimy w interakcję z witryną, gdy jesteśmyUwierzytelnianie przy użyciu uwierzytelniania wielu czynników za pomocą numeru telefonu. Dodamy również opcję uwierzytelniania się za pomocą wiadomości e -mail. Zacznij od edytowania modeli użytkowników z

nano users/models.py
Tak powinien wyglądać model, który dodajemy. Nie potrzebujemy żadnych metod, po prostu zmiennych do przechowywania identyfikatora, użytkownika, znacznika czasu, wygaśnięcia, długości i prób w stosunku do dowolnego uwierzytelniania wielu czynników (kod taki jak 123456 wysłany na telefon lub e -mail).

# Podstawowy token używany do logowania się na stronie internetowej
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)
Dodajmy również przywilej naszemu użytkownikowi, a na razie ustawimy go ręcznie, zanim ostatecznie automatycznie migrujemy do rekrutacji uprzywilejowanych użytkowników. W modelach użytkowników dodaj ten wiersz w profilu:

    vendor = models.BooleanField(default=False)
Podobnie jak w przypadku wszelkich zmian w bazie danych, musimy dokonywać migracji i migracji bazy danych za każdym razem, gdy edytujemy plik Models.py w Django. Pamiętaj, aby to zrobić, najpierw używamy źródła (jeśli nie było już używane od momentu otwartego terminala), a następnie Python Manage.py, aby migracje i migracja.

cd project-directory-you-named # (W razie potrzeby)
source venv/bin/activate
python manage.py makemigrations && python manage.py migrate
Na razie możesz zaciągnąć wszelkie konta, które utworzyłeś jako dostawcy za pomocą powłoki.

python manage.py shell
from users.models import Profile
p = Profile.objects.get(user__username='Charlotte')
p.vendor = True
p.save()
exit()
Teraz ewoluujmy nasz pogląd na uwierzytelnianie wielu czynników, aby użyć tego tokena. Najpierw musimy zmodyfikować nasze media pomocnicze MFA. Używając 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

# Uwierzytelnij użytkownika za pomocą numeru e -mail lub numeru telefonu
def mfa(request, username, usertoken):
    token = MFAToken.objects.filter(uid=username, expires__gt=timezone.now() + datetime.timedelta(seconds=30)).order_by('-timestamp').last() # Odfiltruj token według wartości przekazanej w adresie 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)) # Jeśli ta sesja nie została utworzona, utwórz ją
    user = User.objects.filter(id=token.user.id).first() # Zdobądź użytkownika z tokena
    if not user and request.user.is_authenticated: return redirect(reverse('feed:home')) # Jeśli są już uwierzytelnieni, zaloguj się
    if not user: raise PermissionDenied() # Zaprzecz, jeśli nie znaleziono użytkownika
    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): # Sprawdź token Auth
        auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Zaloguj użytkownika, jeśli nie są jeszcze zalogowani
        user.profile.mfa_expires = timezone.now() + datetime.timedelta(minutes=settings.LOGIN_VALID_MINUTES) # Ustaw wygaśnięcie ich uwierzytelniania wielu czynników
        user.profile.save()
        return HttpResponseRedirect(next if next != '' else reverse('landing:landing')) # Przekieruj użytkownika na następną stronę
    if not user.profile.mfa_enabled: # Sprawdź, czy MFA jest włączona
        if not check_verification_time(user, token): # Sprawdź czas
            user.profile.mfa_enabled = False # Wyczyść numer telefonu
            user.profile.enable_two_factor_authentication = True # Włącz Mfa
            user.profile.phone_number = '+1' # Wyłącz numer telefonu
            user.profile.save() # Zapisz profil
            auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Zaloguj użytkownika, jeśli jego MSZ nie jest włączony
            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): # Jeśli żądanie jest żądaniem pocztowym
        form = TfaForm(request.POST) # Utworzyć formularz
        code = str(form.data.get('code', None)) # Zdobądź kod
        if code and code != '' and code != None: # Upewnij się, że nie jest pusty
            token_validated = user.profile.check_auth_token(usertoken) # Sprawdź token Auth
            p = user.profile
            is_verified = check_verification_code(user, token, code) # Sprawdź kod
            p.mfa_authenticated = is_verified
            if token_validated: # Jeśli wszystko
                if is_verified: # Jest w porządku
                    user.profile.mfa_enabled = True # Włącz MFA (jeśli jeszcze nie włączony)
                    user.profile.save()
                    auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Zaloguj użytkownika
                    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(): # Zbuduj QueryString dla następnego parametru (jeśli istnieje)
                        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) # Przeadresować
                    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: # Jeśli token był nieważny
                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: # Gdyby było zbyt wiele prób
                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): # Wyślij wiadomość e -mail (lub SMS)
                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('/'))
    # Renderować formularz (dla żądań GET)
    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'})
Gdy dodajemy ten kod, upewnij się, że zaimportować funkcję, aby wysłać wiadomość e -mail. Na górze pliku użytkownik wyświetla (z innymi importami), dodaj

from .mfa import send_verification_email as send_mfa_verification_email
Teraz musimy napisać tę funkcję, zanim z tego zadziała. Powinno to przedłużyć naszą funkcję wysyłania e -maila i po prostu wysłać wiadomość e -mail do użytkownika z kodem weryfikacji.

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))
Więc to wszystko działa świetnie, teraz mamy system uwierzytelniania wielu czynników, który zależy numer telefonu lub e -mail do zalogowania się. Ale potrzebujemy również sposobu na usunięcie, a przynajmniej ukryj użytkowników, którzy nie współpracują z naszymi warunkami. Mogą to być spamery, roboty lub każdy, kto nie znaczy dobrze dla naszej pracy. Spójrz na widok na monitorowanie użytkowników na mojej stronie:

# kwoty
from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import user_passes_test
from .tests import is_superuser_or_vendor # Będziemy musieli utworzyć ten test

@login_required
@user_passes_test(is_superuser_or_vendor)
def users(request):
    # Uzyskaj listę użytkowników
    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', { # Zwracaj użytkowników w szablonie
        'title': 'All Accounts',
        'users': User.objects.all(),
        'new_today': new_today,
        'new_this_month': new_this_month,
        'subscribers': subscribers
    })
Zauważ, że ten kod używa testu, będziemy musieli zadeklarować ten test w pliku tests.py i zaimportować go. Edycja użytkowników/tests.py, utwórzmy test.

def is_superuser_or_vendor(user):
    return user.profile.vendor or user.is_superuser
Jest to w połączeniu z szablonem Users/Users.html, który wygląda mniej więcej tak:
 
{% 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 %}
 
Zauważ, że szablon zawiera inny szablon, Users/_User.html. Podczas korzystania z szablonu, który ma subtelną płytę i nie używa Extends, dobrym pomysłem jest dodanie podkreślenia (_) przed nazwą pliku do rozszerzenia, aby rozróżnić szablony. Zauważ, że jest to dużo Jinja, możesz nie mieć zdefiniowania wszystkich tych zmiennych. Ale tak wygląda mój kod.
 
{% 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>
 
Potrzebujemy również kolejnej subtelnej płyty, toggle_active.html. Ten szablon powinien być formą, która pozwala nam przełączać, czy użytkownik jest aktywny.
 
<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>
 
Będziemy również musieli dodać widok, aby przełączyć aktywność użytkownika i odpowiednie wzorce URL. Podczas gdy jesteśmy przy tym, dodajmy widok, aby usunąć użytkownika na wypadek, gdybyśmy tego potrzebujemy.

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


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

class UserDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    model = User
    success_url = '/' # Przekierowanie URL sukcesu
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        return context

    def test_func(self): # Przetestuj, czy użytkownik jest superuser i ma zgodę na usunięcie
        user = self.get_object()
        if self.request.user != user and self.request.user.is_superuser:
            return True
        return False
Chociaż jest to praktyczne w razie potrzeby, usunięcie użytkownika nie powinno być konieczne przez większość czasu, możemy po prostu przełączyć widoczność użytkowników, którzy odwiedzają witrynę, jeśli będziemy musieli je odrzucić. Wzory adresów URL, które dodaliśmy, wyglądają tak. Z nano, edytuj użytkowników/urls.py i dodaj te wiersze:

nano users/urls.py
Linie powinny trafić na listę ścieżek w widokach użytkownika, przed zakończeniem „]”, ale po początku „[”.

# …
    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'),
# …
Teraz pamiętaj, aby utworzyć kopię zapasową witryny, abyś mógł pobrać ją na serwerze WWW, nad którym będziemy kontynuować pracę. Z wiersza poleceń,

sudo backup
Teraz nasza strona jest kopowana. Więc teraz mamy kilka bardziej przydatnych funkcji. Ale co z dużym zdjęciem tutaj? Ten kod nadal nie jest dostępny z Internetu, nie mamy jeszcze serwera poczty i musimy rozwinąć naszą aplikację, aby uwzględnić kompleksowy proces weryfikacji, a także płynne układy, które pomogą nam zbadać witrynę, a także bezpieczne protokoły uwierzytelniania uprzywilejowanych użytkowników . Dostaniemy to wszystko. Najważniejszą rzeczą na razie będzie po prostu wprowadzenie tego kodu online, co możemy zrobić z zaledwie kilkoma wierszami bash na serwerze Ubuntu. Będziesz jednak musiał wypożyczyć serwer do tego, chyba że masz serwer w domu i subskrypcję internetową biznesową, która pozwala otwierać porty. Osobiście uruchamiam moją stronę internetową na HP Z440, który jest zainstalowany w moim mieszkaniu, ale zwykle jest to znacznie tańsze w przypadku podstawowych potrzeb do wypożyczenia wirtualnego prywatnego serwera (VPS). Należy pamiętać, że kod, który teraz uruchomimy, jest stosunkowo cienki, będzie musiał zostać utrzymany i ulepszony, zanim będziemyGotowy do użycia tego, co musimy zbudować produkt. Uważaj, co robisz z Internetem, upewnij się, że jeśli publicznie wdrożysz tę stronę na serwerze Linux, planujesz zablokować niechciane interakcje ze swoją witryną. To prawdopodobnie nie stanowi problemu, ale przyjrzymy się różnorodnym rozwiązaniom, aby to zwalczyć, w tym uczenie maszynowe, sztuczną inteligencję i wizję komputerową. Kiedy staje się problemem, poszukaj dalej w tym tekście, aby uzyskać rozwiązanie. Jeśli chodzi o wynajęcie VPS, można znaleźć wiele miejsc. Google Cloud ma serwery VPS, Ionos, Kamatera, Amazon AWS i więcej dostawców oferuje rozwiązania serwerów w chmurze, które będą odpowiadające naszym potrzebom. Musisz kliknąć ich formularze i wybrać plan, aby rozpocząć. Możesz przejść do planu podstawowego z dowolnym dostawcą, ale upewnij się, że dostawca umożliwia otwieranie portów serwera poczty portowej w celu wysyłania wiadomości e -mail (powinien to być port 587 i port 25), niektórzy dostawcy blokują te porty. So far I have had theEST Doświadczenie z Ionos i Kamatera, oboje pozwolą mi wysłać nieograniczony e -mail, a ich ceny są dość tanie. Połączysz się z nowym serwerem przez protokół o nazwie SSH lub Secure Shell, który umożliwia zdalne połączenie z serwerem dokładnie tak, jak komputer osobisty, z komputera osobistego. Po skonfigurowaniu serwera dostawca hostingów prawdopodobnie poprosi Cię o dodanie klucza SSH, w przeciwnym razie da ci nazwę użytkownika i hasło. Klucz SSH to sposób logowania się na serwerze z wiersza poleceń, aby edytować kod. Użyj poniższych opcji SSH-KeyGen, aby wygenerować SSH

ssh-keygen
Zapisz plik i zastąp go, jeśli potrzebujesz, dobrze jest obrócić klawisze SSH, jeśli jeszcze tego nie zrobiłeś. Teraz możesz użyć następującego polecenia, aby zobaczyć swój klucz SSH. Będziesz chciał skopiować go na swój zdalny serwer, aby użyć go do uwierzytelnienia.

cat ~/.ssh/id_rsa.pub
Jeśli nie byłeś w stanie zobaczyć klawisza SSH podczas pisania tego polecenia (długi ciąg cyfr i liter, zaczynając od „SSH-RSA AAA”), spróbuj wygenerować klucz RSA (są one bezpieczniejsze, więc radzę ich użyć .) Poniższy kod wygeneruje klucz 4096 -bitowy RSA SSH.

ssh-keygen -t rsa -b 4096
Utwórz VPS z Ubuntu, jednak planujesz to zrobić. Po utworzeniu VPS, klikając formularze na stronie internetowej dostawców (kamatera.com, ionos.com lub podobne), będziesz chciał się zalogować. Aby to zrobić, użyj polecenia SSH z adresem IP (adres To wygląda jak xx.xx.xx.xx). Będziesz także musiał być wrażliwy na domyślną nazwę użytkownika na utworzonym serwerze, na przykład Ubuntu.

ssh ubuntu@XX.XX.XX.XX
Możesz zostać poproszony o hasło, jeśli zostaniesz poproszony o hasło, wprowadź je. Nie użyjemy domyślnej nazwy użytkownika, więc zacznijmy od utworzenia nowego użytkownika i dodania klucza SSH do ich konta. Zacznijmy od dodania nowego pliku SSHD_CONFIG, który informuje serwer, jak korzystać z SSH.

nano sshd_config

# Jest to plik konfiguracyjny systemu konfiguracyjnego serwera SSHD.  Widzieć
# SSHD_CONFIG (5) Aby uzyskać więcej informacji.

# Ten SSHD został skompilowany z ścieżką =/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

# Strategia zastosowana do opcji w domyślnym sshd_config dostarczonym z
# OpenSSH to określenie opcji o ich wartości domyślnej, gdzie
# możliwe, ale zostaw je skomentowane.  Niezwykłe opcje zastępują
# Wartość domyślna.

# Port 22
# Adressfamily dowolne
# Adres listy 0.0.0.0
# Posłuchaj adres ::

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

# Szyfry i keying
# Rekeylimit domyślnie Brak

# Wycięcie lasu
# SYSLOGFACILE Auth
# Informacje o logowaniu

# Uwierzytelnianie:

# LogringRAceTime 2M
# Permitrootlogin zakaz słowa
# StrictModes tak
# Maxauthtries 6
# Maxessions 10

PubkeyAuthentication yes

# Spodziewaj się.
AuthorizedKeysFile	.ssh/authorized_keys .ssh/authorized_keys2

# AutoryzowanyPrincipalSfile Brak

# AutoryzowanyKeysComand nikt
# AutoryzowanyKeysComanduser Nikt

# Aby to zadziałało
# HostbasedAuthentication nr
# Zmień na tak, jeśli nie ufasz ~/.ssh/znane_hosts
# HostbaseAuthentication
# IgnororeUser Nownownhosts nr
# Nie czytaj plików ~/.rhosts i ~/.
# Ignorerhosty tak

# Aby wyłączyć tunelowane hasła tekstowe, zmień na NO TUTAJ!
PasswordAuthentication no
# Zezwolenie na słowa nr

# Zmień się na tak, aby włączyć hasła do odpowiedzi na wyzwanie (uważaj na problemy z
# Niektóre moduły i wątki PAM)
KbdInteractiveAuthentication no

# Opcje Kerberos
# Kerberosauthentication nr
# KerberosorlocalPasswd Tak
# KerberosticketCleanup Tak
# Kerberoscted Rod nr

# Opcje GSSAPI
# Gssapiauthentication nr
# Gssapicleanupcredentials tak
# Gssapistrictacceptorcheck tak
# GssapikeyExchange nr

# Ustaw to na „Tak”, aby włączyć uwierzytelnianie PAM, przetwarzanie konta,
# i przetwarzanie sesji. Jeśli jest to włączone, uwierzytelnianie PAM
# być dozwolone poprzez KBDInteractiveAutentication i
# HasłoAuthentication.  W zależności od konfiguracji PAM,
# Uwierzytelnianie PAM za pośrednictwem KBDInteractiveAuthentication może ominąć
# ustawienie „Pertrootlogin bez słowa”.
# Jeśli chcesz, aby konto PAM i kontrole sesji działały bez
# Uwierzytelnianie PAM, a następnie włącz to, ale ustaw hasłoAutentowanie
# i kbdinteractiveAuthentication do „nie”.
UsePAM yes

# Bezpełnienie, tak
# Zezwolenie na rzecz, tak
# Gatewayports nr
X11Forwarding yes
# X11Displayoffset 10
# X11uselocalhost Tak
# Permittty tak
PrintMotd no
# Printlastlog tak
# TCPKEEPALIVE TAK
# Permittuenvironment in
# Opóźniona kompresja
# Interwał klienta 0
# ClientAliveCountMax 3
# Używane w
# Pidfile /run/sshd.pid
# MaxStartups 10: 30: 100
# Pemittunl no
# Chrootdirectory brak
# Dodatek wersji Brak

# Brak domyślnej ścieżki banerowej
Banner /etc/banner

# Pozwól klientowi przejść zmienne lokalne
AcceptEnv LANG LC_*

# Zastąp domyślnie brak podsystemów
Subsystem	sftp	/usr/lib/openssh/sftp-server

# Przykład nadrzędnych ustawień dla użytkownika
# Dopasuj anoncvs użytkownika
# X11 wściekłość nr
# Zezwolenie dla nr
# Zezwalaj na
# Serwer CVS ForceCommand
PermitRootLogin no
Pamiętaj, Ctrl+X i Y, aby zapisać plik. Następnie napiszmy podstawowy skrypt o nazwie inicjaliza (wszystko w domyślnym katalogu domowym naszego użytkownika).

nano initialize
Dodaj te linie do pliku, zastępując with your SSH key you found using cat. (.ssh/id_rsa.pub)

# ! / bin / bash
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
To walk you through this file, let's start line by line. The first line tells the compiler that this is a bash script. Następnie instalujemy zależności, kopiujemy SSHD_CONFIG do poprawnego katalogu, ponowne uruchomienie SSH, generowanie klawiszy SSH dla root, dodawanie „zespołu” użytkownika (możesz wybrać nazwę, którą lubisz, użyj polecenia AddUser z ich nazwą i hasłem wyłączonym dla dla hasła dla osób Teraz). Dodajemy również zespół do grupy Sudo, generujemy ich klucz SSH, dodajemy nasz klucz do autoryzowanych kluczy i ich również oraz drukuje ich klucz. Ten nowy użytkownik będzie sposobem logowania się do witryny. W nowym terminalu śmiało ponownie otwórz serwer.

ssh team@XX.XX.XX.XX
Tym razem nie powinieneś potrzebować hasła, ponieważ masz klucz SSH. Wyłączyliśmy również login z hasłem, aby zapewnić bezpieczeństwo witryny. Teraz ten serwer zaczyna się całkowicie puste, bez żadnych informacji na ten temat. Zacznijmy od klonowania naszego projektu z GIT, abyśmy mogli pobrać go i uruchomić na zdalnym komputerze. Na zdalnym serwerze podłączonym do SSH najpierw wydrukuj klucz SSH:

cat ~/.ssh/id_rsa.pub
Next, paste this key into the git settings like we did before to set up our git repository. Możemy teraz sklonować nasz projekt bezpośrednio do serwera. Upewnij się, że najpierw utworzyłeś kopię zapasową projektu, aby pobrać na serwerze GIT.

git clone git://github.com/you/yourproject.git
Doskonały. Teraz wszystkie pliki są tutaj. Widzimy je z LS

ls
Teraz zacznijmy konfigurować serwer. Najpierw skopiuj swój katalog projektu na prostą, niezapomnianą nazwę, której użyjemy do projektu.

cp -r yourproject whatyoucalledit
Gdzie „WhatyouCalledit” to nowa nazwa twojego projektu. Następnie będziemy musieli zbudować podstawowe narzędzie do skonfigurowania serwera. Zapiszemy to narzędzie i wykorzystamy je w przyszłości. Aby zbudować to narzędzie, utwórzmy binarne użytkownika, aby zdefiniować sposób edycji skryptu. Za pomocą bash, edytuj/usr/bin/ascript

sudo nano /usr/bin/ascript
Pamiętaj, aby używać tam sudo, aby mieć uprawnienia do edycji pliku. W pliku dodaj te wiersze:

# ! / bin / bash
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
Pamiętaj, że ten skrypt przyjmuje argument, nazwę skryptu, jako 1 USD. Najpierw sprawdza, czy plik istnieje, czy w inny sposób go tworzy, dodaje pierwszy wiersz, który deklaruje, że skrypt jest bash, zmienia jego uprawnienia, edytuje i dodaje swoją nazwę do /etc /ascripts, co pozwala nam przechowywać nazwy skryptów my tworzą. Jeśli plik już istnieje, po prostu zmień uprawnienia i edytuj go. Zapisz plik, a następnie zmienimy jego uprawnienia. Dopóki używamy tego skryptu, nie będziemy musieli tego ponownie robić.

sudo chmod a+x /usr/bin/ascript
Doskonały. Teraz utwórzmy skrypt o nazwie Setup. Po pierwsze, nie przytłaczają cię, ale spójrz na to, jak wygląda mój skrypt konfiguracji. Przejdziemy przez to, jak powinien wyglądać ten skrypt w twoim projekcie, nie będziesz potrzebować wszystkiego w moim skrypcie na początek.

# ! / bin / bash
SECONDS=0
PYTHON_VERSION=3.12
echo "femmebabe installer initialized."
# sudo chmod A+x Scripts/Userstetup
# ./scripts/usersetup
# SSH-KEYEN
# Katalog projektu
DIR="/home/team/femmebabe"
USER="team"
# Polecenia dziennika
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
# Zaktualizuj i zainstaluj
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
# Włącz antywirus CLAMAV
echo "Starting antivirus"
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Ustaw nazwę hosta
echo "127.0.0.1 femmebabe" | sudo tee -a /etc/hosts
sudo hostnamectl set-hostname localhost
# Konfiguracja 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;"
# Baza danych konfiguracji kopii zapasowej
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
# Wyłączone ipatables
echo "Configuring firewall"
sudo iptables -P INPUT ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -F
sudo iptables-save
# Zainstaluj 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
# Konfiguracja 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
# Utwórz 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
# Konfiguracja Virtueealenv
cd $DIR
echo "Creating virtual environment"
python -m venv venv
source venv/bin/activate
# Uzyskaj i buduj zależności
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
# Ustaw zasady zapory ogniowej
cd $DIR
# Zainstaluj zależności 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 Instaluj openCV-Python == 4.5.5.64
# PIP Instaluj openCV-Contib-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
# Zainstaluj 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
# Uruchom certbot
sudo certbot --apache --non-interactive --agree-tos --domains femmebabe.com --email jasper.camber.holton@gmail.com
# Załaduj serwer poczty
sudo systemctl restart opendkim postfix dovecot
# Kopiuj certyfikaty
# sudo cp /etc/letscrypt/live/femmebabe.com/privkey.pem privey.pem
# sudo cp /etc/lettesencrypt/live/femmebabe.com/cert.pem cert.pem
# Skrawek
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"
# Ustaw ustawienia użytkownika
sudo gpasswd -a www-data users
# Ustaw uprawnienia
echo "Setting permissions"
sudo chown -R team:users cache/
sudo chmod a+rwx -R cache/
# Zespół sudo chown -r: użytkownicy/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: Użytkownicy 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
# Skopiuj konfigurację i ustaw uprawnienia
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
# Konfiguracja bazy danych
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"
# Wstrzykiwać PAM Config i usuń wadliwą konfigurację SSH
# sudo sed -i '' -e '$ d' /tc/pam.d/sshd
# Sudo sed -i '' -i $ d ' /etc /profil
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
# Skopiuj skrypty kosza i ustaw uprawnienia
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
# Załaduj i włącz usługi
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
# Włącz moduły 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
# Wyłącz domyślną witrynę
sudo a2dissite 000-default
sudo a2dissite 000-default-le-ssl
# Włącz witrynę
sudo a2ensite femmebabe-le-ssl
# Załaduj demona i uruchom ponownie Apache, Postfix i Opendkim
sudo systemctl daemon-reload
sudo systemctl restart apache2
sudo systemctl restart opendkim postfix
sudo systemctl start daphne
# Ustaw uprawnienia
sudo chown -R :www-data /var/www/
sudo chown -R :www-data /var/www/.deepface
# Konfiguracja zamiany
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
# Silnik podpisu inicjowego
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
# Konfiguracja 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
# Pokaż IPv6 i Opendkim do konfiguracji domeny
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}'
# Ukończona konfiguracja
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."
To dużo konfiguracji! Krótko mówiąc, niniejszy kod loguje polecenia, konfiguruje nano i git, kopie pliki, pliki do pobrania i instaluje pakiety Ubuntu apt, zależności Python, konfiguruje postfix, konfiguruje PostgreSQL (serwer bazy danych) i ładuje bazę danych, konfiguruje UFW (nieskomplikowane Firewall), Wyłącza IPTABLE, pobiera antywirus, tworzy katalogi, zależności klonów, instaluje certyfikaty i konfiguruje serwer, instaluje konfigurację, uruchamia i umożliwia Sever, przydziela zamiany, ustawia uprawnienia i drukuje adres IP, IPv6 i klucz OpenDkim. Całkiem proste, ale wygląda na dużo kodu. Nie będziemy tego dużo potrzebować, ponieważ nie mamy zależności, nie używamy selera, selerybeat ani Daphne, ale i tak zainstalujemy niektóre z nich, aby zacząć. Zauważ, że ten kod ma domenę zadeklarowaną kilka razy. Będziemy również musieli kupić nazwę domeny (która jest małą opłatą roczną). Polecam squarespace do zakupu domeny, ich układ jestIntuicyjne i łatwe w użyciu. Możesz kupić dowolną wybraną domenę, ale w tym przykładzie używam domeny femmebabe.com. Po zakupie domeny udaj się do panelu konfiguracji Squarespace DNS i dodaj rekord A wskazujący domenę na serwer według adresu IP. Powinno to wyglądać: @ A xx.xx.xx.xx Z operatorem @ jako hostem, co oznacza wszystkie subdomeny w tej domenie, a domena root będzie przekierować na serwer. Deklaracja należy zadeklarować więcej, ale możemy przejść do nich, gdy będziemy gotowi wysłać pocztę. Pamiętaj, że może to potrwać kilka dni, zanim będziesz w stanie pomyślnie wysłać pocztę z serwera. Propiowanie, które ustawiamy w DNS, zajmie czas na propagowanie. W każdym razie jedynym rekordem, który musimy rozpocząć, jest rekord A. Więc teraz możemy wypełnić poniższy skrypt zgodnie z naszym projektem i uruchomić go. Zacznijmy od mniejszego skryptu konfiguracji, aby po prostu zainstalować to, czego potrzebujemy do podstawowego postępu. Nie będziemy jeszcze używać tak wielu zależności ani postgreSQLup a basic HTTP server and worry about certifying it when that's done. Remember, to get an HTTPS certificate and run the server securely, we will need to buy a domain along with rent a server. Na razie zastąp „Zespół” w tym pliku na nazwę swojego użytkownika „Dir” z katalogiem projektu i podaj e -mail i domenę w tagach <>. Ponadto, zanim uruchomię ten kod, musimy zmienić ustawienia na zaporę zapory obsługującej dostawcę hostingów, jeśli istnieje. Zwykle jest to w zakładce „sieci” twojego dostawcy hostingów lub jeśli jesteś hostingiem, jest to w sekcji „Przekazywanie portów” routera. Jeśli używasz hostingu. Będziesz musiał otworzyć następujące porty w celu odczytu/zapisu. 22 (SSH) 25 (poczta) 587 (mail) 110 (klient pocztowy) 80 (HTTP) 443

# ! / bin / bash
SECONDS=0
PYTHON_VERSION=3.12
echo "femmebabe installer initialized."
DIR="/home/team/<yourproject>"
USER="team"
# Polecenia dziennika
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
# Zaktualizuj i zainstaluj
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
# Włącz antywirus CLAMAV
echo "Starting antivirus"
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Ustaw nazwę hosta
echo "127.0.0.1 femmebabe" | sudo tee -a /etc/hosts
sudo hostnamectl set-hostname femmebabe
# Baza danych konfiguracji kopii zapasowej
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
# Wyłączone ipatables
echo "Configuring firewall"
sudo iptables -P INPUT ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -F
sudo iptables-save
# Konfiguracja Virtueealenv
cd $DIR
echo "Creating virtual environment"
python -m venv venv
source venv/bin/activate
pip3 install -r requirements.txt
# Zainstaluj 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
# Uruchom certbot
sudo certbot --apache --non-interactive --agree-tos --domains femmebabe.com --email <youremail>@gmail.com
# Ustaw ustawienia użytkownika
sudo gpasswd -a www-data users
# Ustaw uprawnienia
echo "Setting permissions"
sudo chown -R team:users cache/
sudo chmod a+rwx -R cache/
# Zespół sudo chown -r: użytkownicy/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 ./
# Załaduj i włącz usługi
echo "Enabling services"
sudo systemctl daemon-reload
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Włącz moduły 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
# Załaduj demona i uruchom ponownie Apache, Postfix i Opendkim
sudo systemctl daemon-reload
sudo systemctl restart apache2
sudo systemctl restart opendkim postfix
# Pokaż IPv6 i Opendkim do konfiguracji domeny
echo "COPY the below information to domain configuration."
hostname -I
ip a | grep inet
ip -6 addr | grep "scope link"
Przed uruchomieniem tego kodu upewnij się, że zakupiona domena jest podłączona do serwera. Aby to zrobić, otwórz terminal na komputerze lokalnym i uruchom to polecenie za pomocą swojej domeny:

ping femmebabe.com # Włóż swoją domenę tutaj, po ping
Jeśli wszystko wygląda dobrze, a serwer wysyła odpowiedzi, jesteśmy gotowi uruchomić skrypt i zainstalować pakiety, a także uruchomić, włączyć i certyfikować nasz serwer Apache. To nie jest cała konfiguracja potrzebna do skonfigurowania postfix, przyjrzymy się tej konfiguracji bardziej później. Na razie uruchom ten kod instalacyjny i zainstalowanie i poświadczenie serwera powinno zająć kilka minut. Ponownie, pamiętaj, aby zastąpić nazwę, e -mail i nazwę domeny w skrypcie zgodnie z zakupioną nazwą. Teraz, gdy serwer jest udostępniany, możesz przejść do adresu URL w dowolnej przeglądarce internetowej i sprawdzić, czy serwer uruchamia HTTPS. Jeśli tak nie jest, spróbuj trochę poczekać, aż rekordy DNS nadrobią zaległości, a następnie uruchom następujące polecenie, aby ponieść certyfikat Certbot:

sudo certbot --apache --non-interactive --agree-tos --domains <domain>.com --email <youremail>@gmail.com
Tak długo, jak poprawnie skonfigurowałeś wszystko, powinieneś mieć dostęp do domyślnej strony Apache, aby wiedzieć, że Twój kod działa i wyświetla stronę internetową na żywo. Następnie edytujmy setting.py, aby zmienić nasz domyślny tryb debugowania na produkcję. Skonfigurujemy również domenę w ustawieniach, a także wewnętrzne IPS.

nano yourproject/settings.py
W ustawieniach zmień/dodaj te linie.

DEBUG = False

# Konfiguracja witryny
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',
]
Teraz będziemy musieli skonfigurować Apache2. Edytujmy plik konfiguracyjny, który wdrożymy w tym wierszu:

sudo nano /etc/apache2/sites-available/femmebabe-le-ssl.conf
Ten plik konfiguracji powinien mieć naszą nazwę domeny oraz nazwę użytkownika i projektu. Używam nazwy domeny femmebabe.com, zespołu nazwy użytkownika i nazwy projektu 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>
Make sure to replace the name of the project, directories, and domain in this example code when configuring your server. Now, we will need to disable the default site. Można to zrobić za pomocą Bash.

sudo a2dissite 000-default-le-ssl
sudo a2dissite 000-default
sudo a2dissite default-ssl
Następnie możemy włączyć domyślną stronę i ponownie załadować Apache2, również za pomocą Bash. Pamiętaj, aby zastąpić femmebabe nazwą zadeklarowanego pliku podczas edytowania w/etc/apache2/witryn-dostępna/.

sudo a2ensite femmebabe-le-ssl
sudo systemctl reload apache2
Wróć do swojej domeny w pasku Nav. Powinieneś zobaczyć stronę skonfigurowaną w przeglądarce internetowej. Gratulacje! Jeśli tego nie widzisz, być może będziesz musiał wprowadzić pewne zmiany. Carefully review the settings in your project, apache configuration, and make sure you don't have any errors, and run the following commands to check the project for errors.

cd projectname
source venv/bin/activate
python manage.py check
Jeśli masz błędy w swoim projekcie Python, prześledź je tam, gdzie są i napraw. Być może nie możesz zobaczyć wszystkich swoich błędów w zależności od tego, gdzie są, więc jeśli masz błąd, który po prostu mówi „wypełnienie nie jest powtórne”, edytuj następujący plik w środowisku wirtualnym, Registry.py, aby ujawnić błąd.

nano venv/lib/python3.12/site-packages/django/apps/registry.py
Przewiń do wiersza 83, gdzie ten błąd wykonawczy jest podniesiony (podnieś runtimeerror („populacja () nie jest ponownie sentrant”)) i dodaj komentarz przed tą linią, a następnie dodaj, z tym samym wgłębieniem, self.app_configs = {}. This looks like this:

            if self.loading:
                # Zapobiegaj połączeniom Reentrant, aby uniknąć uruchamiania AppConfig.Ready ()
                # metody dwa razy.
# Raise RuntimeError („populacja () nie jest powtórna”)
                self.app_configs = {}
            self.loading = True
Następnie możesz ponownie sprawdzić projekt i ujawnić błąd.

python manage.py check
Następnie możesz zobaczyć błąd i naprawić go. Po naprawie i kod kompiluje bez błędów, pamiętaj, aby zmienić plik z powrotem, aby wyglądał tak:

            if self.loading:
                # Zapobiegaj połączeniom Reentrant, aby uniknąć uruchamiania AppConfig.Ready ()
                # metody dwa razy.
                raise RuntimeError("populate() isn't reentrant")
# self.app_configs = {}
            self.loading = True
Pod warunkiem, że serwer jest online, gdy wprowadzamy do niego dalsze zmiany, musimy użyć następującego polecenia, aby ponownie załadować serwer:

sudo systemctl reload apache2
Wspaniały! Ale co z wysłaniem poczty? Aby rozpocząć wysyłanie wiadomości e -mail, najpierw będziemy musieli zaktualizować konfigurację domeny. Powinno to znajdować się w panelu DNS w Squarespace lub dowolnym rejestrowaniu nazwy domeny. Będziemy również musieli zainstalować i dodać konfigurację oraz uruchomić kilka poleceń. Najpierw uzyskajmy adres IPv6 serwera. Następnie otworzymy Twoje DNS i dodamy rekordy. Aby uzyskać adres IPv6 serwera, użyj tego polecenia:

ip -6 addr
Teraz możemy dodać następujące rekordy do ustawień DNS. Moje płyty wyglądają tak. Jednak w przypadku rekordów należy zastąpić adres IP swoim IP (nie 75.147.182.214, to moje). Dodaj także swoją domenę zamiast femmebabe.com, a także adres IPv6 znaleziony z poprzednim poleceniem (nie możesz użyć mojego, Fe80 :: 725a: FFF: FE49: 3E02). Na razie nie martw się o dominę, jest to tworzone, gdy konfigurujemy Postfix, serwer pocztowy z Opendkim i drukuje klucz. Skonfigurujemy to ostatnie. @ A Nie dotyczy 75.147.182.214 @ MX 10 femmebabe.com @ Ptr Nie dotyczy femmebabe.com @ Txt Nie dotyczy Txt @ v = SPF1 MX IP75.147.182.214IP6: Fe80 :: 725a: FFF: FE49: 3E02 ~ All All default._BIMI Txt Nie dotyczy v = bimi1; l = https: //femmebabe.com/media/static/femmebabe.svg _dmarc Txt Nie dotyczy v = dmarc1; p = Brak sendonly._domainkey Txt Nie dotyczyTeraz będziemy musieli dodać trwałą konfigurację dla Postfix. Wszystko, co musimy zrobić, to upewnić się, że zastępujemy nazwę domeny, femmebabe.com, z używaną nazwą domeny. Spójrzmy na wszystkie pliki konfiguracyjne jeden po drugim i zainstaluj je w katalogu o nazwie Config w naszym projekcie, aby zainstalować system operacyjny.

nano config/etc_postfix_main.cf
Dodaj ten tekst do pliku

# Patrz /usr/share/postfix/main.cf.dist, aby uzyskać skomentowaną, pełniejszą wersję


# Debian specyficzny: Określenie nazwy pliku spowoduje pierwszą
# wiersz tego pliku, który ma być używany jako nazwa.  Debian domyślnie
# IS /ETC /MailName.
# miorigin = /etc /MailName

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

# Dołączenie .domain to praca MUA.
append_dot_mydomain = no

# Odkształcić następny wiersz, aby wygenerować ostrzeżenia „opóźnionej poczty”
# Delay_Warning_Time = 4H

readme_directory = no

# Zobacz http://www.postfix.org/compatibility_readme.html - domyślnie na 3.6
# Świeże instalacje.
compatibility_level = 3.6



# Parametry 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

# Konfiguracja miltera
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
Następna konfiguracja!

nano config/etc_postfix_master.cf
Dodaj te linie:

# 
# Plik konfiguracji procesu postfix.  Szczegółowe informacje na temat formatu
# z pliku patrz strona ręczna Master (5) (polecenie: „Man 5 Master” lub
# On-line: http://www.postfix.org/master.5.html).
# 
# Nie zapomnij o wykonaniu „Postfix Reload” po edycji tego pliku.
# 
# ================================================== ========================
# Typ usługi Prywatne bezbolesne Command MAXPROC Wakeup + Args
# (tak) (tak) (nie) (nigdy) (100)
# ================================================== ========================
smtp      inet  n       -       y       -       -       smtpd
# SMTP INET N - Y - 1 PostScreen
# SMTPD PASS - - Y - - SMTPD
# DNSBLog UNIX - - Y - 0 DNSBLog
# TLSproxy Unix - - Y - 0 Tlsproxy
# Wybierz jeden: Włącz przesyłanie tylko dla klientów pętli lub dla każdego klienta.
# 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/Zwrot
# -O smtpd_tls_security_level = szyfrow
# -O smtpd_sasl_auth_enable = tak
# -O smtpd_tls_auth_only = tak
# -O smtpd_reject_unlisted_recipient = no
# -O smtpd_client_restrictions = $ mua_client_restrictions
# -O smtpd_helo_restrictions = $ mua_helo_restrictions
# -O smtpd_sender_restrictions = $ mua_sender_restrictions
# -O smtpd_recipient_trival =
# -O smtpd_relay_restrictions = augt_sasl_authentive, odrzucić
# -O Milter_Macro_daemon_name = pochodzenie
# Wybierz jeden: Włącz SMTPS tylko dla klientów pętli lub dla każdego klienta.
# 127.0.0.1:smtps inet n - y - - smtpd
# SMTPS INET N - Y - - SMTPD
# -O syslog_name = postfix/smtps
# -O SMTPD_TLS_WRAPREMODE = Tak
# -O smtpd_sasl_auth_enable = tak
# -O smtpd_reject_unlisted_recipient = no
# -O smtpd_client_restrictions = $ mua_client_restrictions
# -O smtpd_helo_restrictions = $ mua_helo_restrictions
# -O smtpd_sender_restrictions = $ mua_sender_restrictions
# -O smtpd_recipient_trival =
# -O smtpd_relay_restrictions = augt_sasl_authentive, odrzucić
# -O Milter_Macro_daemon_name = pochodzenie
# 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
# 
# ================================================== ===================
# Interfejsy do oprogramowania bez Postfix. Pamiętaj, aby zbadać instrukcję
# Strony oprogramowania bez Postfix, aby dowiedzieć się, jakie opcje chce.
# 
# Wiele z poniższych usług korzysta z rur postfix (8) dostawy
# agent.  Informacje o $ {odbiorcy} zobacz stronę rurę (8)
# i inne opcje koperty wiadomości.
# ================================================== ===================
# 
# Maildrop. Szczegółowe informacje można znaleźć w pliku Postfix Maildrop_Readme.
# Podaj także w main.cf: Maildrop_destination_recipient_limit = 1
# 
maildrop  unix  -       n       n       -       -       pipe
  flags=DRXhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
# 
# ================================================== ===================
# 
# Ostatnie wersje Cyrus mogą użyć istniejącego wpisu „LMTP” Master.cf.
# 
# Określ w Cyrus.conf:
# lmtp cmd = "lmtpd -a" słuchanie = "localhost: lmtp" proto = tcp4
# 
# Określ w main.cf jeden lub więcej z poniższych:
# Mailbox_transport = LMTP: INET: LocalHost
# Virtual_transport = LMTP: INET: LocalHost
# 
# ================================================== ===================
# 
# Cyrus 2.1.5 (Amos Gouaux)
# Podaj także w Main.cf: Cyrus_Destination_recipient_Limit = 1
# 
# Cyrus Unix - N N - - Rura
# flagi = DRX User = Cyrus arg =/cyrus/bin/dostarczenie -e -r $ {sender} -m $ {rozszerzenie} $ {użytkownik}
# 
# ================================================== ===================
# Stary przykład dostawy przez Cyrus.
# 
# Stary -cyrus unix - n n - - rurka
# flagi = r użytkownik = Cyrus argv =/cyrus/bin/dostarczenie -e -m $ {rozszerzenie} $ {użytkownik}
# 
# ================================================== ===================
# 
# Szczegółowe informacje konfiguracji znajdują się w pliku Postfix UUCP_Readme.
# 
uucp      unix  -       n       n       -       -       pipe
  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
# 
# Inne metody dostarczania zewnętrznego.
# 
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}
I konfiguracja Opendkim. Opendkim identyfikuje serwery e -mail za pomocą klawiszy domenowych, aby były bardziej bezpieczne. Bez tego poczta nie jest podpisana i może nie dotrzeć do skrzynki odbiorczej.

nano config/etc_default_opendkim
Dodaj te linie:

# Uwaga: Jest to starszy plik konfiguracyjny. Nie jest używany przez Opendkim
# Usługa systemu. Użyj odpowiednich parametrów konfiguracji w
# /etc/opendkim.conf zamiast tego.
# 
# Wcześniej można było tutaj edytować ustawienia domyślne, a następnie wykonać
# /lib/opendkim/opendkim.service.generate, aby wygenerować system systemu zastępowania plików do
# /etc/systemd/system/opendkim.service.d/override.conf i
# /etc/tmpfiles.d/opendkim.conf. Chociaż jest to nadal możliwe, jest teraz
# Zalecane w celu dostosowania ustawień bezpośrednio w /etc/opendkim.conf.
# 
# Daemon_opts = ""
# Zmień na/var/szpula/postfix/run/opendkim, aby używać gniazda Unixa z
# Postfix w chroot:
# Rundir =/był/szpula/postfix/run/opendkim
RUNDIR=/run/opendkim
# 
# Ukształcenie, aby określić alternatywne gniazdo
# Zauważ, że ustawienie to zastąpi dowolną wartość gniazda w opendkim.conf
# domyślny:
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
# Słuchaj wszystkich interfejsów na porcie 54321:
# Gniazdo = INET: 54321
# Posłuchaj Loopback na porcie 12345:
# Socket = INET: 12345@localHost
# Słuchaj to 192.0.2.1 to port 12345:
# Socket = INET: 12345@192.0.2.1
USER=opendkim
GROUP=opendkim
PIDFILE=$RUNDIR/$NAME.pid
EXTRAAFTER=

nano config/etc_dovecot_conf.d_10-master.conf
Dodaj te linie:

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

# Domyślny limit VSZ (wielkość pamięci wirtualnej) dla procesów serwisowych. To jest głównie
# Miejsce do złapania i zabicia procesów, które wyciekają pamięć, zanim się zjedzą
# wszystko.
# Default_VSZ_LIMIT = 256M

# Użytkownik logowania jest wewnętrznie używany przez procesy logowania. To jest najbardziej niezgodne
# Użytkownik w systemie dovecot. W ogóle nie powinien mieć dostępu do niczego.
# default_login_user = dovenull

# Użytkownik wewnętrzny jest używany przez nieuprzywilejowane procesy. Powinien być oddzielony od
# Zaloguj się użytkownik, aby procesy logowania nie mogą zakłócać innych procesów.
# default_internal_user = dovecot

service imap-login {
  inet_listener imap {
    # Port = 143
  }
  inet_listener imaps {
    # Port = 993
    # SSL = Tak
  }

  # Liczba połączeń do obsługi przed rozpoczęciem nowego procesu. Zazwyczaj
  # Jedynymi przydatnymi wartościami są 0 (nieograniczona) lub 1. 1 jest bezpieczniejszy, ale 0
  # jest szybszy. <ca/wiki/loginProcess.txt>
  # service_count = 1

  # Liczba procesów, które zawsze czekają na więcej połączeń.
  # Proces_min_avail = 0

  # Jeśli ustawisz service_count = 0, prawdopodobnie musisz to rozwinąć.
  # vSZ_LIMIT = $ default_vsz_limit
}

service pop3-login {
  inet_listener pop3 {
    # Port = 110
  }
  inet_listener pop3s {
    # Port = 995
    # SSL = Tak
  }
}

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

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

  # Utwórz słuchacz inet tylko wtedy, gdy nie możesz użyć powyższego gniazda Unix
  # inet_lister lmtp {
    # Unikaj uczynienia LMTP widocznego dla całego Internetu
    # Adres =
    # port =
  # }
}

service imap {
  # Większość pamięci trafia do plików MMAP (). Może być konieczne zwiększenie tego
  # Limit, jeśli masz ogromne skrzynki pocztowe.
  # vSZ_LIMIT = $ default_vsz_limit

  # Max. Liczba procesów IMAP (połączenia)
  # Proces_limit = 1024
}

service pop3 {
  # Max. Liczba procesów POP3 (połączenia)
  # proces_limit = 1024
}

service submission {
  # Max. Liczba procesów przesyłania SMTP (połączenia)
  # Proces_limit = 1024
}

service auth {
  # Auth_socket_path wskazuje domyślnie ten gniazdo użytkownika Zazwyczaj jest
  # używane przez Dovecot-LDA, Doveadm, prawdopodobnie proces IMAP itp. Użytkownicy, którzy mają
  # Pełne uprawnienia do tego gniazda są w stanie uzyskać listę wszystkich nazw użytkowników i
  # Uzyskaj wyniki wszystkich wyszukiwań użytkownika.
  # 
  # Domyślny tryb 0666 pozwala każdemu podłączyć się do gniazda, ale
  # wyszukiwania użytkownika
  # Dopasowuje UID procesu dzwoniącego. Również jeśli UID lub GID dzwoniącego pasuje do
  # UID lub GID Socket, wyszukiwanie się udaje. Cokolwiek innego powoduje porażkę.
  # 
  # Aby zapewnić pełne uprawnienia dzwoniącego w celu wyszukiwania wszystkich użytkowników, ustaw tryb na
  # coś innego niż 0666 i Dovecot pozwala jądrze egzekwować
  # Uprawnienia (np. 0777 pozwala na pełne uprawnienia).
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix
  }
}

service auth-worker {
  # Proces pracownika autoryzacji jest domyślnie uruchamiany jako root, aby mógł uzyskać dostęp
  # /itp./Shadow. Jeśli to nie jest konieczne, użytkownika powinno zostać zmienione na
  # $ default_interal_user.
  # Użytkownik = root
}

service dict {
  # Jeśli używany jest proxy DICT, procesy pocztowe powinny mieć dostęp do gniazda.
  # Na przykład: tryb = 0660, Group = vmail i global Mail_Access_groups = vmail
  unix_listener dict {
    # Tryb = 0600
    # Użytkownik =
    # grupa =
  }
}
Jeszcze raz upewnij się, że zastąp domenę we wszystkich tych plikach, femmebabe.com, z wybraną domeną. Edytuj następny plik, konfigurację Dovecot,

nano config/etc_dovecot_dovecot
I dodaj te linie

## Plik konfiguracyjny OVECOT

# Jeśli się spieszysz, patrz http://wiki2.dovecot.org/quickconfiguration

# Polecenie „DoVeconf -n” daje czyste wyjście zmienionych ustawień. Użyj go
# Zamiast kopiowania i wklejania plików podczas publikowania na liście mailingowej Dovecot.

# '# „Postać i wszystko po tym, jak jest traktowane jako komentarze. Dodatkowe przestrzenie
# i zakładki są ignorowane. Jeśli chcesz użyć któregokolwiek z nich jawnie, umieść
# value inside quotes, eg.: key = "# zwęglenie i ciągłe białe listy ”

# Większość (ale nie wszystkie) ustawienia można zastąpić różnymi protokołami i/lub
# Źródło/docelowe adresy IPS, umieszczając ustawienia w sekcjach, na przykład:
# Protokół IMAP {}, lokalny 127.0.0.1 {}, zdalny 10.0.0.0/8 {}

# Wartości domyślne są wyświetlane dla każdego ustawienia, nie jest wymagane odkształcenie
# te. Są to jednak wyjątki od tego: brak sekcji (np. Przestrzeń nazw {})
# lub ustawienia wtyczek są domyślnie dodawane, są wymienione tylko jako przykłady.
# Ścieżki są również przykładami, a rzeczywiste wartości domyślne są oparte na konfiguracji
# opcje. Ścieżki wymienione tutaj są dla konfiguracji - -prefix =/usr
# --SYSCONFDIR =/etc--localstatedir =/var

# Włącz zainstalowane protokoły
!include_try /usr/share/dovecot/protocols.d/*.protocol

# Oddzielona przecinek IPS lub hosty, gdzie słuchać połączeń.
# „*” słucha we wszystkich interfejsach IPv4, ”::„ słucha we wszystkich interfejsach IPv6.
# Jeśli chcesz określić porty bezbłędne lub cokolwiek bardziej złożonego,
# Edytuj conf.d/master.conf.
# Słuchaj = *, ::

# Katalog podstawowy, gdzie przechowywać dane wykonawcze.
# base_dir =/var/run/dovecot/

# Nazwa tego instancji. W konfiguracji wielu instancji Doveadm i innych poleceń
# może użyć -i <name_name>, aby wybrać, która instancja jest używana (alternatywa
# do -c <config_path>). Nazwa instancji jest również dodawana do procesów Dovecot
# W PS wyjściu.
# instance_name = dovecot

# Wiadomość z życzeniami dla klientów.
# login_greeting = dovecot gotowy.

# Oddzielona przestrzeń lista zaufanych zakresów sieciowych. Połączenia z nich
# IPS mogą zastąpić ich adresy IP i porty (w celu rejestrowania i
# do kontroli uwierzytelnienia). disable_plaintext_auth jest również ignorowany dla
# te sieci. Zazwyczaj określasz tutaj swoje serwery proxy IMAP.
# login_trusted_networks =

# Oddzielona przestrzeń lista dostępu do logowania do sprawdzania gniazda (np. TCPWRAP)
# login_access_sockets =

# Z proxy_maybe = tak, jeśli cel proxy pasuje do dowolnego z tych adresów IP, nie rób
# Proxying. To zwykle nie jest konieczne, ale może być przydatne, jeśli miejsce docelowe
# IP to np. IP wydziwiający obciążenie.
# auth_proxy_self =

# Pokaż bardziej pełne tytuły procesów (w PS). Obecnie pokazuje nazwę użytkownika i
# Adres IP. Przydatne do sprawdzania, kto faktycznie korzysta z procesów IMAP
# (np. Udostępnione skrzynki pocztowe lub jeśli ten sam UID jest używany dla wielu kont).
# Verbose_Proctitle = no

# Jeśli wszystkie procesy zostaną zabite, gdy proces Master zostanie zamknięty.
# Ustawianie tego na „nie” oznacza, że ​​Dovecot można zaktualizować bez
# zmuszanie istniejących połączeń klientów do zamknięcia (choć może to być również
# Problem, jeśli aktualizacja jest np. z powodu poprawki bezpieczeństwa).
# Shutdown_clients = Tak

# Jeśli niezerowe, uruchom polecenia pocztowe za pośrednictwem tych wielu połączeń z serwerem Doveadm,
# zamiast uruchamiać je bezpośrednio w tym samym procesie.
# DoveAdm_Worker_Count = 0
# Gniazdo UNIX lub host: port używany do łączenia z serwerem Doveadm
# Doveadm_socket_path = Doveadm-Server

# Oddzielona przestrzeń lista zmiennych środowiskowych, które są zachowane na Dovecot
# uruchamianie i przekazanie wszystkich procesów dziecka. Możesz także dać
# Key = Pary wartości, aby zawsze ustawić określone ustawienia.
# Import_environment = tz

## 
## Ustawienia serwera słownika
## 

# Słownik może być używany do przechowywania list kluczowych = wartości. Jest to używane przez kilka
# wtyczki. Słownik można uzyskać bezpośrednio bezpośrednio lub choć
# Serwer słownika. Poniższe nazwy słowników blokowych mapy dla URI
# Gdy serwer jest używany. Można je następnie odwoływać za pomocą URI w formacie
# „Proxy :: <Nazwa>”.

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

# Większość faktycznej konfiguracji jest zawarta poniżej. Nazwy plików są
# Najpierw posortowane według ich wartości ASCII i przeanalizowane w tej kolejności. 00-prefiks
# w nazwach plików mają ułatwić zrozumienie zamówienia.
!include conf.d/*.conf

# Plik konfiguracyjny może również zostać uwzględniony bez podania błędu, jeśli
# Nie można go znaleźć:
!include_try local.conf

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

protocols = imap pop3

# Pozwala Dovecot słuchać wszystkich połączeń wejściowych (IPv4 / IPv6)

listen = *, ::
Dodaj hasło dla użytkownika dovecot:

nano config/etc_dovecot_passwd
Pierwszą częścią pliku przed okrętem jest nazwa użytkownika. Ostatnia część „YourPassword” oznacza hasło, które chcesz podać serwer poczty.

team:{plain}yourpassword
Następnie konfiguracja OpendKim

nano config/etc_opendkim.conf
I dodaj te linie:

# Jest to podstawowa konfiguracja podpisywania i weryfikacji. To może być łatwo
# dostosowany do podstawowej instalacji. Patrz Opendkim.conf (5) i
# /usr/share/doc/opendkim/examples/opendkim.conf.sample do pełnego
# Dokumentacja dostępnych parametrów konfiguracyjnych.

Syslog			yes
SyslogSuccess		yes
# Log, dlaczego nie

# Wspólne parametry podpisywania i weryfikacji. W Debian nagłówek „od” jest
# wyprzedzone, ponieważ często jest to klucz tożsamości używany przez systemy reputacji
# i w ten sposób wrażliwy na bezpieczeństwo.
Canonicalization	relaxed/simple
Mode			s
SubDomains		no
OversignHeaders		From

# Podpisanie domeny, selektora i klucza (wymagane). Na przykład wykonuj podpisywanie
# dla domeny „example.com” z selektorem „2020” (2020._domainkey.example.com),
# Korzystanie z klucza prywatnego przechowywanego w /etc/dkimkeys/example.private. Bardziej ziarniste
# Opcje konfiguracji można znaleźć w /usr/share/doc/opendkim/readme.opendkim.
# Domena przykład.com
# Selektor 2020
# KeyFile /etc/dkimkeys/example.private

# W Debian Opendkim działa jako użytkownik „Opendkim”. Wymagana jest Umas 007
# Korzystanie z lokalnego gniazda z MTA, które uzyskują dostęp do gniazda jako niepewnego
# Użytkownik (na przykład Postfix). Może być konieczne dodanie użytkownika „postfix” do grupy
# „Opendkim” w takim przypadku.
UserID			opendkim
UMask			007

# Gniazdo do połączenia MTA (wymagane). Jeśli MTA znajduje się w więzieniu Chroot,
# Należy upewnić się, że gniazdo jest dostępne. W Debian, Postfix działa
# chroot in/var/szpula/postfix, dlatego gniazdo Unix musiałoby być
# skonfigurowane jak pokazano w ostatnim wierszu poniżej.
# Gniazdo lokalne: /run/opendkim/opendkim.sock
# Gniazdo INET: 8891@LocalHost
# Gniazdo INET: 8891
Socket			local:/var/spool/postfix/opendkim/opendkim.sock

PidFile			/run/opendkim/opendkim.pid

# Hosty, do których można podpisać, a nie weryfikować, domyślnie wynosi 127.0.0.1. Zobacz
# Operacja Sekcja Opendkim (8) Aby uzyskać więcej informacji.
# InternalHosts 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12

# Kotwica zaufania umożliwia DNSSEC. W Debian podano plik kotwicy zaufania
# przez pakiet DNS-Root-Data.
TrustAnchorFile		/usr/share/dns/root.key
# Nazwale 127.0.0.1

# Mapuj domeny od adresów do klawiszy używanych do podpisywania wiadomości
KeyTable           refile:/etc/opendkim/key.table
SigningTable       refile:/etc/opendkim/signing.table

# Zestaw wewnętrznych hostów, których poczta powinna zostać podpisana
InternalHosts       /etc/opendkim/trusted.hosts

nano config/etc_default_opendkim
I dodaj te linie

# Uwaga: Jest to starszy plik konfiguracyjny. Nie jest używany przez Opendkim
# Usługa systemu. Użyj odpowiednich parametrów konfiguracji w
# /etc/opendkim.conf zamiast tego.
# 
# Wcześniej można było tutaj edytować ustawienia domyślne, a następnie wykonać
# /lib/opendkim/opendkim.service.generate, aby wygenerować system systemu zastępowania plików do
# /etc/systemd/system/opendkim.service.d/override.conf i
# /etc/tmpfiles.d/opendkim.conf. Chociaż jest to nadal możliwe, jest teraz
# Zalecane w celu dostosowania ustawień bezpośrednio w /etc/opendkim.conf.
# 
# Daemon_opts = ""
# Zmień na/var/szpula/postfix/run/opendkim, aby używać gniazda Unixa z
# Postfix w chroot:
# Rundir =/var/buol/postfix/run/opendkim
RUNDIR=/run/opendkim
# 
# Ukształcenie, aby określić alternatywne gniazdo
# Zauważ, że ustawienie to zastąpi dowolną wartość gniazda w opendkim.conf
# domyślny:
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
# Słuchaj wszystkich interfejsów na porcie 54321:
# Gniazdo = INET: 54321
# Posłuchaj Loopback na porcie 12345:
# Socket = INET: 12345@localHost
# Słuchaj to 192.0.2.1 to port 12345:
# Socket = INET: 12345@192.0.2.1
USER=opendkim
GROUP=opendkim
PIDFILE=$RUNDIR/$NAME.pid
EXTRAAFTER=
Gdy będziemy gotowi skonfigurować nasz serwer postfix, uruchomimy poniższy kod z osadzoną odpowiednią nazwą domeny. Zacznij od utworzenia skryptu

touch scripts/postfixsetup
sudo chmod a+x scripts/postfixsetup
nano scripts/postfixsetup
Teraz, w Nano, edytor tekstu, edytuj ten plik, aby zawiera nazwę domeny zamiast femmebabe.com.

# ! / bin / bash
# Konfiguracja 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}'
Teraz uruchom wypełniony skrypt, aby skonfigurować Postfix, Opendkim i Dovecot.

./scripts/postfixsetup
Po uruchomieniu tego skryptu skopiuj ostatni wiersz, który drukuje i wklej go do konfiguracji DNS jako wartości SendOnly._Domainkey. Jest to klucz OpendKim używany do identyfikacji Twojej domeny podczas wysyłania bezpiecznej poczty. Wspaniały! W ciągu kilku dni powinieneś być w stanie wysłać pocztę z serwera pod warunkiem, że wszystko jest prawidłowo skonfigurowane. Jeśli właśnie skonfigurowałeś DNS dla serwera pocztowego, aktualizacja rekordów powinna zająć mniej niż 72 godziny. Zazwyczaj jest znacznie szybszy. Możesz sprawdzić, czy Twój serwer działa za pomocą tego polecenia, dostarczył e -mail:

echo “test” | mail -s “Test Email” youremail@gmail.com
Jeśli wydaje się, że wszystko działa poprawnie, powinieneś być w stanie wysyłać wiadomość e -mail ze swoim serwerem. Jeśli to nie działa, spróbuj spojrzeć na dzienniki, aby zobaczyć, jaki może być błąd.

tail –lines 150 /var/log/mail.log
Będzie to oferować szczegółowe informacje o poczcie, które jest wysyłane przez serwer i to, czy działa poprawnie. Powinieneś być w stanie zobaczyć e -mail w swojej skrzynce odbiorczej, jeśli go nie ma, sprawdź folder spamowy. Będziesz także musiał skonfigurować swoje ustawienia w ustawieniach.py, aby Twój serwer e -mail mógł porozmawiać z aplikacją Django, projektem. Dodaj lub wymień te linie w swoich ustawieniach

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)
Zauważ, że używamy pliku konfiguracyjnego, aby uzyskać hasło. Załadujmy ten plik w ustawieniach tak, na samym początku pliku.

import os
import json

# Otwórz i załaduj konfigurację
with open('/etc/config.json') as config_file:
    config = json.load(config_file)
Utwórzmy ten plik i dodajmy do niego tajny klucz, a także hasło pocztowe. Aby wygenerować tajny klucz, użyj tego polecenia, o jakiejkolwiek długości na końcu:

openssl rand -base64 64
Teraz skopiuj tekst, który openssl wygenerował i edytuj /etc/config.json

sudo nano /etc/config.json
Dodaj następujące wiersze do pliku, z kluczem, który openssl wygenerował jako tajny klucz.

{
	"SECRET_KEY": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX-generated-using-openssl)",
	"EMAIL_HOST_PASSWORD": "yourpassword"
}
Format JSON jest prosty i łatwy w użyciu, możemy zadeklarować inne klucze, których chcemy również użyć w naszym projekcie, i utrzymywać je odrębne od naszego katalogu projektu, aby inni użytkownicy nie mogli do nich pisać, aby nie mogli ich czytać sam z naszego katalogu projektu. Jest to zalecana praktyka dla klawiszy API, z których użyjemy więcej niż kilku tutaj. Będziesz także chciał wykonać kopię zapasową swojego projektu, aby upewnić się, że wszystko jest zapisane i będziesz mógł później odzyskać swoją pracę, nawet jeśli nie chcesz już wynająć serwera.

sudo backup
Teraz spróbuj wysłać wiadomość e -mail HTML z serwera WWW, pod warunkiem, że wysłanie jednego z wiersza poleceń działa. Zapytaj instancję użytkownika w powłoce i wyślij wiadomość e -mail HTML do tego użytkownika za pośrednictwem Django. Zmień moje imię w kodzie, Charlotte, na swoją nazwę użytkownika.

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()
Jeśli pierwsze polecenie nie działa, upewnij się, że użyj

source venv/bin/activate
Pod warunkiem, że wszystko jest skonfigurowane poprawnie, teraz otrzymasz mile widziany e -mail w skrzynce pocztowej wysłanej przez Twoją aplikację internetową. Dobra robota! Przeszedłeś długą drogę. Chciałem dodać, jeśli kiedykolwiek walczysz z jakichkolwiek błędów podczas pracy nad takim projektem, nie wahaj się wyszukać odpowiedzi i poproś o pomoc. Google, wśród innych wyszukiwarek, są świetnymi zasobami do wyszukiwania pomocy w programowaniu. Po prostu wyszukaj otrzymany błąd, a będziesz mógł zobaczyć, jak inne osoby rozwiązują problem. Możesz się ze mną skontaktować, twoi nauczyciele (nauczyciele, profesorowie, nauczyciele), wszelkich rówieśników w Internecie, którzy są dostępni do pomocy w programowaniu, lub ponownie zapoznaj się z tą książką lub innymi zasobami, aby znaleźć rozwiązania problemów, które doświadczasz. Rozumiem, że to nie jest łatwe, ale nawet jeśli przeczytałeś w tej chwili i nie piszesz żadnego kodu, uczysz się dużo o budowaniu aplikacji internetowej od zera. Poklepać się po plecach, robisz świetniestanowisko. Dziękujemy za poświęcenie czasu na przeczytanie tego trzeciego edycji przewodnika w tworzeniu stron internetowych. W przyszłych wydaniach podam więcej ważnych przykładów omówionych na początku dokumentu i zanurzymy się znacznie głębiej w świat oprogramowania i sprzętu. Bądź na bieżąco z tym, co ma nadejść, i nie mogę się doczekać, aby nauczyć Cię, jak budować niesamowite oprogramowanie. Do zobaczenia w następnym






Zamknąć
Strona 1
Skok
Zobacz pełny artykuł
Kontynuuj czytanie

Kupić | Kupuj za kryptowalutę



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


(Kliknij lub dotknij, aby pobrać obraz)
Profesjonalna rozrywka, zdjęcia, filmy, dźwięk, transmisja na żywo i swobodna rozgrywka, a także skanowanie tożsamości, tworzenie stron internetowych i usługi macierzyństwa zastępczego.

Zostaw mi napiwek w Bitcoin, korzystając z tego adresu: 3KhDWoSve2N627RiW8grj6XrsoPT7d6qyE

© Glam Girl X 2025

Warunki świadczenia usług