Praktisk webbaserad djupinlärning och säkerhet genom exempel

DaisyS profilfoto

Av Daisy

Praktisk webbaserad djup inlärning och säkerhet med exempel Tredje upplagan Charlotte Harper 3 juli 2024 Förord: Säkerhetsöverväganden för att bygga programvara för webben är en viktig del av alla webbutvecklare plan och exekvering medan man konstruerar en prototyp som är pålitlig, stabil och användbar för praktiska ändamål. DOM (dokumentobjekt Markup), med implementeringen av HTML, JavaScript och CSS samt backend -programvara som implementerar Python, C/C ++, Java och Bash, ger webbutvecklare frihet och kraft att skapa ett brett utbud av projekt som uttrycker som uttrycker kreativitet, ge användarvänlighet och funktionalitet, framställa ödmjukhet och karaktär och ge användarvänlighet samt bekvämlighet och viktiga tjänster som alla är attraktiva för den genomsnittliga Joe, slutanvändaren som vill döda tid eller få något gjort på internet, Vanligtvis på en smarttelefonenhet på pekskärmen. De flesta skulle inte ens veta var de ska börja när de vill bygga en webbplats från grunden,De tenderar att starta på en annans webbplats och bygga något begränsat i funktionalitet, pålitlighet, användarvänlighet och särskilt kreativitet när de kunde ha haft alla de senaste kraftfulla verktygen till sitt förfogande för att bygga något användbart utan att slösa tid på att trycka på knappar, och Speciellt slösa pengar för att betala för dyra prenumerationer på programvara som få människor ville använda ändå med tanke på att de är begränsningar i användarvänlighet och flexibilitet. Om du har några minuter att läsa igenom den här boken och lära mig vad jag vill lära dig, eller till och med prata med mig personligen om dina mål och få lite vägledning i rätt riktning och är motiverade att lära sig att koda och skriva din egen programvara , Ta den här boken hem och avsätta lite tid för att lära sig att bygga nästa inflytelserika, kraftfulla, strömlinjeformade och viktiga webbapplikationer, en webbplats som är allt på dig och gör exakt vad du vill och uppfyller din publiks behov. Om mig: Jag är en mjukvaruutvecklare med en bredAnge of Experience in C/C ++, Java, Python, HTML, CSS och JavaScript. Jag bygger webbplatser som människor vill använda, vill besöka och till och med bli beroende av att använda bara för att lära mig, återskapa och döda tid, och viktigast av allt säljer jag programvara. Om du hade en idé om exakt hur du ville att en webbplats skulle se ut och fungera, var du villig att stödja mig så att jag kan tillgodose mina egna behov medan jag möter din, och du är villig att täcka kostnaderna för att driva en webbplats själv, Jag skulle bygga dig nästa YouTube, Tiktok, Twitter, Google eller till och med en högteknologisk säkerhetsapp bara du kan komma åt. Istället för att försöka sälja dig min tid försöker jag köpa din: Jag vill prata dig om att bygga en app (webbplats) själv med den information som redan finns och lära dig vad du behöver för att vara en oberoende mjukvaruutvecklare, Entreprenör, vilket leder en framgångsrik karriär inom vilket område du önskar. Och låt mig vara tydlig, den utbildning jag ger dig kommer att vara informell. Du kan gå i skolan och lära dig allt detta med enRMAL Education, eller till och med läsa den här boken i skolan, slutföra dina uppdrag och ta bort mycket från din utbildning, men jag kommer inte formellt att lägga dig i den heta platsen och be dig att slutföra uppdrag. Jag är inte din professor, du kan tänka på mig som en vän som vill vägleda dig mot en karriär som drivs av din egen personliga framgång. Och jag säljer inte heller din framgång, du måste köpa den med din tid. Learning to Code har en brant inlärningskurva och var aldrig lätt eller ens tänkt att vara. Du måste arbeta så hårt du kan och fortsätta att försöka misslyckas och försöka igen även när du är frustrerad för att lära dig och bygga appar själv. Det är i själva koden. Kod drivs av en kompilator som är utformad för att ge programmerarens felmeddelanden, och dessa kommer att lära dig hur du kodar, även om du helt enkelt kopierar felet i din sökmotor och läser andra människors exempel. Och jag måste säga, du behöver inte vara extremt rik, smart, framgångsrik,en detaljorienterad eller organiserad för att bygga en app. Datorn tar hand om den organisationen för dig. Du behöver bara fortsätta genom rättegången och felet, behålla fokus och arbeta hårt på vad du gör, och du kommer att ha en mycket framgångsrik karriär i hela det du gör. Vem jag är: Jag inser att det sista avsnittet handlade mer om att lära dig och ta dig en väg från den här boken. Vem är jag exakt? Det är en komplicerad fråga. Jag är oklar på det själv, eftersom jag lider av medicinska tillstånd som kan göra det svårt för mig att till och med koda eller skriva den här boken ibland, samtidigt som jag presenterar utmaningar med socialisering och identitetsfrågor som gör mitt liv svårare när det gäller att introducera mig själv . Kort sagt, om du läser den här boken tog du hem för att du bläddrade igenom den och tyckte att den var användbar, eller till och med om du bara läste så långt in, för dig är jag en likasinnad person som vill se dig lyckas i allt du gör. Jag är själv ingenjör, en programvarautvecklare och en student, och jag skriver den här boken för andra studenter som vill göra sina liv enklare genom att ha en handbok med programvaran de behöver göra sina liv enklare genom att ge exempel för att kopiera som passar ihop som ett stort pussel i ett arbete , användbar, stor, funktionell, sammanhängande och engagerande app som kan driva framgång oavsett när det gäller affärsverksamheten. I stort sett är det vad jag gör: Jag bygger appar för att hjälpa mig själv och andra människor lyckas. Jag är också författare, även om det här är min första publikation som jag tänker slutföra för att sätta min portfölj i ett användbart dokument, och jag är också konstnär. Jag ska erkänna detta för dig, jag är en konstig person. Jag är inte perfekt, jag har haft insatser med lagen till och med ledat mig att lämna högskolor och universitet och lämna stater för att försöka göra ett namn för mig själv med mer framgång. Jag är en kvinna vid födseln, jag bär smink, tar bilder av mig själv, bär klänningar och andra kvinnors kläder och jag håller mig medveten om mig själv som enMan av naturen. Jag har haft problem med andra människor tidigare som leder till kamp med att skriva och bygga webapps, och jag ber om ursäkt för att jag inte har kunnat få den här boken i dina händer förr: du behövde detta. Du kommer att vilja läsa och skriva kod som ser ut som min och fungerar som min och gör samma sak men ännu bättre, för om du har råd att köpa den här boken istället för att masha tangentbordet som jag bara för att skapa en bok själv som frågar pengar För det har du de resurser du behöver för att lyckas i ditt liv. Jag hade alla möjliga problem med familjen som växte upp, hälsotillstånd, läkare, media och lagen och min kod återspeglar djupt kampen som är feminism och kvinnlig natur i en uppdelad och frustrerad värld. Men den här boken är något jag bryr mig djupt om, min bebis, min portfölj och mitt försörjning, så jag uppskattar din övervägande när du tar texten hem och noggrant pore över den för att lära av mig. Kom ihåg att jag inte är perfekt,Bok kommer att ha fel, revideringar och nya utgåvor, och du måste tänka med din logiska hjärna så bra du kan för att få en framgångsrik upplevelse med mitt skrivande. Förstå också att jag menar bra för dig även när du står inför utmaningar när du skriver. Tänk på det så här: När du bara kan hyra ett datorsystem för att göra vad du kan föreställa dig i det digitala utrymmet, lagra all information du möter, #$%! Yze och organisera den och förstå det, kommer du Oundvikligen möter svårigheter med den information du intar och till och med publicerar. Jag säger detta eftersom jag stöter på samma svårigheter. Använd den här boken på din egen risk, arbeta med ditt samhälle och samhällen tillgängliga för dig för att bygga programvara inom en säker miljö och ta inte saker till personligen när du misslyckas eller till och med lyckas på fel sätt: det är så jag fick så långt och varför jag kan ta med dig den här texten och hjälpa dig att lyckas utan att diverge på en väg av galenskap som lämnarJag förstörde, slits och slogs medan jag stöter på de vanliga problemen som alla gör på global skala tack vare den paralellistiska globala skalan i nätverket som vi kommer att arbeta, Internet. Du kanske inte är mycket bekant med vem jag är med bara några ord, men jag uppmuntrar dig att läsa vidare, du kommer att lära känna mig när du fortsätter att läsa och förstå mig medan du bygger dina egna projekt för att slutföra ditt arbete. Det kommer inte att finnas några läxor med den här boken, så länge dina professorer eller lärare inte tilldelar dig några, men jag uppmuntrar dig starkt att bygga en portfölj av projekt själv när du läser längs, liksom ett capstone -projekt som visar hur du kan Applicera det du har lärt dig. Mitt Capstone -projekt är grunden för det mesta av det du kommer att läsa i den här boken, eftersom det innehåller kod från mina tidigare projekt, kod som jag har skapat och lärt mig att skriva metodiskt för hand och ett brett utbud av idéer och tips som har hjälpt mig lyckas till den punkt där jag kan snurra upp en enkel app som ärUlt presenterade och ser ut och uppför sig som en populär app som du kan se din vän eller familj använda, på internet, annonseras till dig eller i nyheterna. Vad den här boken är: Den här boken är en tutorial med exempel. Du kan hitta kod här, instruktioner för hur du lär dig att koda, information om felsökningskod och fixa fel, felsöka steg, instruktioner om hur du säkerhetskopierar och sparar din kod, omplacerar om någon bryter din kod, säkra din kod, distribuera Din kod, bygg interaktiva webbplatser som är underhållande, engagerande och beroendeframkallande, så får du en känsla av vem jag är, varför detta är viktigt och hur du kan framställa dig själv, din app och företagsbild, såväl som programvaran du byg...
Praktisk webbaserad djupinlärning och säkerhet genom exempel

Praktisk webbaserad djup inlärning och säkerhet med exempel Tredje upplagan Charlotte Harper 3 juli 2024 Förord: Säkerhetsöverväganden för att bygga programvara för webben är en viktig del av alla webbutvecklare plan och exekvering medan man konstruerar en prototyp som är pålitlig, stabil och användbar för praktiska ändamål. DOM (dokumentobjekt Markup), med implementeringen av HTML, JavaScript och CSS samt backend -programvara som implementerar Python, C/C ++, Java och Bash, ger webbutvecklare frihet och kraft att skapa ett brett utbud av projekt som uttrycker som uttrycker kreativitet, ge användarvänlighet och funktionalitet, framställa ödmjukhet och karaktär och ge användarvänlighet samt bekvämlighet och viktiga tjänster som alla är attraktiva för den genomsnittliga Joe, slutanvändaren som vill döda tid eller få något gjort på internet, Vanligtvis på en smarttelefonenhet på pekskärmen. De flesta skulle inte ens veta var de ska börja när de vill bygga en webbplats frånSkrapa, de tenderar att starta på en annans webbplats och bygga något begränsat i funktionalitet, pålitlighet, användarvänlighet och särskilt kreativitet när de kunde ha haft alla de senaste kraftfulla verktygen till sitt förfogande för att bygga något användbart utan att slösa tid på att trycka på knappar , och särskilt att slösa pengar som betalar för dyra prenumerationer på programvara som få människor ville använda ändå med tanke på att de begränsningar i användarvänlighet och flexibilitet. Om du har några minuter att läsa igenom den här boken och lära mig vad jag vill lära dig, eller till och med prata med mig personligen om dina mål och få lite vägledning i rätt riktning och är motiverade att lära sig att koda och skriva din egen programvara , Ta den här boken hem och avsätta lite tid för att lära sig att bygga nästa inflytelserika, kraftfulla, strömlinjeformade och viktiga webbapplikationer, en webbplats som är allt på dig och gör exakt vad du vill och uppfyller din publiks behov. Om mig: Jag är en mjukvaruutvecklare mederfarenhetsintervall i C/C ++, Java, Python, HTML, CSS och JavaScript. Jag bygger webbplatser som människor vill använda, vill besöka och till och med bli beroende av att använda bara för att lära mig, återskapa och döda tid, och viktigast av allt säljer jag programvara. Om du hade en idé om exakt hur du ville att en webbplats skulle se ut och fungera, var du villig att stödja mig så att jag kan tillgodose mina egna behov medan jag möter din, och du är villig att täcka kostnaderna för att driva en webbplats själv, Jag skulle bygga dig nästa YouTube, Tiktok, Twitter, Google eller till och med en högteknologisk säkerhetsapp bara du kan komma åt. Istället för att försöka sälja dig min tid försöker jag köpa din: Jag vill prata dig om att bygga en app (webbplats) själv med den information som redan finns och lära dig vad du behöver för att vara en oberoende mjukvaruutvecklare, Entreprenör, vilket leder en framgångsrik karriär inom vilket område du önskar. Och låt mig vara tydlig, den utbildning jag ger dig kommer att vara informell. Du kan gå i skolan och lära dig allt detta med enFormell utbildning, eller till och med läsa den här boken i skolan, slutföra dina uppdrag och ta bort en hel del från din utbildning, men jag kommer inte formellt att lägga dig i den heta platsen och be dig att slutföra uppdrag. Jag är inte din professor, du kan tänka på mig som en vän som vill vägleda dig mot en karriär som drivs av din egen personliga framgång. Och jag säljer inte heller din framgång, du måste köpa den med din tid. Learning to Code har en brant inlärningskurva och var aldrig lätt eller ens tänkt att vara. Du måste arbeta så hårt du kan och fortsätta att försöka misslyckas och försöka igen även när du är frustrerad för att lära dig och bygga appar själv. Det är i själva koden. Kod drivs av en kompilator som är utformad för att ge programmerarens felmeddelanden, och dessa kommer att lära dig hur du kodar, även om du helt enkelt kopierar felet i din sökmotor och läser andra människors exempel. Och jag måste säga, du behöver inte vara extremt rik, smart,ESSFUL, eller till och med detaljorienterad eller organiserad för att bygga en app. Datorn tar hand om den organisationen för dig. Du behöver bara fortsätta genom rättegången och felet, behålla fokus och arbeta hårt på vad du gör, och du kommer att ha en mycket framgångsrik karriär i hela det du gör. Vem jag är: Jag inser att det sista avsnittet handlade mer om att lära dig och ta dig en väg från den här boken. Vem är jag exakt? Det är en komplicerad fråga. Jag är oklar på det själv, eftersom jag lider av medicinska tillstånd som kan göra det svårt för mig att till och med koda eller skriva den här boken ibland, samtidigt som jag presenterar utmaningar med socialisering och identitetsfrågor som gör mitt liv svårare när det gäller att introducera mig själv . Kort sagt, om du läser den här boken tog du hem för att du bläddrade igenom den och tyckte att den var användbar, eller till och med om du bara läste så långt in, för dig är jag en likasinnad person som vill se dig lyckas i allt du gör. Jag är själv ingenjörutvecklare och en student, och jag skriver den här boken för andra studenter som vill göra sina liv enklare genom att ha en handbok med programvaran de behöver göra sina liv enklare genom att ge exempel för att kopiera som passar ihop som ett stort pussel i ett arbete , användbar, stor, funktionell, sammanhängande och engagerande app som kan driva framgång oavsett när det gäller affärsverksamheten. I stort sett är det vad jag gör: Jag bygger appar för att hjälpa mig själv och andra människor lyckas. Jag är också författare, även om det här är min första publikation som jag tänker slutföra för att sätta min portfölj i ett användbart dokument, och jag är också konstnär. Jag ska erkänna detta för dig, jag är en konstig person. Jag är inte perfekt, jag har haft insatser med lagen till och med ledat mig att lämna högskolor och universitet och lämna stater för att försöka göra ett namn för mig själv med mer framgång. Jag är en kvinna vid födseln, jag bär smink, tar bilder av mig själv, bär klänningar och andra kvinnors kläder och jag håller mig medveten om mig själv som enKvinna av naturen. Jag har haft problem med andra människor tidigare som leder till kamp med att skriva och bygga webapps, och jag ber om ursäkt för att jag inte har kunnat få den här boken i dina händer förr: du behövde detta. Du kommer att vilja läsa och skriva kod som ser ut som min och fungerar som min och gör samma sak men ännu bättre, för om du har råd att köpa den här boken istället för att masha tangentbordet som jag bara för att skapa en bok själv som frågar pengar För det har du de resurser du behöver för att lyckas i ditt liv. Jag hade alla möjliga problem med familjen som växer upp, hälsotillstånd, läkare, media och lagen och min kod återspeglar djupt den kamp som är feminism och kvinnlig natur i en delad och frustrerad värld. Men den här boken är något jag bryr mig djupt om, min bebis, min portfölj och mitt försörjning, så jag uppskattar din övervägande när du tar texten hem och noggrant pore över den för att lära av mig. Kom ihåg att jag inte är detECT, den här boken kommer att ha fel, revideringar och nya utgåvor, och du måste tänka med din logiska hjärna så bra du kan för att få en framgångsrik upplevelse med mitt skrivande. Förstå också att jag menar bra för dig även när du står inför utmaningar när du skriver. Tänk på det så här: När du bara kan hyra ett datorsystem för att göra vad du kan föreställa dig i det digitala utrymmet, lagra all information du möter, #$%! Yze och organisera den och förstå det, kommer du Oundvikligen möter svårigheter med den information du intar och till och med publicerar. Jag säger detta eftersom jag stöter på samma svårigheter. Använd den här boken på din egen risk, arbeta med ditt samhälle och samhällen tillgängliga för dig för att bygga programvara inom en säker miljö och ta inte saker till personligen när du misslyckas eller till och med lyckas på fel sätt: det är så jag fick så långt och varför jag kan ge dig den här texten och hjälpa dig att lyckas utan att diverge på en väg av galenskapAves mig förstörde, slits och sliten medan jag stöter på de vanliga problemen som alla gör på global skala tack vare den paralellistiska globala skalan i nätverket som vi kommer att arbeta, Internet. Du kanske inte är mycket bekant med vem jag är med bara några ord, men jag uppmuntrar dig att läsa vidare, du kommer att lära känna mig när du fortsätter att läsa och förstå mig medan du bygger dina egna projekt för att slutföra ditt arbete. Det kommer inte att finnas några läxor med den här boken, så länge dina professorer eller lärare inte tilldelar dig några, men jag uppmuntrar dig starkt att bygga en portfölj av projekt själv när du läser längs, liksom ett capstone -projekt som visar hur du kan Applicera det du har lärt dig. Mitt Capstone -projekt är grunden för det mesta av det du kommer att läsa i den här boken, eftersom det innehåller kod från mina tidigare projekt, kod som jag har skapat och lärt mig att skriva metodiskt för hand och ett brett utbud av idéer och tips som har hjälpt mig lyckas till den punkt där jag kan snurra upp en enkel app somFullt presenterat och ser ut och uppför sig som en populär app som du kan se din vän eller familj använda, på internet, annonseras till dig eller i nyheterna. Vad den här boken är: Den här boken är en tutorial med exempel. Du kan hitta kod här, instruktioner för hur du lär dig att koda, information om felsökningskod och fixa fel, felsöka steg, instruktioner om hur du säkerhetskopierar och sparar din kod, omplacerar om någon bryter din kod, säkra din kod, distribuera Din kod, bygg interaktiva webbplatser som är underhållande, engagerande och beroendeframkallande, så får du en känsla av vem jag är, varför detta är viktigt och hur du kan framställa dig själv, din app och företagsbild, såväl som programvaran du bygger I det absolut bästa ljuset att vara det mest attraktiva som möjligt för dina slutanvändare, din webbplats besökare. I den här boken kommer jag att visa ett antal exempel på mjukvarudesign med fokus på webben som plattform och säkerhet. Vi kommer att initiera inlärningsupplevelsen genom att bygga en grundläggandeoject med UNIX -skalet, med säkerhetskopierings- och skriptfunktioner. Sedan kommer vi att undersöka en grundläggande bloggwebbplats, uppgradera vår blogg med foto- och videofunktioner samt använda dessa funktioner för att använda säkerhetslösningar med gratis programvara och säkra vår server med en pluggbar autentiseringsmodul (PAM). Vi kommer sedan att granska filhantering och bearbetning, utforska videoredigering, röstdonation, streckkodskanning och optiskt teckenigenkänning, bland andra koncept. På vägen kommer vi att undersöka API: er som hjälper oss att göra vår programvara mer användbar och säker, med gratis och betalda alternativ. Längs vägen kommer vi att utforska fysiska säkerhets- och militanta verktyg som skjutvapen och ammunitionsdesign och tillverkning inklusive fat- och repeaterdesign, torn- och drone -design och andra rektorer som vi kommer att integrera med vår programvara i det befintliga nätverket för att skydda vår programvara och visa självförsvar och resillience. Vi tar pauser på vägen för att bygga spel, 2D och 3DUtlänningsmotorer och arbeta med inbäddad hårdvara i exempelstudieexempel på grundläggande dimensionell renderingsprogramvara och en elektronisk vibrerande massager i silikongummi. På vägen kommer vi också att använda maskininlärningslösningar som redan finns för att bättre säkra vår programvara. Vi kommer också att använda aktieverktyg som finns tillgängliga för webben för att effektivisera och säkra processen. Den här boken är en guide till din framgång med att bygga en webbapplikation och integrera den med ett professionellt nätverk av dator och inbäddade mekaniska system, och totalt sett en guide för att bygga programvara och inbäddad hårdvara utan bakgrundskunskap eller tidigare erfarenhet. Vad den här boken inte är: Om du verkligen vill ha en webbplats kan du bara ställa in en enkel butik och sälja vad du behöver, lägga upp en blogg, posta foton eller videor eller på annat sätt utan att skriva en enda kodrad. Den här boken är inte det. Den här boken kommer att lära dig hur du bygger programvara som är mer användbar, heltFunktion, funktionell och säker än någon programvara du redan kan hitta, eftersom den distribuerar den senaste programvaran som fortfarande är prototyper, kan vara dyrt att köra på en skala äldre företag som arbetar på och inte tilltalar bakåt, invecklade företag som ställs in på Tjäna pengar för människor som inte riktigt gör någonting. Om du följer den här boken noggrant, vill du skriva kod, forskningskod, bygga dina egna appar och du kommer att tjäna pengar på vad du gör. Jag kommer att tjäna pengar på den här boken, även i tidiga stadier, eftersom den innehåller information som människor behöver och vill läsa, och redan köper när de köper eller använder mina appar. Den här boken kommer inte att bygga en app för dig, men den kommer att peka dig i rätt riktning och beväpna dig med de verktyg du behöver och de färdigheter och tips som underlättar din egen framgång i att bygga programvara för webben, med varje rad Kod Du måste skriva som ett exempel, redo att vara ihop i programvara du och dina supportrar, gäster, kundkrets,Riends, familj, besökare, entreprenörer och människorna på internet vill använda och stödja. Vad du kommer att lära dig: Den här boken kommer att lära dig hur du bygger och säljer programvara, riktigt funktionell, användbar programvara, medieinspelning, säkerhetsfunktioner som ansiktsigenkänning, maskinläsbar zonens streckkodskanning, webb -API: er för att autentisera, spela in och göra video och foton och utbyta meddelanden som Bluetooth och nära fält (NFC) kommunikation. Den här boken kommer att lära dig hur du använder en nätverksdator, med fokus på Debian Linux, hur man bygger baskod för att göra installation och säkerhetskopiera din programvara till en sömlös, automatiserad bris, hur man bygger pythonkod som backend för att servera dynamiska meddelanden, stil Saker snyggt med CSS -stilar med bootstrap, möjliggör användarinloggningar och interaktivitet genom nätverksenheter, bygga interaktiva medier och nätverk med andra webbplatser för att erbjuda säkerhetsfunktioner som textmeddelanden för verifiering eller andra ändamål, ID -skanning, bild och videomoderering, dataRansaktioner för att hålla din programvara säker, betalningsbehandling, cryptocurrency -handel, asynkrona uppgifter och mer. Du kommer att lära dig hur du bygger dina egna Bluetooth -enheter, med batterier, laddare, mikrokontroller, kretsar, motorer och sensorer, med löd, tråd och 3D -tryckt samt gjutmaterial. Jag kommer att demonstrera 3D -designprinciper som används för tillsatsstillverkning och verktyg och dö, så du kan tillverka dina egna inbäddade hårdvaruenheter med integrerade batterier, laddare, elektroniska kretsar och funktionella utgångar. och nätverk dem med Bluetooth och webben. Specifikt kommer vi att undersöka två fallstudier, en vibrerande massager och ett hemlagat skjutvapen, båda programmerade i OpenSCAD, som är tillgängligt som ett grafiskt gränssnitt eller kommandoradsverktyg och kan integreras i en webb för snabbare resultat. Du kommer att lära dig att bygga och distribuera en webbplats från grunden utan tidigare erfarenhet, gör den funktionell, säker, vacker, användbar och mestMitant praktiskt. Du kommer att lära dig att använda maskininlärning och datorsyn för att göra en webbplats säker och mer praktisk, spela in video och ljud från din webbplats, donera din röst, skapa musik och modulera ljud för att skapa användbara prover och hur man bryter igenom bruset med Utnyttja andra webbplatser för att bygga det bästa möjliga nätverket av webbplatser som du kan länka direkt till ditt för att dela all användbar information du har att erbjuda, och ännu viktigare att föra människor till din programvara och företag. Den här boken kommer att fokuseras mest på media, säkerhet och maskininlärning, som är de viktigaste tre komponenterna som hjälper dig att bygga användbar programvara för webben genom att engagera rätt användare och frigöra fel på ett sätt som är realistiskt, praktiskt, praktiskt, Händer på och engagerar sig även automatiska och robusta. Den här boken lär Unix, Speciellt Debian (Ubuntu), Bash Shell, Python, HTML, CSS, JavaScript och ett antal användbara programvarupaket förn som förfrågningar, såväl som användbar bash -programvara som GIT och FFMPEG. Jag kommer också att lära dig hur du handlar cryptocurrency automatiskt och tar betalningar i cryptocurrency eller från vanliga betalkort medan du till och med betalar dina besökare en del av dina intäkter om du väljer att göra det. Jag kommer att lära dig hur du kan tjäna pengar från din webbplats genom reklam också, hur du kan redo din app för sökmotorer och göra det snabbt, rankat i den första rankingen för vad dina kunder kommer att söka för att hitta dig och rangordna i så många vanliga sökningar som möjligt. Jag kommer att lära dig hur du säljer din programvara, annonserar den, vädjar till kunder som letar efter dina tjänster och gör ett namn för dig själv på internet via vägar som redan finns, är billiga och fungerar bra. Jag kommer att lära dig hur du sparar dina data på molndatorer som fungerar för dig och sparar dina data billigt, hur du planerar och bygger en webbplats som gör vad dina användare vill ha och vad du vill och hur du håller dina användare engagerade aving din webbplats en kran bort på sina telefoner med aviseringar, e -post, textmeddelanden, telefonsamtal och fler vägar för att föra dina användare tillbaka till din webbplats till ditt förfogande bakom klicket på en knapp som är säkrad till dig. Den här boken kommer att fokusera på praktiken att publicera och distribuera media i stora mängder, från text till foton till videor till ljud, vilket gör ett gott intryck på slutanvändare (din kundkrets) och säljer dig själv på något sätt som du gör för att skapa En webbplats, en app som bara är representativ för dig och dig, och gör dig, din programvara och ditt företag ser bra ut på bästa sätt. Du kommer också att lära dig några tips och tricks från mig, från kodningstips, praktisk fåfänga som smink och fotografering, modellering och skådespelare och mer, vilket kommer att vara viktigt för att framställa dig själv och ditt företag i bästa möjliga ljus med alla tillgängliga verktyg till dig när du distribuerar så mycket innehåll du behöver över en hälsosam balans mellan plattformar för att ta med dig dine att realiseras utan mer ansträngning, arbete eller pengar än vad som är nödvändigt. Den här boken kallas "praktisk webbaserad djup inlärning och säkerhet med exempel" av en anledning: den handlar om att lära sig att koda, speciellt för webben, särskilt med fokus på säkerhet, ur praktisk synvinkel, med exempel på arbetskod som tjänar De praktiska syftena som beskrivs i texten. Inlärningskomponenten i denna text omfattar också maskininlärning av maskiner, koden som jag visar hur du kör för webben som hanterar datorsyn, ansiktsigenkänning, bild- och videomoderering, förbättring av bild, upplösning, bildtexter och andra uppgifter som som Förutsägelsemetriker som kommer från bilder, till exempel bildens natur som en autentisk, datorövervakad bild eller en optisk kopia (ett foto av en bild eller tryckt foto). Maskininlärning är mycket viktigt när det gäller webbsäkerhet och mjukvarusäkerhet, eftersom det kan förforma uppgifter som annars var omöjliga. Din datorLogga in dig med ett lösenord, men det kan vara säkrare att använda den om det loggar in dig med ditt ansikte. Du kan göra en serverdator så säker, en dator som normalt skulle be dig om ett användarnamn och lösenord och logga in dig, kanske med ett bekräftelsetoken för varje ny inloggning eller ny IP -adress, men om du bygger stor skala, lätt att Användning, grundläggande säker och kraftfull programvara, det kan räcka. Att binda din programvara för nära någon annans programvara, som en e -posttjänst eller textmeddelande, räcker inte för att göra din programvara säker, eller någons (någon webbplats du använder). Den som bygger programvara som är oklanderligt säker har en viss känsla av vad detta innebär. Programvaran är i sig osäker eftersom enheterna och kontona vi använder för att komma åt den inte alltid står till vårt förfogande, de kan vara i händerna på alla med sjuk avsikt för programvaran och därför kan utgöra en risk för själva programvaran. Detta är något i fokus för denna bok. En nätverksdator är som standardSäkrad med ett långt nyckeltoken, kallad och SSH eller Secure Shell -nyckel, och är annars bäst säkrad med en webbserver, eftersom webbservern ger den öppna åtkomsten såväl som toppmodern för konstsäkerhetsverktyg som körs på servern. Webservern har tillgång till användarens webbläsare, vilket utan tvekan är den mest kraftfulla delen av användarens enhet, eftersom det är den plats där användaren kan komma åt nätverksprogramvara. Denna verktygssats kan göra text, webbsidorna du ser och kan också spela in bilder, ljud och video (som ett foto av ett ansikte eller ett tillstånds -ID), kan läsa och skriva till Bluetooth -radioenheter och kan läsa och skriva till Near Field Transponder -taggar, billiga nyckelkort, fobs, klistermärken, ringar och till och med chipimplantat med unika serienummer som kan läsas och skrivas till med data genererade och validerade av en webbserver bunden till webbplatsen. Med hjälp av alla verktyg till ditt förfogande, med den här boken kommer du att utrusta dig med kunskapen för att bygga en säker webbplats och totalt sett aUre nätverkat datorsystem som fungerar för dig, gör ditt bud och ser ut och känns rätt. Var man ska börja: Du är välkommen att hoppa över det avsnitt jag börjar den här boken med, eller i alla avsnitt, till den exakta koden du behöver, särskilt om du har erfarenhet av kodning före eller någon av de ovannämnda verktygen som jag kommer att beskriva i detalj i den här boken som samt dokumentera användningsfall och praktiska exempel därav. Om du inte har erfarenhet av att skriva kod rekommenderar jag starkt att du läser hela den här boken, och särskilt rekommenderar att du läser de tidigare avsnitten, för att se till att den här boken är rätt för dig. Om den här boken inte är rätt för dig, överväg att gåva den till en vän eller släkting som kan vara intresserad av att lära sig om webbutveckling själva och till och med överväga att låna den tillbaka och lära av dem för att fylla i luckorna där jag misslyckades med dig som en Lärare eller andra lärare gjorde före mig. Börja var du vill kommer alla delar av den här boken att vara användbar om du tänker bygga en användbarPP, och tänk på att de bästa apparna är byggda med slutanvändaren i åtanke: Känn din kund. Nu känner du mig, du känner den här boken och du är redo att börja. För att börja, ta en dator (även den billigaste bärbara datorn från en boxbutik, Amazon eller ett gammalt skrivbordsverk, och ställa in den på ett sätt som fungerar för dig. Hur man läser den här boken: Text markerad, anger att texten tillhör i en kommandotolk, där du skriver koden du kör. Kommandotolken är starkt tangentbordsfokuserat och kräver lite till ingen klickning, påskyndar ditt arbetsflöde och gör det lättare för dig. Komma igång: Låt oss dyka in. Vi börjar med att bygga kod på en lokal maskin och börja utan att bygga en webbplats ansluten till internet. Detta är säkrare att börja med, kostar ingenting och är lätt för dig. Beroende på ditt operativsystem kommer det att vara lite annorlunda att komma in i ett bash -skal. För Mac OS rekommenderar jag att du installerar en virtuell maskin vid denna tidpunkt, eftersom du får mest kompatibilitet medVirtuell maskin. Olika leverantörer som VirtualBox och Paralells kan köra en virtuell maskin för dig, även om det också är möjligt att installera Ubuntu direkt på maskinen, om du föredrar att använda en inhemsk miljö som rekommenderas för att skapa en snabb, strömlinjeformad upplevelse. Om du använder Linux eller Windows, som jag rekommenderar, bör det vara ganska enkelt att skapa ett projekt. Öppna din terminal, justera storleken som du ser lämpligt och börja följa steg 2. Om du använder Windows, följ steg 1. Steg 1: - Endast Windows -användare I Windows, Open Command Prompt som administratör och typ WSL –installera Steg 2: - Fortsätt här eller hoppa över steg 1 till här om du inte använder Windows I en öppen terminal, (beroende på ditt operativsystem, kallad Ubuntu i Windows, Terminal i Mac eller Linux eller ett liknande namn), börja med att skapa ett projekt. Vi gör detta med mkdir -kommandot, som skapar en katalog. Om du behöver skapa en katalog för att lagra ditt projekt, vilket rekommenderas, användCD -kommando att ändras till katalogen och och och CD/sökväg/till/katalog - sökvägen är mapparna (filer) som föregår din destinationskatalog, din standardväg är ~ eller/hem/användarnamn (där användarnamn är ditt användarnamn). För att ändra till standardkatalogen skriver du CD eller CD ~ MKDIR -exempel - Byt ut "Exempel" med namnet på katalogen Nu har du en arbetskatalog för ditt projekt. Att vara så viktigt att den här katalogen sparas om du behöver byta till en annan maskin eller distribuera koden du skriver så att den är redo för webben, kommer vi att bygga ett skript för att säkerhetskopiera din katalog i de kommande stegen. Men att bygga ett skript tar lite kod, och koden måste automatiseras för att vara så användbar som möjligt. Så låt oss bygga ett manus för att bygga skript först. Låt oss börja med att skapa skriptet och göra det körbart. Vi använder sudo, chmod och touch för detta och ringer skriptet


sudo touch /usr/bin/ascript
sudo chmod a+x /usr/bin/ascript
sudo nano /usr/bin/ascript
Nu har vi skapat skriptet, gjort det körbart och är redo att redigera det. Nano är en textredigerare som låter dig redigera text utan att klicka, vilket är mycket enklare än att använda ett grafiskt användargränssnitt. För att redigera en fil med Nano, använd Nano och sedan sökvägen till filen. För att skapa ett manus som gör ett manus är det ganska likt att göra vårt manus i första hand. Vi använder samma kod som ovan och ersätter namnet på skriptet, "Ascript" med en argumentparameter, $ 1. Detta låter oss ringa skriptet genom att skriva Simply Sudo Ascript Newscript, vid vilken tidpunkt vi kan skapa alla nya skript genom att ersätta "Newscript" med namnet på ditt skript. Koden i Nano ska se ut:

sudo touch /usr/bin/$1
sudo chmod a+x /usr/bin/$1
sudo nano /usr/bin/$1
Och för att stänga Nano kan vi hålla ner kontrollknappen och trycka på x, sedan y för att beteckna vi sparar filen och träffar return. I stället för att skriva dessa tre kommandon för att redigera ett skript kommer vi att kunna skriva Sudo Ascript Ascript för att redigera skriptet igen. Det här fungerar! Och alla nya skript kan enkelt köras genom att kalla det i skalet. Låt oss spara vårt arbete nu: Låt oss skriva ett säkerhetsskript för att spara vårt nya skript och sedan säkerhetskopiera det i vår projektkatalog, samtidigt som vi säkerhetskopierar säkerhetsskriptet.

sudo ascript backup
Nu, i Nano:

sudo cp /usr/bin/backup /path/to/directory/
sudo cp /usr/bin/ascript /path/to/directory/
Där/sökväg/till/katalog är vägen till projektet du skapade med mkdir. Senare kommer vi att lära oss att kopiera upprepade vägar som denna med en slinga och en lista, som är mindre kod, men för nu låt oss hålla det enkelt och ha några rader. För att köra det här skriptet och säkerhetskopiera din kod, spara filen i nano med kontroll+x, y och returnera och skriv nedan i ditt skal

backup
Om du alls uppmanas till ett lösenord när du läser den här boken och följer med i skalet, ange ditt användarlösenord korrekt, kommer du att ha tre försök innan du behöver köra kommandot igen. Du kan använda pilarna upp och ner för att köra om kommandon och redigera dem om du behöver köra något två gånger. Enkel tryck upp och ner intermittent för att välja ett kommando, innan du redigerar kommandot med höger, vänster pilar och radera tangent samt tangentbord och kör det med retur. Grattis! Du lyckades skapa ett fantastiskt backup -skript som säkerhetskopierar två viktiga skalskript i din arbetskatalog. Vi kanske flyttar saker senare när projektet blir större, men det fungerar för tillfället. Låt oss gå vidare till säkerhetskopiering i molnet, vi använder GitHub för detta (även om det finns många andra Git -lösningar för säkerhetskopiering, de är ungefär samma.) Git är en verisionskontrollprogramvara som låter dig säkerhetskopiera redigeringar till din programvara när du gör dem till en server, medangör det också möjligt för dig att ladda ner hela kopior av din programvara bakom ett lösenord eller nyckel. Det är avgörande för att spara din programvara, särskilt när vi migrerar till säkrade Linux -instanser som ibland går sönder när en enda kodrad misslyckas, vilket gör att du är inlåst medan din kod kanske inte säkerhetskopieras om du inte får chansen att stödja den Upp automatiskt, som vi kommer att täcka. Om du inte redan använder en Virtual Machine Ubuntu vid denna tidpunkt, rekommenderar jag att jag använder en Virtual -maskin i Ubuntu vid denna tid operationer på din dator. Vi kommer att flytta koden till en webbserver inom en snar framtid, men vi vill se till att det finns åtminstone några få lager av säkerhet bakom vår webbserver som är resistenta mot phishing och använder ett antal Linux -paket för att göra detta. Om du fortfarande vill använda Mac OS är du välkommen att söka efter och installeraE Nödvändiga paket online, men det kanske inte finns alternativ för varje paket som denna bok eller serie kommer att täcka. Låt oss lägga till några kommandon för att begå vårt arbete med säkerhetskopieringsskriptet genom att köra kommandot sudo ascript

# ...
git add –all
git commit -m “backup”
git push -u origin master
Återigen, kontrollera X för att spara. Nu måste vi göra en engångskonfiguration för detta projekt. Eftersom det snart kommer att vara ett GIT -projekt, behöver vi inte skriva varje kommando varje gång vi distribuerar från ett git -förvar, men vi får tag på detta när vi skriver våra distributionsskript. För att börja, låt oss se till att vi är i rätt katalog och initialisera Git -förvaret och generera SSH -nycklar.

cd /path/to/directory
git init
git branch -m master
ssh-keygen
När vi har skrivit ssh-keygen bör den nya nyckeln sparas i hemmappen under en mapp som heter .ssh. Det kallas id_rsa.pub. Låt oss hitta den här nyckeln och kopiera den. Att se det,

cd ~
cat .ssh/id_rsa.pub
Kopiera texten som returneras av det sista kommandot och skapa ett konto hos din GIT -leverantör (idealiskt Github) innan du lägger till SSH -tangenten till ditt konto. När du har ett konto klickar du på den övre högra menyn och anger inställningar innan du lägger till din SSH -nyckel i SSH- och GPG -tangenter under åtkomst i menyn. Välj Lägg till en SSH -tangent och lägg till din genom att klistra in den och ge den en titel, innan du sparar och återvänder till GitHub för att skapa ett nytt arkiv. Detta liknar andra GIT -leverantörer, du måste läsa deras dokumentation. I den nya arkivkonfigurationen, ge ditt förvar ett beskrivande namn och bestäm om du vill publicera det och se till att inte konfigurera inga filer för inkludering ännu. När förvaret har skapats, kopiera klonen med SSH -url och klistra in den i följande kommando.

git remote add git://… (your remote URL)
Nu kan du flytta tillbaka till ditt förvar med CD, du känner till detta. Prova ditt backup -skript nu med säkerhetskopiering Stor! Nu kan vi verkligen få kodning. Låt oss installera Django nu när vi har ett bra grepp om bash och git. Django låter oss automatiskt säkerhetskopiera vår programvara, Bash kan göra detta också men Django bör ha en enklare säkrare implementering (den kan inaktiveras och konfigureras lättare). För att installera programvara i Ubuntu kommer vi att använda sudo apt-get-kommandot. Låt oss först uppdatera och uppgradera programvaran vi redan hade. Detta kan göras med sudo apt-get-uppdatering och sudo apt-get upgrade -y. Låt oss sedan installera Python och vår virtuella miljö, hemmet till vår kod, med följande kommando: sudo apt-get install Python-is-python3 python3-venv Detta är allt du behöver för att komma igång med Django när det gäller programvaruinstallationer i Ubuntu -instansen. För Windows och Linux bör detta vara ganska enkelt, men för Mac kanske du vill installera en virtuell maskin ochLinux på den med en gratis eller betald virtuell miljö som VirtualBox eller Paralells Desktop och återskapar stegen ovan för att installera en Ubuntu -miljö. Ubuntu är avgörande i det här fallet eftersom det är programvaran som webbplatserna kör och det gör det möjligt för dem att vara värd för webbplatser med all ovannämnda programvara. Låt oss gräva in i Django. I vår katalog igen, med

python -m venv venv # Skapar den virtuella miljön där koden lagras
source venv/bin/activate # Aktiverar den virtuella miljön
pip install Django
django-admin startproject mysite . # Där mysite är projektet börjar jag i min nuvarande katalog.
Django kommer bara att komma igång, för Django är värd för webbservern och gör allt vi behöver för att få en grundläggande lokal webbplats igång. Nu när vi har Django installerat, låt oss redigera inställningarna lite för att det ska fungera hur vi behöver. Låt oss först skapa en ny app

python manage.py startapp feed
Du kommer att märka att den första appen heter Feed. Appen ska kallas vad du vill, och vi skapar nya appar, men namnet på varje app måste vara konsekvent varje gång appen hänvisas till i koden. För att lägga till en ny app kommer vi alltid att redigera inställningarna. Med nano,

nano app/settings.py
I inställningarna, hitta installerade_apps och separera [] i 3 rader. Använd fyra utrymmen på den tomma mittlinjen, lägg till "flöde" eller namnet på din app. Det här avsnittet av inställningarna. Ppy bör se ut:

INSTALLED_APPS = [
    'feed',
]
Innan vi glömmer, låt oss testa att Django arbetar. Med hjälp av kommandot python manage.py runserver 0.0.0.0:8000 kan vi köra servern och sedan navigera i en webbläsare på datorn som kör koden till http: // localhost: 8000 och se ett exempel webbsida (det fungerar!) Avsluta servern med Control C, samma som alla andra kommandon. Låt oss nu gräva till att skriva en pythonkod. Django har tre huvudkomponenter, alla drivs av kod helt. Komponenterna kallas modell, vy och mall, och var och en är på en högre respektive lägre nivå innan webbsidan levereras till användaren. Modellen är koden som lagrar information i databasen för hämtning, sortering och rendering. Vyn bestämmer hur modellen återges, manipuleras och modifieras, nästan varje vy kommer att använda en modell direkt. Mallen är HTML -koden med några extra klockor och visselpipor som kallas mallspråk. Mallen återges av vyn där den är fylld med pythonkod ochKontext som modeller och information (USA: s strängar och heltal) från vyn. Django har också andra komponenter, inklusive men inte begränsat till: Inställningar, som konfigurerar appen som vi diskuterade. URL: er, som är mönster som användaren följer för att få tillgång till specifika delar av webbapplikationen. Formulär, som definierar hur information som skickas till servern hanteras och återges till databasen såväl som till användaren. Dessa är grunden för att bearbeta information på serversidan och kan acceptera alla typer av information som datorlagringarna, framför allt textsträngar, siffror och sanna/falska booleans (vanligtvis kryssrutor). Mallar, som är HTML -kod- och mallspråk och överbrygga klyftan mellan Python och HTML, vilket innebär att Python -information kan serveras som HTML -kod som vem som helst kan komma åt och kan säkra en webbplats med begränsad åtkomst, samtidigt som Python -kod är tillgänglig för webben och användbar för en mängd olika ändamål på en fjärrenhet som inte gör deteed är nära servern. Statiska filer, som vanligtvis är JavaScript och dess bibliotek som servern serverar och är länkade till mallen. Mediefiler, som servern tjänar eller är externt värd, eller bara skrivna till servern innan de behandlas och publiceras till en annan server (en hink) för värd. Middleware, som är kodbitar som körs samtidigt som varje vy och betraktas som "inkluderade" i vyn. Kontextprocessorer, som bearbetar sammanhanget för varje vy och används för att lägga till extra sammanhang. Tester, som validerar att användaren eller begäran klarar vissa krav innan vyn återges. Konsumenter, som dikterar hur websockets hanterar och svarar på kommunikation. Admin, som används för att registrera modeller så att de kan manipuleras i detalj på Django Admin -sidan, där databasen kan administreras via ett grafiskt gränssnitt. Selleri, som definierar asynkrona uppgifter delar av Django -koden kan börjanning innan du omedelbart fortsätter till nästa uppgift eller kodrad. Django kan ha många andra komponenter, som vi kommer att diskutera i detalj här. Det finns många sätt att göra Django mer funktionella, lägga till webbutvecklingar, som är snabba, strömlinjeformade kommunikationskanaler, selleri, som kör asynkrona uppgifter och en mängd andra mjukvaror för att utöka Django, särskilt i visningsfunktionerna, där de flesta av koden körs. Visa funktioner är nyckeln eftersom de vanligtvis förklarar varje kod som är specifik för ett specifikt URL -mönster eller ett avsnitt av servern. Låt oss först utforska visningsfunktioner. Visa funktioner börjar med import som betecknar kod som kommer att användas i vyn och definieras med regelbundna funktionsdefinitioner eller klasser. De enklaste vyerna definieras av funktionsdefinitionen def och returnerar en httpresponse med en grundmall. Låt oss börja med att definiera en grundvy för att returnera texten "Hello World". Kom ihåg att varje gång du lägger tillfrån ett uttalande som def, om, medan du, etc, måste du lägga till fyra utrymmen för var och en av de föregångande definitionerna du vill använda på din funktion. Vi kommer att komma in på vad var och en av dessa betyder snart. Redigera filen med nano och lägg till följande rader från vår webbplats katalog och lägg till följande rader i slutet av

from django.http import HttpResponse

def hello(request):
    return HttpResponse('hello world')
Djangos httpresponse svarar med en textsträng, betecknad med öppningen och stängningen. Varje gång du skickar information till en funktion eller klass, som begäran eller en sträng, måste du använda parentes (, öppna och stänga). Det här är inte allt vi behöver för att se vår åsikt ännu. Naturligtvis har vi inte sagt till servern var vyn är exakt, vi måste fortfarande definiera en väg som vyn ska göra. Låt oss börja med att definiera en grundläggande sökväg i app/urls.py, så kommer vi in ​​i väggrupper senare. I app/urls.py, lägg till en rad efter importmeddelandena efter början av att importera den vy vi just skapade.

from feed import views as feed_views
Låt oss nu definiera visningsmönstret. Visa mönster har tre komponenter, sökvägskomponenten, som berättar för servern var vyn finns inom servern (URL -sökvägen som användaren skriver in i navigeringsfältet för att komma in på webbsidan), vynkomponenten där vyn anges och en Vänligt namn för vyn så det är enkelt att hämta sitt mönster när du arbetar med en mall, särskilt så att det är namn kan ändras och uppdateras om det behövs för att göra plats för en annan vy eller ta ett mer logiskt namn. Det är meningsfullt att göra saker på detta sätt och vara flexibel, eftersom din kodbas kommer att vara en ständigt föränderlig miljö som behöver flexibilitet och improvisation för att vara värdefull och lätt att arbeta med. Så här kommer din åsikt att se ut, du kan lägga till detta i urlpatterns = [avsnittet av app/urls.py. Visningsmönstret definieras med de tre komponenterna som beskrivs ovan och en funktion som kallas sökväg. Dina URL -mönster är en lista, så se till att alltid avsluta varje objekt i demmed ett komma, eftersom detta separerar var och en. Varje objekt bör också gå på en ny linje, återigen med fyra utrymmen innan det, precis som appen i inställningar.py. Vi definierar den första komponenten i vyn med en tom strängfunktion för att skapa en vy som körs på webbserverns rotkatalog. Dina webbadresser.py ska nu se ut

from feed import views as feed_views

urlpatterns = [
    path('', feed_views.hello, name='hello'),
]
Detta är grunden för att skapa en webbplats med Django som är helt statisk. För att skapa en mer dynamisk webbplats där vi kan börja cacheinformation, som bilder, videor, ljud och mer, måste vi använda modeller, som vi kommer att utforska nästa. Låt oss nu kontrollera vår kod och köra servern. För att kontrollera koden för fel, kör: Kör:

python manage.py check
Om det finns några felmeddelanden bör du noggrant granska de ändringar du gjorde i din app och se om det finns något som måste fixas, som ett främmande eller bristande utrymme, en extra karaktär, en oklart sträng, alla skrivfel, alla av misstag Raderat tecken eller något annat. När du läser igenom felmeddelandet (om du har ett) bör du kunna se sökvägen till en fil du skapade eller redigeras tillsammans med ett radnummer, så titta på den filen och raden och se om du kan fixa något som finns där . Om du har fixat problemet, kör ovanstående kommando igen. När din programvara är redo att köra och arbetar ser du utgången "Systemkontroll identifierade inga problem." Nu är du redo att gå. Kör servern med:

python manage.py runserver 0.0.0.0:8000
Öppna nu en webbläsare och navigera till http: // localhost: 8000. Du bör se texten som returneras i parentesen och citat för HTTPRESPES -funktionen i din åsikt. Detta är bara ett grundläggande exempel, men om du har gjort det så långt förstår du grunderna för hur Linux, Bash, Python och Django fungerar. Låt oss gräva djupare i någon databasmodellering och utforska kraften i en pythonklass för att lagra information. Sedan kommer vi att börja få tag på HTML och CSS innan vi gör vår webbplats fullt ut, flexibel och säker med JavaScript och maskininlärning. Klasserna lagras i modellerna. Redigera app/modeller.py med hjälp av Nano och lägg till en ny klass. En klass definieras med klassdefinitionen och skickas en superklass som den ärver från, i detta fall modeller.model. Klassens namn kommer efter klassdefinitionen, och efter klassdefinitionen A: (kolon) används, innan attributen och funktionsdefinitionerna är bundna till klassen betecknas nedan. Vår klassBehöver ett ID som vi kan använda för att hämta det och hålla det unikt, och det behöver också ett textfält för att lagra lite information. Senare kan vi lägga till en tidsstämpel, filer, booleans (sanna eller falska definitioner som kan hjälpa vår kod att fatta beslut om vad vi ska göra med modellen, och kan användas för att sortera den), en instans för att binda modellen till en användare loggad in i servern och mer. Låt oss packa upp koden

from django.db import models # Importen som används för att definiera vår klass och det är attribut

class Post(models.Model): # Definitionen av vår klass själv
    id = models.AutoField(primary_key=True) # ID för vår modell, en automatiskt genererad nyckel som låter oss fråga modellen, hålla den unik och är användbar när vi behöver interagera med modellen när den har skapats.
    text = models.TextField(default='') # Attributet som våra klassaffärer, i detta fall, en text, som inte är en tom sträng.
Stäng och spara filen som vi gjorde tidigare för att avsluta. Det finns många andra fält och alternativ som vi kommer att utforska när vi uppdaterar den här klassen när vår app utvecklas, men detta är de grundläggande nödvändigheterna av att skapa en app för att publicera lite text. Men denna modell fungerar inte ensam. Som beskrivits tidigare kommer vi att behöva ett anpassat vy och anpassat URL -mönster för att få denna modell att fungera, och vi kommer också att behöva ett formulär tillsammans med en mall. Låt oss utforska formuläret först. För att definiera ett formulär redigerar du app/forms.py med nano och lägg till följande rader. Vi kommer att behöva två import, våra formulärklasser, såväl som modellen vi skapade (Feed.Models.Post), en klassdefinition som liknar modellen och ett fält tillsammans med en underklass som heter META som kommer att definiera modellen som formen interagerar med. Formuläret kan också ha en initialiseringsfunktion som ställer in den baserat på information i begäran, modellen eller på annat sätt kommer vi att utforska detta senare. Modellformulär är så användbara eftersom de kan skapa en modell eller också redigera en modell,Så vi kommer att använda dem för båda. Låt oss definiera en i form.py

from django import forms
from feed.models import Post

class PostForm(forms.ModelForm):
    text = forms.CharField(widget=forms.Textarea)
    class Meta:
        model = Post
        fields = ('text',)
Detta är grunderna i hur en form och modell ser ut. Denna modellform kan användas för att instansera eller redigera ett inlägg och ändra texten som den innehåller. Vi tittar på att integrera denna form i en vy nästa. Låt oss först göra migrationer och migrera databasen så att vår kod kan interagera med modellen när den körs. För att göra detta, kör följande kommandon:

python manage.py makemigrations
python manage.py migrate
Det kommer att ta en minut att köra, men när det görs kommer det att göra det möjligt för modellen i vyer, mellanprogram eller någon annanstans i programvaran. Låt oss fortsätta med att göra en vy där vi kan se vår modell. Redigera flöde/visningar. Ppy och lägg till följande kod, som nämnts. Du behöver inte lägga till någonting efter # -tecknet, den koden är kommentarer som används för att beteckna information om koden. Vi börjar med att importera vår modell i vyerna och lägga till den i ett sammanhang där vi kan göra den i en mall som en lista för display. Därefter lägger vi till en mall där vi kan göra formuläret och modellen med en knapp för att skapa ett nytt objekt baserat på modellen och publicera den på servern. Detta låter komplicerat, så låt oss bara ta det steg för steg. Innan vi är klar med vyn, låt oss skapa en mall som bara gör modellen och se till att vi kan se den genom att skapa ett nytt inlägg i skalet. Så här ska den åsikten se ut:

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

def feed(request):
    posts = Post.objects.all() # Fråga alla inlägg i databasen hittills
    return render(request, 'feed/feed.html', {
        'posts': posts,
    })
Allt ser ganska enkelt ut tills vi kommer till botten. Render, värdet som returneras av funktionen istället för i ett HTTP -svar som föregående exempel, tar alltid en begäran som sin första input, accepterar ett sammanhang (i detta fall inläggen i databasen), som nu kan återges i mallen och returnerar mallen som definieras i funktionen. Mallen kommer att bli ett HTML -dokument med lite språk som heter Jinja2, som gör Python -information till HTML. För att börja skapa mallar ska du skapa två kataloger i flödet.

mkdir feed/templates
mkdir feed/templates/feed
Redigera sedan en mall i katalogen ovan, mata/mallar/mata och lägg till koden för det här exemplet. Låt oss titta på mallen för det här exemplet.
 
<!doctype HTML>
<html>
<body>
<legend>Feed</legend>
<hr>
{% for post in posts %}
<p>{{ post.text }}</p>
{% endfor %}
</body>
</html>
 
Detta är en mycket enkel mall. Den definierar öppnings- och stängning av HTML -taggar, en dokumenttyp, en kroppstaggen med en legendtitel, en paus -tagg som lägger till en liten linje över skärmen och en för slinga som gör varje inlägg i listan över inlägg som ett stycke i mallen. Detta är allt som krävs för att göra inlägg, men det finns ingen i databasen än. Låt oss skapa några med skalet. Vi kan köra skalet med hanter.py

python manage.py shell
Låt oss nu importera vår inläggsmodell

from feed.models import Post
Därefter skapar vi ett enkelt inlägg med en sträng och lämnar skalet. Strängen kan vara vad som helst, så länge är det giltigt text.

Post.objects.create(text='hello world')
exit()
Slutligen måste vi lägga till ett URL -mönster till vårt foder. Eftersom vår flödesapp kommer att använda flera webbadresser och vi vill hålla filstorlekar små, låt oss skapa en lokal webbadress.py i vår flödesapp som ser ut så här:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.feed, name='feed'),
]
Vi kommer också att behöva redigera URLS.py i basappen, vad vi beslutade att kalla den, detta var den första katalogen vi skapade. Redigera app/app.py och lägg till följande till URL -mönstren

from django.urls import include # upptill

urlpatterns = [
    # ... tidigare kod här
    path('feed/', include(('feed.urls'), namespace='feed')),
]
Nu, när vi kör servern med Python Manage.py RunServer, kommer vi att se sidan vi skapade eftersom vi har modell, vy och mall samt URL -mönster, tillsammans med objekt i databasen. Låt oss sedan implementera det formulär vi skapade och börja skapa våra egna inlägg. Men innan vi skriver för mycket kod, låt oss göra en säkerhetskopia med skriptet vi skrev tidigare, säkerhetskopia. Kör det här skriptet i skalet, vänta några ögonblick, och all kod kommer att säkerhetskopieras till vårt git -förvar.

backup
Att implementera formuläret är relativt enkelt. Vi kommer att importera vårt formulär, lägga till en handlare efter begäran till vyn och spara inlägget i databasen innan vi omdirigerar till samma vy. Vi kan använda den omdirigeringsfunktionen vi redan importerade, och en annan funktion som kallas omvänd för att få URL för visningsmönstret. Vi kommer att fråga detta med strängen "Feed: Feed" eftersom namnområdet för det medföljande mönstret är matning, och vyn kallas också foder.

from feed.forms import PostForm

def feed(request):
    posts = Post.objects.all() # Fråga alla inlägg i databasen hittills
    if request.method == 'POST': # Hantera postförfrågan
        form = PostForm(request.POST) # Skapa en instans av formuläret och spara data på den
        if form.is_valid(): # Validera formuläret
            form.save() # Spara det nya objektet
        return redirect(reverse('feed:feed')) # Omdirigera till samma URL med en GET -begäran
    return render(request, 'feed/feed.html', {
        'form': PostForm(), # Se till att skicka formuläret i sammanhanget så att vi kan göra det.
        'posts': posts,
    })
Nu måste vi uppdatera mallen för att redovisa det nya formuläret. Vi kan göra detta genom att använda
Tagg i HTML och rendering av formuläret i HTML -mallen med en skicka -knapp. Vi kommer också att behöva ett CSRF -token, ett symbol som förhindrar att externa webbplatser publiceras till formuläret utan att först ladda en sida.
 
<!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>
 
Låt oss bryta ner detta. Det finns en ny formklass, ett token, själva formuläret och en skicka -knapp. Ganska enkelt, men när vi tittar på det kanske vi vill få det att se bättre ut. Det fungerar, vi kan publicera nya inlägg med formuläret och de sparas nu i databasen. Det finns några saker som händer här. Vi använder HTML -taggar för att förklara att dokumentet är ett HTML -dokument, vi använder en malltagg ({ % ... %}) för att göra token för formuläret och ett annat, {{…}} för att göra formuläret. Vi har också en slinga för att göra texten med blocktaggar och en malltagg. Blocktaggar är verkligen viktiga eftersom vi kan definiera hur delar av mallen görs med dem, och malltaggar är grunden för hur vi lägger variabler i vår kod. Nu måste vi få vår app att se bättre ut, för nu ser den riktigt grundläggande ut. Vi kan göra detta genom att använda CSS, antingen inline eller i klasser bundna till varje objekt i dokumentet. CSS är riktigt trevligt eftersom det berättar allt på sidan hur det ska se ut,och kan få det att se riktigt bra ut. Det finns några bibliotek som kan göra detta, men min personliga går till är bootstrap. Bootstrap kan laddas ner från deras webbplats,Getbootstrap.com/. När du är där trycker du på knappen för att läsa installationsdokumenten och kopiera koden från avsnittet Inkludera via CDN. Du behöver den här koden högst upp i ditt HTML -dokument, i en tagg som heter Head. Låt oss också gå vidare och skapa en basmall så att vi inte behöver återskapa dessa länkar i varje mall. Gör en ny katalog som kallas mallar med mkdir -mallar och redigera sedan mallar/base.html. Det ska se ut så här:
 
<!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>
 
Se till att kopiera CSS och JavaScript, .CSS- och .JS -filerna, eftersom vi kommer att behöva JavaScript för att göra vår webbplats mer funktionell i framtiden. Låt oss nu återvända till bash -skalet och köra ett snabbt kommando. Kom ihåg att om du någonsin behöver komma åt den virtuella miljön skriver du källkälla VENV/bin/aktivera. Detta låter dig installera Python -paket lokalt på ett sätt som låter Django komma åt dem. För att ge våra former genererade av Django Bootstrap -klasser kommer vi att använda ett Python -paket som heter Crispy Forms. Vi kan ladda ner detta med följande kommando

pip install django-crispy-forms
När detta har installerats, lägg till den i inställningarna.py

INSTALLED_APPS = [
    # ... tidigare kod här
    'crispy_forms',
]
Nu, tillbaka i vår fodermall, kan vi ta bort vissa saker. Låt oss ta bort början och slutet av dokumentet och ersätta det med arv från vår basmall med hjälp av förlängningar och blockdefinitionen. Vi lägger också till en mallfilterimport med last och ett mallfilter till formuläret. Slutligen, låt oss lägga till en bootstrap -klass till knappen på formuläret så att den ser mer ut som en knapp. Det borde se ut så här:
 
{% 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 %}
 
Vacker! Det är en hel del kod redan. Därefter bör vi testa det och se till att vi kan se att allt ser bra ut och också vara säker på att allt fungerar ordentligt. Kör servern enligt tidigare instruktioner och se till att webbplatsen ser ut och fungerar okej. Bra jobb! Du är redo att gå vidare till nästa steg, där vi lägger till användarinloggningsfunktioner med liknande webbadresser, formulär, vyer och mallar. Basmallen är viktig, och vi kommer att fortsätta att ändra den och göra ändringar efter behov, men låt oss för tillfället fokusera på att göra vår webbplats säkrare genom att göra det möjligt för användare att logga in med ett användarnamn och lösenord, och så småningom ännu viktigare information som hjälper till att hålla din app säker och ditt eget konto endast tillgängligt av dig. För att göra detta måste vi använda användarmodellen inbyggd i Django. Användarmodellen är en databasmodell, som vårt inlägg, som kan återges för att logga in en användare på webbplatsen. I framtiden, innan vi distribuerar webbplatsen till Internet, kommer vi att göra detUtöka denna modell med andra modeller som tillskrivs den och bygga ytterligare säkerhetsåtgärder för inloggningen som är resistenta mot phishing. Vi börjar med att använda några inbyggda inloggningsformulär som Django tillhandahåller. Låt oss först skapa en ny app som vi kommer att använda för att göra mallar och vyer för den grundläggande inloggningssidan. Vi kommer också att skapa andra appar för att representera de fortsatta inloggningsutmaningarna för att säkra appen, inklusive en pincode, ansiktsigenkänning, nära fältkommunikation, externa enheter, autentisering av flera faktorer och fingeravtrycksigenkänning. Vi pratade redan om att starta en app. Från vår katalog, inuti den virtuella miljön, passerar du.

python manage.py startapp users
Nu borde vi ha en katalog för den nya appen. Låt oss börja med att skapa en vy i den katalogen som motsvarar användarinloggningen. Django har inbyggt vyer för användarinloggningar, men dessa kommer inte att vara lämpliga för oss eftersom vi behöver en anpassad vy, vilket företrädesvis görs med en definition. I denna vy kommer vi att börja med att kontrollera om en postförfrågan, skicka begäran. Post till en inloggningsform importerad från Django, autentisera användarkontot och logga in användaren innan du omdirigerar dem till vår flödesapp. Lägg till följande kod i användare/visningar

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'] # Få användarnamn och lösenord från postförfrågan
        password = request.POST['password'] # Autentisera användaren
        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()})
Detta är allt du behöver för en grundläggande inloggningsvy. Låt oss nu skapa ett formulär för vyn genom att utöka basmallen. Vi börjar med att skapa en ny katalog för mallar i användarmappen.

mkdir users/templates
mkdir users/templates/users
Nu bör vi kunna redigera användare/mallar/användare/inloggning.html. Medan vi är på det skapar vi en mall för att låta användaren också registrera dig.

nano users/templates/users/login.html
Nu, i mallen,
 
{% 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 %}
 
Detta är grunderna i en inloggningsmall. Det är verkligen precis som den andra mallen i strukturen, men den ser lite annorlunda ut när den görs. Vi kan kopiera den här koden för att bygga en annan mycket liknande mall som heter Register.html, där vi kommer att ändra formuleringen och använda en ny form som vi bygger. Låt oss göra mallen först. Redigera användare/mallar/användare/register.html och lägg till följande 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 %}
 
Låt oss nu bygga ett formulär för vår användarregistrering och gå tillbaka till vyerna innan vi uppgraderar våra användarinloggningar med en modell. Vi kommer att göra detta formulär grundläggande till att börja med, men integrera mer detaljer och säkerhetsfunktioner som avtal och CAPTCHA i framtiden. Redigera formulärerna med Nano -användare/formulär. Ppy och lägg till följande 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']
Så vi har en annan form här, som fungerar ganska enkelt. Det är ett användarregisterformulär med ett användarnamn, e -post och lösenord samt ett bekräftelsesfält. Observera att det här formuläret inte förlänger regelbundna former. Formklassen, det är en modellform som innebär att den har en meta. Ett fält definieras precis detsamma, och klass Meta definierar modellen som formuläret motsvarar resten av informationen som kommer att skrivas till formuläret. Det mesta av detta finns redan i Djangos inbyggda usercreationform, så vi kommer att använda det som grund för klassen (passerad i parentesen). Därefter kommer vi att undersöka vyn för att registrera en användare, nu när vi har ett formulär och en mall. Detta är en Modelform, precis som den i den nya postvyn. Redigera användare/visningar.py och lägg till följande kod:

# ... belopp
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})
Det här är allt vi behöver för att få en användare registrerad, men vi borde ha mer information. Vi vill veta den tid som användaren registrerade, vilken tid de sist var på webbplatsen, lite information om dem, som en biografi, tidszon osv. Vi måste också uppdatera vår fodermodell, posta, för att redogöra för användaren Modell och attributinlägg till varje användare. För att göra det kommer vi att uppdatera modellerna.py i båda apparna. Låt oss börja med att redigera matningsmodellen. Det ska se ut så här nu:

from django.db import models # ... belopp
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') # Lägg till den här raden
    text = models.TextField(default='')
Var uppmärksam på den andra raden som lades till i filen. Detta är en utländsk nyckel, som kommer att tillskriva varje inlägg till en enda användare per inlägg, så vi kan se till att vi sparar inläggen på användare per användare och inget inlägg kan göras utan att tillskriva det till en användare. Vi definierar denna utländska nyckel med den klass som den representerar, ett raderingsargument för att säkerställa att inlägg raderas med användare, noll och tomma argument för att se till att vi kan ta bort användaren vid behov och för att tillgodose bristen på en användare på inlägg som vi redan har skapat och ett relaterat namn, som vi kan använda för att hänvisa till inlägget objekt som användaren skapar. Detta relaterade namn, till skillnad från Post.Author, författaren till inlägget, ger oss användare som publicerade själva inlägget. Vi kan nu få inlägg som en användare gör genom att köra user.posts.all () eller author.posts.all (). Låt oss nu göra våra inloggningar mer motståndskraftiga. Vi kan redan göra vår webbplats mycket mindre sårbar för phishing genom att helt enkelt bedöma antalet gånger vi tillåter en inloggning påWebbplats, detta är ganska enkelt. Låt oss också börja lagra lite information om varje användare innan vi fortsätter att utveckla vår app. Redigera användare/modeller.py, lägg till följande

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='')
Observera att den här modellen är ganska lik postmodellen. Vi har en ytterligare import, tidszon, som gör att vi kan ställa in standardvärden på DateTime -fälten, och vi har också en karaktär och textfält som inlägget. Att använda alla dessa tidsstämplar hjälper oss att säkra webbplatsen och förstå dess användning, och textfälten låter oss ge information om varje användare eller författare på webbplatsen. OneToonefield bör vara den enda mindre överväganden, den uppför sig exakt samma som en föregångare men med endast en per efterföljande modell. På detta sätt har användaren bara en profil, medan de kan ha många inlägg. Låt oss nu förbättra vår inloggning och registrera vyer för att redogöra för profilen. Först redigera användare/visningar. Ppy och fokus på registervyn:

# ... import
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) # Se till att lägga till den här raden för att skapa en profil för användaren
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
Detta skapar helt enkelt en profil för användaren utan att fylla i någon av informationen. Nu vill vi se till att användarkontot inte kan loggas in för ofta, eller åtminstone kan lösenord inte testas för ofta, så låt oss uppdatera inloggningsvyn.

# ... belopp
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(): # Observera att vi nu kontrollerar om användaren kan logga in
            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: # Om inloggningen inte lyckades,
            messages.warning(request, 'Username or password incorrect. Please try again.')
            user = User.objects.filter(username=username).first() # Detta är den del där vi uppdaterar användarprofilen
            if user: 
                profile = user.profile
                profile.can_login = timezone.now() + datetime.timedelta(seconds=15) # Så de kan inte logga in igen i några sekunder
                profile.save()
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
Detta är den grundläggande grundläggande säkerheten. Se till att webbplatsen inte är sårbar för att någon bara försöker alla möjliga lösenordskombinationer, eller till och med några av dem samtidigt. Detta kommer inte att vara frustrerande för den vanliga användaren som känner till sin lösenord och bara loggar in på några enheter, men det kommer att hålla många phishing -robotar ur appen. Observera att vi har lagt till ett IF -uttalande med en variabel, can_login, som borde vara en tid tidigare och uppdatera det med varje misslyckad inloggning med samma användarnamn. På detta sätt kommer en skadlig användare inte att kunna gissa ett lösenord någonstans nära så snabbt. Antalet sekunder i datetime.timedelta () kan också uppdateras, och webbplatsen kommer att vara mer motståndskraftig men ändå något mindre användbar med fler sekunder. Jag rekommenderar 15 att börja med. Kom ihåg att vi byggde ett backup -skript för att spara vårt arbete, så låt oss gå vidare och säkerhetskopiera vad vi hittills har för att se till att vi har sparat allt. Kör kommandot:

sudo backup
Återigen kommer detta att spara ditt arbete hittills. Jag rekommenderar att du kör ofta säkerhetskopiering för att spara ditt arbete, och du kanske till och med vill köra ett säkerhetskopieringsjobb automatiskt. Du kan göra detta med ett Unix -verktyg som heter Cron. För att aktivera detta verktyg, kör följande kommando och ange ditt lösenord:

sudo crontab -e
Om du inte redan har valt alternativ 1 för Nano, bör textredigeraren du redan känner till och bläddra till botten av filen med pilknapparna. Lägg till följande rad:

0 * * * * sudo backup
Cron använder formatet minut, timme, dag i månaden, månaden, veckodagen, där A * eller ett nummer representerar när man ska köra kommandot. Med hjälp av en 0 för minut och * för resten av alternativen kan vi köra ett kommando i den första minuten av varje timme i början av minuten. Detta låter oss säkerhetskopiera koden automatiskt. Alla Crons jobb när de körs med Sudo körs som root, så vi behöver inte skriva in ett lösenord varje timme. För att göra det enklare att säkerhetskopiera vår kod utan att använda ett lösenord, låt oss inaktivera lösenordet för vårt säkerhetskopieringskommando. Vi kommer att göra detta genom att köra följande kommando och ange ett lösenord:

sudo visudo
Låt oss nu bläddra till botten av filen och lägga till en annan rad:

ALL ALL=NOPASSWD: /bin/backup
Detta låter oss köra kommandot "säkerhetskopiering" som alla användare utan lösenord. Formatet för detta är enkelt, bara prefix raden med “All All = nopasswd:/bin/” och slut med kommandot, till exempel/bin/backup, som finns i/usr/bin/. Låt oss börja arbeta med e -post. E -post är verkligen viktigt för webbplatser, eftersom det är ett sätt att hålla en webbplats säkrare, verifiera att användare är riktiga människor och till och med marknadsprodukter eller tjänster till kunderna. Många som ofta internet kontrollerar sin e -post dagligen och får alla möjliga marknadsföringsmeddelanden om produkter och tjänster de är intresserade av. Det finns några alternativ när det gäller att aktivera e -post på en Django -webbplats, och du är välkommen att välja Oavsett vad som fungerar bäst för dig. Först kan du betala för en e -posttjänst som gör att du kan skicka e -post från din domän och kräver minimal kod. Det finns många tjänster som erbjuder detta, till exempel Google Workspace, SendInBlue, Mailgun och mer. Annars är du väl på väg att byggaDin egen e -posttjänst inom din server från grunden. Jag rekommenderar det här alternativet, även om det är mer kod och kan kräva speciell värd. Du kommer inte att kunna starta en e -postserver från din hemdator troligen, så låt oss gå vidare och undersöka konfigurationen och koden för att skicka e -post innan vi startar en server i molnet och skapar vår egen e -postserver inom. Först redigera inställningar.py med följande

nano app/settings.py
Där app är namnet på appen du skapade med StartApp. Lägg till följande rader:

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)
Se till att ändra dessa när du är redo att distribuera din app, vi kommer att besöka detta senare. Inställningen för e -post_Address ska vara e -postmeddelandet du vill skicka från och lösenordet (e -post_host_password) ska ställas in på lösenordet du genererar för servern. Jag laddar lösenordet från en konfigurationsfil för att hålla den utanför koden med följande logik, ovanför dessa rader i inställningar. Py:

import os
import json
with open('/etc/config.json') as config_file:
    config = json.load(config_file)
Sedan har jag skapat en JSON -fil med Config In /etc/Config.json med Nano enligt följande. För att redigera filen:

sudo nano /etc/config.json
Lägg till följande rader:

{
	“EMAIL_HOST_PASSWORD”: “<some password here>”
}
Vi fortsätter att redigera konfigurationsfilen och lägga till alla lösenord och nycklar vi kommer att använda i appen. För nu, låt oss snabbt undersöka hur man skickar e -post med Python. Låt oss först skapa en mall för ett verifierings -e -postmeddelande som vi kan skicka till våra användare och lägga den i användarmallkatalogen. Den här mallen kommer att skrivas i 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>
 
Det här e -postmeddelandet är ganska enkelt. Det tar ett sammanhang av en användare, bas -URL för webbplatsen och ett användar -ID och token som används för att verifiera användarens e -post. Se till att definiera bas -url i inställningar. Gå vidare och lägg till följande rader till app/inställningar.py, nära början.

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

BASE_URL = PROTOCOL + '://' + DOMAIN
Så småningom, när din webbplats är redo för internet och du distribuerar den, vill du definiera din domän som det domännamn du köper för att representera webbplatsen. Detta är namnet som du kommer att skriva i Navbar för att komma åt din webbplats. För tillfället kan du lämna domänen tom eller använda en platshållare. Du vill också ändra webbplatsnamnet till ett namn du vill ge din webbplats, du väljer. Innan vi skickar e -post, låt oss skapa en tokengenerator så att vi kan ha ett kontotoken som aldrig löper ut. Vi kan göra detta genom att bygga och importera ett kontotoken som ser ut som följande. Redigera filen:

nano users/tokens.py
Lägg till följande 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()
Denna grundläggande tokengenerator genererar ett token Vi kan skicka användaren i en URL och användaren kan använda för att verifiera deras e -postmeddelande och aktivera deras konto. Låt oss sedan se hur du skickar ett e -postmeddelande. Redigera användare/e -post.py med NANO.

nano users/email.py
Att skicka verifiering av HTML -e -post kommer att se ut så här:

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)
Detta är ganska enkelt. Vi importerar de funktioner vi behöver för att skicka e -postmeddelandet, göra e -postmeddelandet med mallar och våra inställningar, och sedan definierar vi e -postmeddelandet med mallnamnet och skickar det till användaren med en funktion. Du kommer att märka att vi inte har definierat funktionen för att skicka posten, Send_html_email, ännu, så låt oss skriva detta nedan koden som vi redan har lagt till användare/e -post.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()
Detta är lite mer komplex, och vi är inte redo att köra all denna kod ännu. Lägg märke till att vi definierar en unsub_link, länken som användaren kan använda för att avsluta prenumerationen på våra e -postmeddelanden. Detta är viktigt, eftersom användare kommer att behöva kunna välja bort våra e -postmeddelanden om de inte vill se dem när som helst. Vi lägger också till ett textalternativ till vårt meddelande, som är HTML -meddelandet som har tagits bort från HTML -taggar. Slutligen kontrollerar vi om e -postmeddelandet skickas, och om det inte gjorde det, markerar vi i användarens profil att deras e -post är inte giltig. Låt oss gå tillbaka till användarmodellerna så att vi kan få allt att fungera. Vi måste definiera en funktion för att generera en länk för att avsluta prenumerationen och definiera ett booleskt fält för att markera att användarens e -postmeddelande inte är giltig. Lägg först till följande import till toppen av användare/modeller.py

nano users/models.py

# ...
from django.core.signing import TimestampSigner, BadSignature, SignatureExpired
from django.urls import reverse
Låt oss sedan lägga till funktioner i användarmodellen för att göra token och kontrollera token som används för att aktivera e -postmeddelandet, såväl som fältet för att spara om användaren framgångsrikt får sin e -post. I användare/modeller.py igen, lägg till följande kod i slutet av modellen (intryckt kod)

# ...
    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) # Giltig i 30 dagar
        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,})
Detta är ganska enkelt, vi använder en timestampsigner, som är ett grundläggande kryptografiverktyg, för att skapa ett symbol som kommer att löpa ut efter en viss tid, och vi använder också en annan funktion för att kontrollera om den är giltig. Vi använder dessa symboler två gånger, en gång för att verifiera e -postmeddelandet och en gång för en länk av prenumerationen. Nu när vi har dessa är det sista av det arbete vi behöver göra i utsikten. Inom användare/visningar.

nano users/views.py
Lägg först till följande import. Jag kastade in några extra så att vi inte behöver importera fler föremål igen senare.

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 # Se till att importera funktionen Verifiering E -postmeddelande
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
Du kanske redan har en del av dessa import, men det skadar inte att upprepa dem. Du kommer att behöva importera funktionen Verification E -post, såväl som Account_Activation_Token från användare. Tokens, bland annat import. Lägg till följande kod längst ner i filen:

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)):
        # avsluta prenumerationen
        profile = user.profile
        profile.subscribed = False
        profile.save()
        return render(request, 'users/unsubscribe.html')
    # Annars omdirigera till inloggningssidan
    messages.warning(request,f'Your unsubscribe link has expired. Please log in to unsubscribe.')
    next_url = reverse('users:unsubscribe', kwargs={'username': username, 'token': token,})
    return HttpResponseRedirect('%s?next=%s' % (reverse('login'), next_url))

def activate(request, uidb64, token):
    try:
        uid = force_str(urlsafe_base64_decode(uidb64))
        user = User.objects.get(pk=uid)
    except(TypeError, ValueError, OverflowError, User.DoesNotExist):
        user = None
    ip = get_client_ip(request)
    if user is not None and account_activation_token.check_token(user, token):
        user.profile.email_verified = True
        user.profile.save()
        user.save()
# SendWelcomeMail (begäran, användare)
        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})
Detta är mycket kod. Låt oss bryta ner det. Den första funktionen, ren och enkel, avskriver användaren från e -postlistan. Den andra funktionen aktiverar deras e -post, och du kommer att märka att jag har lagt till en kommenterad funktion, SendWelcomeMail. Du är välkommen att använda en e -postmall och funktionsdefinition för att skicka ett välkomstmeddelande, jag har bara inte gjort det ännu. Den sista funktionen jag kastade in är viktig, eftersom aktiverings -e -postmeddelanden löper ut. Därför kommer vi att behöva återge aktiverings -e -postmeddelandet en del av tiden. Vi kan använda en grundformulär för detta och ringa funktionen för att skicka verifierings -e -postmeddelandet. Innan vi gör detta, låt oss se till att det skickas i första hand genom att lägga till ett funktionssamtal till registervyn. Lägg till den här raden strax före omdirigeringen i registervyn, def register, i användare/vyer.py.

nano users/views.py

# ... (efter) def register (begäran):
            send_verification_email(user)
# ... (före) omdirigering (
Du behöver inte lägga till de första och sista raderna i det kodavsnittet, se bara till att registervyn skickar verifierings -e -postmeddelandet till användaren. Det ska se ut så här:

# ... belopp
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) # Se till att lägga till den här raden!
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
Nu måste vi lägga till ett formulär för att återge aktiverings -e -postmeddelandet. I användare/formulär.py, lägg till följande formulär:

# ... (belopp)
class ResendActivationEmailForm(forms.Form):
    email = forms.EmailField(required=True)
Vi kommer också att behöva en mall som motsvarar detta återbetalningsformulär för e -post. Låt oss lägga till den här mallen i. Redigera filen:

nano users/templates/users/resend_activation.html
Lägg sedan till följande kod i filen.

{% 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 %}
Whew, det är mycket! Nu, när vi distribuerar koden till vår server, kommer vi att kunna skicka HTML -e -post och aktivera användarkonton med ett klick i e -postmeddelandet. Vi kanske också vill skicka ett enkelt välkomstmeddelande, så låt oss se hur vi gör det. Tillbaka i användare/e -post.py, lägg till följande 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)
Vi kommer också att behöva en mall för att göra all denna information. På min webbplats ser mallen ut som nedan, men du är välkommen att formatera den hur du vill.
 
<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>
 
Observera att vi inte har en stängning av kropps- eller HTML -taggar, eftersom vi lägger till dessa när vi lägger till HTML -avskrivningslänken. Dessa är viktiga, men vi vill inte definiera dem två gånger. Så vad är nästa? Vi har kommit långt. Vi borde verkligen vara redo att distribuera webbplatsen till en server. Vi kan lägga till den @login_required dekoratören och göra våra åsikter säkra, ta användarregistreringar, skicka kompatibel e -post och cacheinformation, vilket är grunden för vad en webbplats behöver göra för att förbli relevant. Vi lägger till några fler användbara funktioner och sedan bygger en grund för att distribuera vår kod till en fjärrserver, ställa in en e -postserver, domänkonfiguration och filter för att göra vår webbplats säker och lämplig. Vi behöver också en återställningsvy för lösenord, så låt oss lägga till det riktigt snabbt. Djangos inbyggda lösenordsåterställning är trasig i vissa funktioner, men vi tittar på hur vi skriver vår egen vy, e -postmall, formulär och URL -mönster. Här är hur vyn ser ut, i användare/vyer.py

# ... belopp
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)
Det här formuläret är inbyggt i Django, men vi behöver en mall för att bekräfta återställningen av lösenord, användare/mallar/användare/lösenord_reset_confirm.html
 
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Reset Password</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-info" type="submit">Reset Password</button>
            </div>
        </form>
{% endblock content %}
 
Vi har också en mall för att skicka ett e -postmeddelande om återställning av lösenord, med en enkel form, i användare/mallar/användare/lösenord_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 %}
 
Mallen för själva e -postmeddelandet är enkel, det är en grundläggande HTML -fil som gör en länk för att återställa lösenordet, i användare/mallar/användare/lösenord_reset_email.html. Django tolkar automatiskt den här filen.
 
<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>
 
Vi behöver också ytterligare två mallar. Den första är att bekräfta att e -postmeddelandet har skickats. Visningar för dessa finns redan i Django, så vi behöver bara adressera dem i URLS.py. Denna mall finns på användare/mallar/användare/lösenord_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 %}
 
Och slutligen, för att bekräfta att lösenordsåterställningen är komplett, användare/mallar/användare/lösenord_reset_komplete.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 %}
 
Nu behöver vi URL -mönster för dessa vyer. I användare/url.py, lägg till följande URL -mönster:

urlpatterns = [
    # ... tidigare webbadresser här
    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'),
]
Fyra mallar, det är mycket! Men nu kan vi vara säkra på att kunna återställa användarens lösenord när vi behöver, allt från webbläsaren. Jag förstår att det här är mycket kod. Om det verkar lite över huvudet är det OK. Du kommer att förbättras, din förståelse kommer att förbättras och du kommer att bli mycket mer kompetent med koden mycket snart. Om du är helt förlorad rekommenderar jag att du kommer tillbaka till den här programvaran senare efter att ha arbetat med en självhastig lärande att koda kurs online. Dessa är vanligtvis gratis att komma igång och kommer att vägleda dig genom allt du behöver för att lyckas när du kommer tillbaka till detta projekt. Om du känner att du är redo att fortsätta, läs vidare, nästa kommer vi att täcka att distribuera din kod till en fjärrserver och ställa in en e -postserver, samt automatisera din distribution med BASH så att du alltid kan ställa in ett nytt projekt med Några enkla kommandon. Det sista vi behöver göra innan vi distribuerar till en fjärrserver är att göra vår webbplats lite säkrare. DuLägg märke till att inloggningsvyn endast tar ett användarnamn och lösenord, och det finns ingen autentisering av flera faktorer eller en gång. Detta är en enkel fix, och med samma kod kan vi få vår webbplats att skicka textmeddelanden och till och med vara lyhörda för textmeddelanden som skickas till servern. Till att starta kommer vi att gå tillbaka till användarmodellerna och lägga till en tidsstämpelundersignare som kommer att representera varje inloggning. Vi kommer också att lägga till en unik, roterande identifierare till användarmodellen som kommer att användas för att lägga till extra säkerhet till vår inloggning. Redigera användarmodellerna, användare/modeller.py, lägg till följande

from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
# Se till att importera UUID, tidsstämpelundersignatör och URL -generator (omvänd)
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='')
    # Lägg till den här koden här
    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)

    # Och lägg till den här funktionen
    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) # Giltig i 3 minuter
        except (BadSignature, SignatureExpired):
            return False
        return True
Se till att dina användare/modeller.py ser ut så här, förutom kommentarerna (kod på raderna med #). Genom att bryta ner detta är det enkelt. Vi har några import, en tidsstämpelSigner som är ett kryptografiskt verktyg som kan generera en säker kod och verifiera den för att se till att den är giltig, endast använts en gång och inte äldre än ett visst antal sekunder. Vi använder också en UUID, som är en unik identifierare som identifierar vår användare i signeringen av token och i URL där token skickas till användaren. Vi använder denna grundläggande kryptografi för att bygga en tvåfaktorautentiseringsvy. Innan vi gör något annat, låt oss köra migrationerna så att våra användarmodeller uppdateras. Kör följande kommandon i katalogen med Manage.py för att göra och slutföra migrationerna.

source venv/bin/activate
python manage.py makemigrations && python manage.py migrate
Detta är viktigt eftersom varje gång vi gör ändringar i modellerna måste vi skapa tabellerna och uppdatera databasen med standardvärden innan vi faktiskt kan använda modellerna. Låt oss sedan improvisera vår inloggningsvy för att omdirigera till en sekundär autentiseringsvy. I användare/visningar.

# ... belopp

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(): # Observera att vi nu kontrollerar om användaren kan logga in
            # Ta bort funktionen AUTH_LOGIN
            messages.success(request, 'Your password was accepted. Please continue.')
            if user.profile.mfa_enabled:
                return redirect(user.profile.create_auth_url()) # Observera att vi omdirigerar till en ny URL här
            else: # Om användaren inte använder multifaktorautentisering, logga bara in dem.
                auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
                return redirect('feed:feed')
        else: # Om inloggningen inte lyckades,
            messages.warning(request, 'Username or password incorrect. Please try again.')
            user = User.objects.filter(username=username).first() # Detta är den del där vi uppdaterar användarprofilen
            if user: 
                profile = user.profile
                profile.can_login = timezone.now() + datetime.timedelta(seconds=15) # Så de kan inte logga in igen i några sekunder
                profile.save()
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
Så detta är ganska enkelt, vi har nu ett sätt att omdirigera till vyn tvåfaktor autentisering när vi skapar den. Vi har också en fallback om användaren inte har lagt till ett telefonnummer. Vi lägger till en grundvy för att lägga till ett telefonnummer snart och logga in med ett textmeddelande snart. Först behöver vi ett enkelt sätt att skicka ett textmeddelande från vår kod. För att göra detta kan vi välja mellan ett antal API: er, men det enklaste enligt min mening är Twilio. De erbjuder också bra priser för mindre projekt samt bulkrabatter. Skapa ett konto på twilio.com, fyll i några detaljer om ditt projekt, köpa ett telefonnummer och kopiera dina API -nycklar till dina inställningar. Lägg sedan till den här koden under en ny fil, användare/sms.py.

nano users/sms.py

# Importera alla nödvändiga paket
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

# Den här koden skickar texten med 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())

# En hjälpfunktion för att få ett nummer med så många siffror
def get_num_length(num, length):
    n = ''
    for x in range(length):
        n = n + str(num)
    return int(n)

# Skicka texten för att verifiera användaren
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)))

# Skicka en användare någon text med den här funktionen
def send_user_text(user, text):
    send_text(user.profile.phone_number, text)

# Validera koden med den här funktionen
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

# Validera tiden
def check_verification_time(user):
    result = user.profile.mfa_code_expires > timezone.now()
    return result
Se till att ändra dina inställningar på lämpligt sätt och lägga till dessa rader med dina nycklar:

# Se till att kopiera dessa från din Twilio -instrumentpanel
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 # Antalet minuter TFA -sidan är aktivt när den är inställda
Först kommer vi att behöva formulär för våra tvåfaktorautentiseringsvyer. Redigera användare/Forms.py, lägg till följande kod.

# ... belopp
from django import forms

# Ett formulär för att ange vårt telefonnummer
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

# En form för autentisation
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.'
    }
Låt oss sedan skapa vyerna i användare/vyer.py

# ... belopp
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})
Vi kommer också att behöva mallar för båda dessa vyer. Låt oss lägga till MFA -mallen först.

nano users/templates/users/mfa.html
Lägg till denna HTML -kod i mallen
 
{% 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 %}
 
Detta är ganska självförklarande. Formuläret skickar antingen en kod eller en tom kod, så kommer du att märka att vi skickar koden om vi får en tom kod. Sedan har vi bara två skicka knappar, och på det här sättet kan vi skicka koden med endera knappen. Därefter lägger vi till ett enkelt formulär för att lägga till ett telefonnummer.

nano users/templates/users/mfa_onboarding.html
Lägg till följande 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 %}
 
Det här formuläret är mycket enklare, det gör bara telefonnummerformuläret vi skapade och låter användaren lägga till ett telefonnummer. Det här ser riktigt bra ut! Så länge allt är korrekt inställt, bör vi kunna skicka meddelanden och logga in användaren med sitt telefonnummer så snart vi lägger till URL -mönstren. Det sista vi behöver ställa in är en profilvy så att vi kan se till att användaren kan ändra sitt telefonnummer utan att vara inloggad. Dessutom vill vi så småningom lägga till ett "Stop to Quit" -alternativ, så användaren kan sms "Stop" för att välja bort framtida textmeddelanden. Låt oss lägga till en profilvy till användarna/vyer.py. Denna vy kommer att uppdatera användarens bio, e -post, användarnamn och telefonnummer samt låta oss möjliggöra multifaktorautentisering. Först kommer vi att behöva ytterligare två formulär i användare/form.py

# ... belopp
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']
Därefter kan vi skapa en vy för att använda båda dessa formulär. Redigera användare/visningar. Ppy och lägg till vyn.

# Lägg till dessa 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)
Vi behöver också en mall för den här vyn.

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 %}
 
Du kommer att märka att detta är en ganska enkel form, men har lite JavaScript i sig som automatiskt publicerar innehållet i formuläret när de uppdateras. Detta är användbart att ha, så du kan göra redigeringar utan att behöva trycka på skicka varje gång. Därefter behöver vi URL: er som representerar alla dessa vyer i användarnas URL -mönster. Redigera användare/urls.py och lägg till den här koden:

# ... tidigare kod, import
from django.urls import path
from . import views

app_name='users'

urlpatterns = [
# ... URL -mönster som vi tidigare angett, lägg till de nästa tre raderna
    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'),
]
Nu är det en bra tid att testa vårt projekt. Men först, låt oss köra en annan säkerhetskopia.

backup
Och kör servern. Innan vi distribuerar till en Linux -server är det en bra idé att aktivera två faktorautentisering på kontot. Vi kommer att göra detta till vår profil -URL,/användare/profil/, och kontrollera rutan för att aktivera autentisering efter att ha angett vårt telefonnummer och sedan skickat formuläret.

python manage.py runserver localhost:8000
Besök webbsidan genom att gå till din webbläsare, jag använder Google Chrome i det här exemplet och går in på URL -https: // localhost: 8000/konton/profil/ Du kommer att kunna logga in vid behov och aktivera tvåfaktorautentisering. Detta projekt behöver en server för att köras så att den verkligen kan skicka e -post. Men först behöver vi ett sätt att se fel. Du kommer att märka att om du kör servern i felsökningsläge, med inställningar. Debug lika med TRUE, visar servern fel automatiskt. För att visa fel utan att använda felsökningsläge, som är osäkert på en produktionsserver, bör vi lägga till en vy för det. De viktigaste felen vi behöver för att kunna hantera är: Fel 500 - Ett problem med vår kod Fel 404 - En sida som inte hittades (trasig URL) Fel 403 - Ett tillstånd nekat fel Låt oss lägga till en ny app för att hantera dessa fel, kallade fel.

python manage.py startapp errors
Lägg till detta i inställningarna.

handler404 = 'errors.views.handler404'
handler500 = 'errors.views.handler500'
handler403 = 'errors.views.handler403'
Detta är allt vi behöver förutom felvyer, mallar och lite mellanprogram. Låt oss definiera dem som så:

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

# Skapa dina åsikter här.
@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.'})
Låt oss sedan definiera mellanprogrammet för att hantera dessa fel. Vi kommer att göra detta genom att först lägga till middleware_classes i inställningar.py, med namnet på vår mellanprogram.

MIDDLEWARE_CLASSES = [
    # ... Tidigare mellanprogram
    'errors.middleware.ExceptionVerboseMiddleware,
]
Låt oss sedan lägga till mellanprogrammet.

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.')
Vi lägger till en funktion för att få det aktuella undantaget genom att använda en trådlokal, vilket hjälper oss att spåra eventuella fel i vår kod. När det gäller mallar behöver vi bara en, eftersom vi definierar titeln dynamiskt i vyn. Mallen behöver bara göra titeln och "Trace", vår felback från sammanhanget.

nano errors/templates/errors/error.html
 
{% extends 'base.html' %}
{% block content %}
<h1>{{ pagetitle }}</h1>
<p>{{ trace }}</p>
{% endblock %}
 
Detta är vår enklaste mall ännu, men det är så lätt det är att se felen i vårt projekt. Låt oss sedan inaktivera felsökning i inställningar.

nano app/settings.py
Hitta den här raden där den är inställd på sant och ändra den till falsk

DEBUG = False
Gå vidare och säkerhetskopiera appen nu. Vi är redo att distribuera till en fjärr Linux -server och fortsätta lägga till funktioner därifrån.

sudo backup
Innan vi publicerar den här koden till en server bör vi överväga att det kan finnas några problem med koden. Beroende på ärendet kommer webbplatser som accepterar information som publiceras på dem att ha problem med att skräppost publiceras och svårigheter att ta bort skräpposten. Detta bör inte hända omedelbart, men om det händer kommer vi senare att undersöka hur man automatiskt kan moderera skräppost på webbplatsen och göra det tuffare för robotar att komma åt webbplatsen, tillsammans med hur man inaktiverar användarkonton och verifierar en användares identitet med En skanning av deras ID eller en biometrisk skanning, som ett fingeravtryck eller ansiktsigenkänning. När man tittar på exemplet med flera faktorer som vi undersökte, i produktionen kan saker vara annorlunda. Lägg märke till hur vi är hastighetsbegränsande inloggningar och löper ut tokens. Om robotar har tillgång till en webbplats kan två faktorautentisering vara svårare eftersom de kan ange koder samtidigt som användaren är. För att bekämpa detta, låt oss använda en modell i användarmodellerna och förklara hur vi interagerar med webbplatsen när vi ärAutentiserar med hjälp av multifaktorautentisering med ett telefonnummer. Vi kommer också att lägga till ett alternativ för att autentisera med e -post. Börja med att redigera användarmodellerna med

nano users/models.py
Det här är hur modellen vi lägger till bör se ut. Vi behöver inga metoder, bara variabler för att lagra ett ID, användaren, tidsstämpeln, utgången, längden och försöken mot eutentisering av flera faktorer (en kod som 123456 skickas till en telefon eller e -post).

# Ett grundläggande token som används för att logga in på webbplatsen
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)
Låt oss också lägga till ett privilegium till vår användare, och vi kommer att ställa in det manuellt för nu, innan vi så småningom migrerar till att anlita privilegierade användare automatiskt. I användarmodellerna lägg till den här raden i profilen:

    vendor = models.BooleanField(default=False)
Som med alla ändringar i databasen måste vi göra migrationer och migrera databasen när vi redigerar en modeller.py -fil i Django. Kom ihåg att för att göra detta använder vi källan först (om det inte har använts redan sedan terminalen var öppen) och sedan python hanterar.py för att göra migrationerna och migrera.

cd project-directory-you-named # (vid behov)
source venv/bin/activate
python manage.py makemigrations && python manage.py migrate
För tillfället kan du få alla konton du har skapat som leverantörer genom att använda skalet.

python manage.py shell
from users.models import Profile
p = Profile.objects.get(user__username='Charlotte')
p.vendor = True
p.save()
exit()
Låt oss nu utveckla vår autentiseringsvy för flera faktorer för att använda detta token. Först måste vi modifiera våra MFA -hjälperverktyg. Med 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

# Autentisera användaren med sin e -post eller telefonnummer
def mfa(request, username, usertoken):
    token = MFAToken.objects.filter(uid=username, expires__gt=timezone.now() + datetime.timedelta(seconds=30)).order_by('-timestamp').last() # Filtrera tokenet med värdet som passeras i URL: n (en 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)) # Om den här sessionen inte har skapats, skapa den
    user = User.objects.filter(id=token.user.id).first() # Få användaren från token
    if not user and request.user.is_authenticated: return redirect(reverse('feed:home')) # Om de redan är autentiserade, logga in dem
    if not user: raise PermissionDenied() # Förneka om ingen användare hittades
    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): # Kontrollera Auth Token
        auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Logga in användaren om de inte redan är inloggade
        user.profile.mfa_expires = timezone.now() + datetime.timedelta(minutes=settings.LOGIN_VALID_MINUTES) # Ställ in en utgång på deras autentisering av flera faktorer
        user.profile.save()
        return HttpResponseRedirect(next if next != '' else reverse('landing:landing')) # Omdirigera användaren till nästa sida
    if not user.profile.mfa_enabled: # Kontrollera om MFA är aktiverad
        if not check_verification_time(user, token): # Kontrollera tiden
            user.profile.mfa_enabled = False # Rensa telefonnumret
            user.profile.enable_two_factor_authentication = True # Aktivera MFA
            user.profile.phone_number = '+1' # Inaktivera telefonnumret
            user.profile.save() # Spara profilen
            auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Logga in användaren om deras MFA inte är aktiverad
            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): # Om begäran är en postförfrågan
        form = TfaForm(request.POST) # Instansera formuläret
        code = str(form.data.get('code', None)) # Få koden
        if code and code != '' and code != None: # Se till att den inte är tom
            token_validated = user.profile.check_auth_token(usertoken) # Kontrollera Auth Token
            p = user.profile
            is_verified = check_verification_code(user, token, code) # Kontrollera koden
            p.mfa_authenticated = is_verified
            if token_validated: # Om allt
                if is_verified: # Är i ordning
                    user.profile.mfa_enabled = True # Aktivera MFA (om inte redan är aktiverad)
                    user.profile.save()
                    auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Logga in användaren
                    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(): # Bygg en queryString för nästa parameter (om någon)
                        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) # Dirigera om
                    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: # Om token var ogiltig
                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: # Om det fanns för många försök
                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): # Skicka e -postmeddelandet (eller text)
                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('/'))
    # Gör formuläret (för GET -förfrågningar)
    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'})
När vi lägger till i den här koden, se till att importera funktionen för att skicka ett e -postmeddelande. Överst i filen, användarens visningar (med annan import), lägg till

from .mfa import send_verification_email as send_mfa_verification_email
Nu måste vi skriva den funktionen innan något av detta kommer att fungera. Det bör utöka vår skicka e -postfunktion och helt enkelt skicka ett e -postmeddelande till användaren med verifieringskoden.

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))
Så allt fungerar bra, nu har vi ett autentiseringssystem med flera faktorer som beror på ett telefonnummer eller e -post för att logga in. Men vi behöver också ett sätt att ta bort, eller åtminstone dölja användare som inte samarbetar med våra villkor. Dessa kan vara spammare, robotar eller alla som inte betyder bra för vårt arbete. Ta en titt på en vy jag har för att övervaka användare på min webbplats:

# belopp
from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import user_passes_test
from .tests import is_superuser_or_vendor # Vi måste skapa detta test

@login_required
@user_passes_test(is_superuser_or_vendor)
def users(request):
    # Få lista över användare
    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', { # Returnera användare i en mall
        'title': 'All Accounts',
        'users': User.objects.all(),
        'new_today': new_today,
        'new_this_month': new_this_month,
        'subscribers': subscribers
    })
Observera att den här koden använder ett test, vi måste förklara detta test i en test.py -fil och importera den. Redigera användare/test.py, låt oss skapa testet.

def is_superuser_or_vendor(user):
    return user.profile.vendor or user.is_superuser
Detta är i samband med användarna/användarna.html -mallen, som ser ut så här:
 
{% 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 %}
 
Observera att mallen innehåller en annan mall, användare/_user.html. När du använder en mall som har en subtemplatta och inte använder förlängningar, är det en bra idé att lägga till en understreck (_) innan filens namn för att förlänga för att skilja mallar. Observera att detta är mycket Jinja, du kanske inte har alla dessa variabler definierade. Men så ser min kod ut.
 
{% 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>
 
Vi behöver också en annan subtemplatta, Toggle_active.html. Den här mallen bör vara ett formulär som gör att vi kan växla om en användare är aktiv.
 
<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>
 
Vi kommer också att behöva lägga till en vy för att växla användaraktivitet och lämpliga URL -mönster. Medan vi är på det, låt oss lägga till en vy för att ta bort en användare om vi behöver det.

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


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

class UserDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    model = User
    success_url = '/' # Omdirigeringen av framgångs -URL
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        return context

    def test_func(self): # Testa om användaren är superanvändare och har tillåtelse att ta bort
        user = self.get_object()
        if self.request.user != user and self.request.user.is_superuser:
            return True
        return False
Även om detta är praktiskt vid behov, bör du ta bort en användare inte vara nödvändig för det mesta, kan vi bara växla synligheten för användare som besöker webbplatsen om vi behöver avfärda dem. URL -mönstren som vi tilllade ser ut så här. Redigera användare/urls.py med nano och lägg till dessa rader:

nano users/urls.py
Linjerna bör gå i listan över sökvägar i användarvyerna, före slutet "]" men efter början "[".

# ...
    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'),
# ...
Se nu till att säkerhetskopiera webbplatsen så att du kan ladda ner den på webbservern vi kommer att fortsätta arbeta med. Från kommandoraden,

sudo backup
Nu säkerhetskopieras vår webbplats. Så nu har vi några fler användbara funktioner. Men hur är det med den stora bilden här? Den här koden är fortfarande inte tillgänglig från Internet, vi har ingen e -postserver ännu, och vi måste utöka vår app för att inkludera omfattande verifieringsprocess samt smidiga layouter för att hjälpa oss att utforska webbplatsen, tillsammans med säkra protokoll för att autentisera privilegierade användare . Vi kommer till allt detta. Det viktigaste för nu kommer bara att få den här koden online, vilket vi kan göra med bara några rader med bash på en Ubuntu -server. Du kommer dock att behöva hyra en server för detta, såvida du inte har en server hemma och ett affärsinternetabonnemang som låter dig öppna portar. Jag driver personligen min webbplats på en HP Z440 som är installerad i min lägenhet, men det är vanligtvis mycket billigare för grundläggande behov för att hyra en virtuell privat server (VPS). Tänk på att koden vi kör nu är relativt tunn, den måste underhållas och förbättras innan vi ärRedo att använda det vi har för att bygga en produkt. Se till att vara försiktig med vad du gör med Internet, se till att om du distribuerar den här webbplatsen offentligt på webben på en Linux -server, har du en plan för att blockera oönskade interaktioner med din webbplats. Detta kommer sannolikt inte att vara ett problem till en början, men vi kommer att undersöka en mängd olika lösningar för att bekämpa detta, inklusive maskininlärning, konstgjord intelligens och datorvision. När det blir ett problem, titta vidare i den här texten efter en lösning. När det gäller att hyra en VPS finns det många platser du kan gå. Google Cloud har VPS -servrar, Ionos, Kamatera, Amazon AWS och fler leverantörer erbjuder molnserverlösningar som passar våra behov. Du måste klicka igenom deras formulär och välja en plan för att komma igång. Du kan gå med en grundläggande plan med vilken leverantör som helst, men se till att leverantören låter dig öppna portpost -serverportar för att skicka e -post (detta ska vara port 587 och port 25), vissa leverantörer blockerar dessa portar. Hittills har jag haftEST -erfarenhet med Ionos och Kamatera, båda kommer att göra det möjligt för mig att skicka obegränsad e -post och deras prissättning är ganska billig. Du kommer att ansluta till din nya server över ett protokoll som heter SSH eller Secure Shell, som gör att du kan gränssnitt på distans med servern exakt som din persondator, från din persondator. När du ställer in servern kommer värdleverantören troligen att be dig lägga till en SSH -nyckel, eller så ger de dig ett användarnamn och lösenord. SSH -tangenten är hur du loggar in på servern från kommandoraden för att redigera koden. Använd alternativen nedan SSH-Keygen för att generera en SSH

ssh-keygen
Spara filen och skriva över den om du behöver, det är bra att rotera dina SSH -nycklar om du inte redan har gjort det. Nu kan du använda följande kommando för att se din SSH -nyckel. Du vill kopiera den till din fjärrserver så att du kan använda den för att autentisera.

cat ~/.ssh/id_rsa.pub
Om du inte kunde se en SSH-nyckel när du skriver det kommandot (en lång rad siffror och bokstäver som börjar med "SSH-RSA AAA") kan du försöka generera en RSA-nyckel (de är säkrare, så jag rekommenderar att använda dem .) Följande kod genererar en 4096 -bitars RSA SSH -nyckel.

ssh-keygen -t rsa -b 4096
Skapa en VPS som kör Ubuntu, men du planerar att göra detta. När du har skapat en VPS genom att klicka igenom formulärerna på leverantörens webbplats (kamatera.com, jonos.com eller liknande), vill du logga in. För att göra detta, använd SSH -kommandot med din IP -adress (adressen Det ser ut som xx.xx.xx.xx). Du måste också vara känslig för standardanvändarnamnet på servern vi skapade, till exempel Ubuntu.

ssh ubuntu@XX.XX.XX.XX
Du kan bli ombedd om ett lösenord, om du blir ombedd om ett lösenord, ange det i. Vi kommer inte att använda standardanvändarnamnet, så låt oss börja med att skapa en ny användare och lägga till en SSH -nyckel till deras konto. Låt oss börja med att lägga till en ny SSHD_Config -fil, som berättar för servern hur man använder SSH.

nano sshd_config

# Detta är SSHD-serverns systemomfattande konfigurationsfil.  Se
# sshd_config (5) för mer information.

# Denna SSHD sammanställdes med sökväg =/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/spel

# Den strategi som används för alternativ i standard SSHD_CONFIG levereras med
# OpenSSH är att specificera alternativ med sitt standardvärde där
# möjligt, men lämna dem kommenterade.  Okommenterade alternativ åsidosätter
# Standardvärde.

# Hamn 22
# Adressfamiljen
# Listadress 0.0.0.0
# Lyssna Adress ::

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

# Ciffer och nyckel
# Rekeylimit standard Inga

# Skogsavverkning
# Syslogfacilitet
# LogLevel Info

# Autentisering:

# LogringRacetime 2m
# Turarootlogin förbjuder passering
# StrictModes Ja
# Maxauthtries 6
# Maxessioner 10

PubkeyAuthentication yes

# Förvänta dig .ssh/auktoriserad_keys2 att bortse från som standard i framtiden.
AuthorizedKeysFile	.ssh/authorized_keys .ssh/authorized_keys2

# Auktoriserade PRICIPALSFILE INGEN

# AuktoriseradeKeyscommand ingen
# AuktoriseradeKeysCommandUser ingen

# För att detta ska fungera kommer du också att behöva värdnycklar i/etc/ssh/ssh_nokh_hosts
# HostbasedAuthentication nr
# Ändra till ja om du inte litar på ~/.ssh/känd_hostar för
# HostbasedAuthentication
# IgnoreUserChickedHosts No
# Läs inte användarens ~/.rhosts och ~/.shosts -filer
# Ignorerhosts ja

# För att inaktivera Tunneled Clear Text -lösenord, ändra till NO här!
PasswordAuthentication no
# TillåtetPasswords nr

# Ändra till ja för att möjliggöra lösenord för utmaningssvar (se upp problem med
# några PAM -moduler och trådar)
KbdInteractiveAuthentication no

# Kerberos -alternativ
# Kerberosauthentication nr
# KerberosorlocalPasswd Ja
# Kerberosticketcleanup ja
# Kerberoscotted Rod No

# GSSAPI -alternativ
# Gssapiauthentication nr
# Gssapicleanupcredentials ja
# GSSAPISTRICTACECEPTORCHECK JA
# GSSAPIKEYEXCHANGE NR

# Ställ in detta på 'Ja' för att möjliggöra PAM -autentisering, kontobehandling,
# och sessionbehandling. Om detta är aktiverat kommer PAM -autentisering att göra
# tillåtas genom KBDinteractiveAuthentication och
# PASSIDERAuthentication.  Beroende på din PAM -konfiguration,
# PAM -autentisering via KBDinteractiveAuthentication kan kringgå
# Inställningen av "PermoRootlogin Wouder-Password".
# Om du bara vill att PAM -konto och sessionskontroller ska köras utan
# PAM -autentisering, aktivera sedan detta men ställ in PasswordAuthentication
# och kbdinteractiveauthentication till 'nej'.
UsePAM yes

# TillåterAgentForing Ja
# Tillåtet föråtelse av ja
# GatewayPorts nr
X11Forwarding yes
# X11DisplayOffset 10
# X11uselocalhost ja
# Tillåtet ja
PrintMotd no
# Printlastlog ja
# Tcpkeepalive ja
# Tillåtet miljö i
# Kompression försenad
# Klientens intervall 0
# ClientalIVECOUNTMAX 3
# Begagnade
# Pidfile /run/sshd.pid
# Maxstartups 10: 30: 100
# Pemittunl nr
# ChrootDirectory Ingen
# Versionstillägg Inga

# Ingen standardbannerväg
Banner /etc/banner

# Låt kunden passera lokala variabler variabler
AcceptEnv LANG LC_*

# åsidosätta standard för inga delsystem
Subsystem	sftp	/usr/lib/openssh/sftp-server

# Exempel på övergripande inställningar per användare
# Matcha användare anoncvs
# X11Forering nr
# Tillåtet avwpforing nr
# Tillåtet i
# ForCecommand CVS -server
PermitRootLogin no
Kom ihåg att ctrl+x och y för att spara filen. Låt oss sedan skriva ett grundläggande skript som heter Initialize (allt i standardkatalogen för vår användare).

nano initialize
Lägg till dessa rader i filen, ersättaMed din SSH -nyckel hittade du med 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
För att leda dig genom den här filen, låt oss starta rad för rad. Den första raden berättar för kompilatorn att detta är ett Bash -skript. Sedan installerar vi beroenden, kopierar sshd_config till rätt katalog, startar om SSH, genererar SSH -nycklar för root, lägger till användarens team "(du kan välja ett namn du gillar för detta, använd adduser -kommandot med deras namn och inaktiverade lösenord för lösenord för nu). Vi lägger också till team till sudo -gruppen, genererar sin SSH -nyckel, lägger till vår nyckel till auktoriserade nycklar och deras också och skriver ut sin nyckel. Den här nya användaren kommer att vara hur vi loggar in på webbplatsen. Gå vidare och öppna upp servern i en ny terminal.

ssh team@XX.XX.XX.XX
Du borde inte behöva ett lösenord den här gången, eftersom du har en SSH -nyckel. Vi har också inaktiverat inloggning med lösenord för att hålla webbplatsen säkrare. Nu startar den här servern helt tom utan information om den. Låt oss börja med att klona vårt projekt från Git så att vi kan ladda ner och köra det på fjärrmaskinen. På fjärrservern ansluten via SSH skriver du först din SSH -nyckel:

cat ~/.ssh/id_rsa.pub
Klistra sedan in denna nyckel i Git -inställningarna som vi gjorde tidigare för att ställa in vårt Git -förvar. Vi kan nu klona vårt projekt direkt till servern. Se till att du har säkerhetskopierat projektet lokalt så att det är på GIT -servern att ladda ner.

git clone git://github.com/you/yourproject.git
Perfekt. Nu är alla filerna här. Vi kan se dem med LS

ls
Låt oss nu börja ställa in servern. Först kopiera din projektkatalog till ett enkelt, minnesvärt namn som vi kommer att använda för projektet.

cp -r yourproject whatyoucalledit
Där "WhatyoucallEdit" är det nya namnet på ditt projekt. Därefter måste vi bygga ett grundläggande verktyg för att ställa in servern. Vi kommer att spara detta verktyg och använda det i framtiden. För att bygga detta verktyg, låt oss skapa en användarbinär för att definiera hur vi redigerar ett skript. Redigera, redigera/usr/bin/ascript

sudo nano /usr/bin/ascript
Se till att använda sudo där så att du har behörigheter för att redigera filen. Lägg till dessa rader i filen:

# ! / 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
Kom ihåg att detta skript tar ett argument, skriptnamnet, som $ 1. Först kontrollerar den om filen finns, eller på annat sätt skapar den, lägger till den första raden för att förklara skriptet är bash, ändrar sina behörigheter, redigerar den och lägger till sitt namn till /etc /Askript som låter oss lagra namnen på skripten vi skapar. Om filen redan finns, ändra helt enkelt behörigheter och redigera den. Spara filen, så kommer vi att ändra sina behörigheter. Så länge vi använder det här skriptet behöver vi inte göra det igen.

sudo chmod a+x /usr/bin/ascript
Perfekt. Låt oss nu skapa ett skript som heter Setup. Först för att inte överväldiga dig, utan ta en titt på hur mitt installationsskript ser ut. Vi kommer att gå igenom hur det här skriptet ska se ut i ditt projekt, du behöver inte allt i mitt manus att börja med.

# ! / BIN / BASH
SECONDS=0
PYTHON_VERSION=3.12
echo "femmebabe installer initialized."
# sudo chmod a+x scripts/usersetup
# ./Scripts/usersetup
#  ssh-keygen
# Projektkatal
DIR="/home/team/femmebabe"
USER="team"
# Loggkommandon
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
# Uppdatera och installera
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
# Aktivera Clamav -antivirus
echo "Starting antivirus"
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Set HostName
echo "127.0.0.1 femmebabe" | sudo tee -a /etc/hosts
sudo hostnamectl set-hostname localhost
# Inställningar 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;"
# Installation av säkerhetskopieringsdatabas
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
# Inaktiverade 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
# Installera 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
# Inställning 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
# Skapa 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
# Installera virtuealenv
cd $DIR
echo "Creating virtual environment"
python -m venv venv
source venv/bin/activate
# Få och bygga beroenden
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
# Ställ in brandväggsregler
cd $DIR
# Installera PYPI -beroenden
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 Install OpenCV-Python == 4.5.5.64
# PIP Install OpenCV-Contrib-Python == 4.5.5.64
pip3 install --upgrade opencv-python-headless
pip3 uninstall channels
pip3 uninstall daphne
pip3 install channels["daphne"]
pip3 install Pillow==9.5.0
pip3 install librosa
pip3 install -U 'Twisted[tls,http2]'
pip3 install --upgrade certifi requests urllib3 numpy oauthlib twisted pyjwt sqlparse cryptography astral webauthn docbarcodes pdf417 deepface --no-cache-dir
pip3 install tensorflow==2.15.1
# Installera 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
# Kör certbot
sudo certbot --apache --non-interactive --agree-tos --domains femmebabe.com --email jasper.camber.holton@gmail.com
# Ladda om e -postserver
sudo systemctl restart opendkim postfix dovecot
# Exemplar
# sudo cp /etc/letsencrypt/live/femmebabe.com/privkey.pem privkey.pem
# sudo cp /etc/lettesencrypt/live/femmebabe.com/cert.pem cert.pem
# Lappa
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"
# Ställ in användarinställningar
sudo gpasswd -a www-data users
# Ange behörighet
echo "Setting permissions"
sudo chown -R team:users cache/
sudo chmod a+rwx -R cache/
# sudo chown -r team: användare/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: användare 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
# Kopiera konfiguration och ange behörigheter
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
# Databasinställning
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"
# Injicera PAM -konfigurering och ta bort felaktigt SSH -konfiguration
# sudo sed -i '' -e '$ d' /tc/pam.d/sshd
# Sudo sed -i '' -och $ 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
# Kopiera fackskript och ställa in behörigheter
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
# Ladda om och aktivera tjänster
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
# Aktivera Apache -moduler
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
# Inaktivera standardwebbplatsen
sudo a2dissite 000-default
sudo a2dissite 000-default-le-ssl
# Aktivera för webbplatsen
sudo a2ensite femmebabe-le-ssl
# Ladda om Daemon och starta om Apache, Postfix och OpenDkim
sudo systemctl daemon-reload
sudo systemctl restart apache2
sudo systemctl restart opendkim postfix
sudo systemctl start daphne
# Ange behörighet
sudo chown -R :www-data /var/www/
sudo chown -R :www-data /var/www/.deepface
# Bytkonfiguration
echo "Allocating swap, this may take a while"
sudo swapoff /swapfile
sudo rm /swapfile
sudo fallocate -l 8G /swapfile
sudo dd if=/dev/zero of=/swapfile bs=1024 count=8388608
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo "/swapfile swap swap defaults 0 0" | sudo tee -a /etc/fstab
sudo swapon --show
# Init bildtexter
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
# Inställningsgit
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
# Visa IPv6 och OpenDkim för domänkonfiguration
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}'
# Installera slutförd
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."
Det är mycket installation! Kort sagt, den här koden loggar kommandon, konfigurerar nano och git, kopierar över filer, laddar ner och installerar ubuntu apt -paket, pythonberoende, konfigurerar postfix, konfigurerar postgresql (databaservern) och laddar databasen, konfigurerar UFW (en ofullständig brandmall), Inaktiverar iptables, laddar ner ett antivirus, gör kataloger, klonberoenden, installerar certifikat och ställer in servern, installerar konfiguration, startar och möjliggör SVAR, tilldelar byte, ställer in behörigheter och skriver ut IP, IPv6 -adressen och OpenDkim Key. Ganska enkelt, men det ser ut som mycket kod. Vi behöver inte mycket av detta eftersom vi inte har beroenden, vi använder inte selleri, selleribeat eller daphne, men vi kommer att installera några av dem ändå för att komma igång. Lägg märke till att den här koden har en domän som deklareras flera gånger. Vi kommer också att behöva köpa ett domännamn (som är en liten årlig avgift). Jag rekommenderar Squarespace för att köpa en domän, deras layout ärintuitivt och lätt att använda. Du kan köpa valfri domän som du väljer, men jag använder domänen femmebabe.com i det här exemplet. När du har köpt en domän, gå till Squarespace DNS -konfigurationspanelen och lägg till en A -post som pekar din domän till servern med IP -adress. Det ska se ut så här: @ A xx.xx.xx.xx Med @ operatören som värd, vilket betyder att alla underdomäner under denna domän och rotdomänen kommer alla att omdirigera till servern. Det finns fler poster att förklara, men vi kan gå vidare till dessa när vi är redo att skicka e -post. Tänk på att det kan ta flera dagar innan du lyckas skicka e -post från servern. DNS -poster som vi ställer in kommer att ta tid att föröka sig. Hur som helst, den enda posten vi behöver för att starta är en A -skiva. Så nu kan vi fylla i skriptet nedan enligt vårt projekt och köra det. Låt oss börja med ett mindre installationsskript för att bara installera vad vi behöver för en grundläggande framsteg. Vi kommer inte att använda så många beroenden eller PostgreSQL ännu, vi kommer baraUpp en grundläggande HTTP -server och oroa dig för att certifiera den när det är gjort. Kom ihåg att för att få ett HTTPS -certifikat och köra servern säkert måste vi köpa en domän tillsammans med Rent A Server. För tillfället, ersätt "team" i den här filen med namnet på din användare, "dir" med katalogen för ditt projekt och leverera din e -post och domän i <> -taggarna. Innan vi kör den här koden måste vi dessutom ändra inställningarna till brandväggen som värdleverantören stöder, om någon. Vanligtvis finns detta på fliken "Networks" i din värdleverantör, eller om du är självhosting, är det i avsnittet "port vidarebefordran" i din router. Du kommer också att vilja ställa in en statisk IP via din router med adressen till din servermaskin om du använder självhotell. Du måste öppna följande portar för läs-/skrivåtkomst. 22 (SSH) 25 (post) 587 (Mail) 110 (Mail Client) 80 (http) 443

# ! / BIN / BASH
SECONDS=0
PYTHON_VERSION=3.12
echo "femmebabe installer initialized."
DIR="/home/team/<yourproject>"
USER="team"
# Loggkommandon
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
# Uppdatera och installera
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
# Aktivera Clamav -antivirus
echo "Starting antivirus"
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Set HostName
echo "127.0.0.1 femmebabe" | sudo tee -a /etc/hosts
sudo hostnamectl set-hostname femmebabe
# Installation av säkerhetskopieringsdatabas
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
# Inaktiverade 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
# Installera virtuealenv
cd $DIR
echo "Creating virtual environment"
python -m venv venv
source venv/bin/activate
pip3 install -r requirements.txt
# Installera 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
# Kör certbot
sudo certbot --apache --non-interactive --agree-tos --domains femmebabe.com --email <youremail>@gmail.com
# Ställ in användarinställningar
sudo gpasswd -a www-data users
# Ange behörighet
echo "Setting permissions"
sudo chown -R team:users cache/
sudo chmod a+rwx -R cache/
# sudo chown -r team: användare/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 ./
# Ladda om och aktivera tjänster
echo "Enabling services"
sudo systemctl daemon-reload
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Aktivera Apache -moduler
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
# Ladda om Daemon och starta om Apache, Postfix och OpenDkim
sudo systemctl daemon-reload
sudo systemctl restart apache2
sudo systemctl restart opendkim postfix
# Visa IPv6 och OpenDkim för domänkonfiguration
echo "COPY the below information to domain configuration."
hostname -I
ip a | grep inet
ip -6 addr | grep "scope link"
Innan du kör den här koden, se till att domänen du har köpt är ansluten till servern. För att göra detta öppnar du en terminal på din lokala maskin och kör detta kommando med din domän:

ping femmebabe.com # Sätt in din domän här, efter ping
Om allt ser bra ut och servern skickar svar är vi redo att köra skriptet och installera paket samt starta, aktivera och certifiera vår Apache -server. Det här är inte all den installation som behövs för att konfigurera PostFix, vi kommer att titta på den inställningen mer senare. För nu, kör denna installationskod och det bör ta några minuter att installera och certifiera din server. Se igen till att ersätta namn, e -post och domännamn i skriptet enligt namnet du köpte. Nu när servern tillhandahålls kan du gå till URL i vilken webbläsare som helst och kontrollera att servern kör HTTPS. Om det inte är det, försök att vänta en liten stund på att DNS -posterna kommer att komma ikapp och sedan köra följande kommando för att försöka certifikatcertifiering:

sudo certbot --apache --non-interactive --agree-tos --domains <domain>.com --email <youremail>@gmail.com
Så länge du har konfigurerat allt korrekt, bör du kunna komma åt Apaches standardsida bara för att veta att din kod fungerar och visar en live -webbsida. Låt oss sedan redigera inställningarna. Ppy för att ändra vårt standardfelsökning till produktion. Vi kommer också att konfigurera domänen i inställningarna såväl som interna IP: er.

nano yourproject/settings.py
Ändra/lägg till dessa rader i inställningarna.

DEBUG = False

# Webbplatskonfiguration
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',
]
Nu måste vi konfigurera Apache2. Låt oss redigera konfigurationsfilen vi kommer att distribuera med den här raden:

sudo nano /etc/apache2/sites-available/femmebabe-le-ssl.conf
Den här konfigurationsfilen ska ha vårt domännamn i den och namnet på användaren och projektet. Jag använder domännamnet femmebabe.com, användarnamnsteamet och projektnamnet 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>
Se till att ersätta namnet på projektet, katalogerna och domänen i det här exemplet när du konfigurerar din server. Nu måste vi inaktivera standardwebbplatsen. Detta kan göras med bash.

sudo a2dissite 000-default-le-ssl
sudo a2dissite 000-default
sudo a2dissite default-ssl
Därefter kan vi aktivera standardwebbplatsen och ladda om Apache2, även med bash. Kom ihåg att ersätta femmebabe med namnet på filen du förklarade när du redigerar i/etc/apache2/webbplatser-tillgängliga/.

sudo a2ensite femmebabe-le-ssl
sudo systemctl reload apache2
Gå tillbaka till din domän i Navbar. Du bör se den webbplats du konfigurerade i din webbläsare. Grattis! Om du inte ser det kan du behöva göra några förändringar. Granska noggrant inställningarna i ditt projekt, Apache -konfiguration och se till att du inte har några fel och kör följande kommandon för att kontrollera projektet för fel.

cd projectname
source venv/bin/activate
python manage.py check
Om du har fel i ditt Python -projekt, spåra dem där de är och fixa dem. Du kanske inte kan se alla dina fel beroende på var de är, så om du har ett fel som helt enkelt säger "Populera är inte reentrant", redigera följande fil i den virtuella miljön, register.py, för att avslöja fel.

nano venv/lib/python3.12/site-packages/django/apps/registry.py
Bläddra till rad 83, där detta runtime -fel tas upp (höja runtimeError ("populate () är inte reentrant")), och lägg till en kommentar innan denna rad och lägger sedan till, med samma intryck, self.app_configs = {}. Det här ser ut så här:

            if self.loading:
                # Förhindra Reentrant -samtal för att undvika att köra AppConfig.Ready ()
                # Metoder två gånger.
# höja RuntimeError ("populate () är inte reentrant")
                self.app_configs = {}
            self.loading = True
Du kan sedan kontrollera projektet igen och avslöja felet.

python manage.py check
Då kan du se felet och fixa det. När du har fixat den och koden sammanställer utan fel, se till att ändra filen tillbaka så att den ser ut så här:

            if self.loading:
                # Förhindra Reentrant -samtal för att undvika att köra AppConfig.Ready ()
                # Metoder två gånger.
                raise RuntimeError("populate() isn't reentrant")
# self.app_configs = {}
            self.loading = True
Förutsatt att servern är online, när vi gör ytterligare ändringar av den, måste vi använda följande kommando för att ladda upp servern:

sudo systemctl reload apache2
Fantastisk! Men hur är det med att skicka e -post? För att börja skicka e -post måste vi först uppdatera domänkonfigurationen. Detta bör finnas i din DNS -panel i Squarespace, eller vilket domännamnsregistrator du valde. Vi kommer också att behöva installera och lägga till konfiguration och köra några kommandon. Låt oss först få IPv6 -adressen till servern. Vi öppnar sedan dina DNS och lägger till posterna. För att få serverns IPv6 -adress, använd det här kommandot:

ip -6 addr
Nu kan vi lägga till följande poster i DNS -inställningarna. Mina poster ser ut så här. Men för dina poster bör du byta ut IP -adressen med din IP (inte 75.147.182.214, det är mitt). Lägg också till din domän i stället för femmebabe.com, såväl som din IPv6 -adress som hittades med föregående kommando (du kan inte använda min, FE80 :: 725A: FFF: FE49: 3E02). Oroa dig inte för DomainKey för nu, detta skapas när vi ställer in PostFix, Mail Server, med OpenDkim och skriver ut nyckeln. Vi kommer att konfigurera det här sista. @ En N/a 75.147.182.214 @ Mx 10 femmebabe.com @ Ptr N/a femmebabe.com @ Txt N/a TXT @ V = SPF1 MX IP75.147.182.214IP6: FE80 :: 725A: FFF: FE49: 3E02 ~ ALLA standard._bimi Txt N/a v = bimi1; l = https: //femmebabe.com/media/static/femmebabe.svg _DMARC Txt N/a v = dMarc1; p = ingen Sendonly._domainkey Txt N/aNu måste vi lägga till lite bestående konfiguration för PostFix. Allt vi behöver göra är att se till att vi ersätter domännamnet, femmebabe.com, med det domännamn du använder. Låt oss titta på alla konfigurationsfiler en efter en och installera dem i en katalog som heter Config i vårt projekt för installation till OS.

nano config/etc_postfix_main.cf
Lägg till den här texten i filen

# Se /usr/share/postfix/main.cf.dist för en kommenterad, mer komplett version


# Debian Specific: Att specificera ett filnamn kommer att orsaka det första
# raden i den filen som ska användas som namn.  Debian standard
# är /etc /mailName.
# myorigin = /etc /mailName

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

# Tillägg. Domain är MUA: s jobb.
append_dot_mydomain = no

# UNCOMMENT Nästa rad för att generera "försenade post" varningar
# fördröjning_warning_time = 4h

readme_directory = no

# Se http://www.postfix.org/compatibility_readme.html - Standard till 3,6 på
# Färska installationer.
compatibility_level = 3.6



#  TLS parameters
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

# Milterkonfiguration
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
Nästa konfiguration!

nano config/etc_postfix_master.cf
Lägg till dessa rader:

# 
# Postfix Master Process Configuration File.  För mer information om formatet
# i filen, se Master (5) Manual -sidan (kommando: "Man 5 Master" eller
# Online: http://www.postfix.org/master.5.html).
# 
# Glöm inte att köra "Postfix Reload" efter att ha redigerat den här filen.
# 
# =================================================== =========================
# Servicetyp Privat oprIV CHROOT WACEUP MAXPROC COMMAND + ARGS
# (ja) (ja) (nej) (aldrig) (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
# Välj en: Aktivera inlämning endast för loopback -klienter, eller för någon klient.
# 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/inlämning
# -o smtpd_tls_security_level = kryptering
# -o smtpd_sasl_auth_enable = ja
# -o smtpd_tls_auth_only = ja
# -o smtpd_reject_unlisted_recipient = nej
# -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 = TILLÄGGD_SASL_AUTHEENTICATERAD, avvisar
# -O Milter_Macro_Daemon_Name = Originating
# Välj en: Aktivera SMTPS endast för loopback -klienter eller för någon klient.
# 127.0.0.1:smtps inet n - y - - SMTPD
# SMTPS inet n - y - - smtpd
# -O syslog_name = postfix/smtps
# -o smtpd_tls_wrappermode = ja
# -o smtpd_sasl_auth_enable = ja
# -o smtpd_reject_unlisted_recipient = nej
# -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 = TILLÄGGD_SASL_AUTHEENTICATERAD, avvisar
# -O Milter_Macro_Daemon_Name = Originating
# 628 inet n - y - - qmqpd
pickup    unix  n       -       y       60      1       pickup
cleanup   unix  n       -       y       -       0       cleanup
qmgr      unix  n       -       n       300     1       qmgr
# qmgr unix n - n 300 1 oqmg
tlsmgr    unix  -       -       y       1000?   1       tlsmgr
rewrite   unix  -       -       y       -       -       trivial-rewrite
bounce    unix  -       -       y       -       0       bounce
defer     unix  -       -       y       -       0       bounce
trace     unix  -       -       y       -       0       bounce
verify    unix  -       -       y       -       1       verify
flush     unix  n       -       y       1000?   0       flush
proxymap  unix  -       -       n       -       -       proxymap
proxywrite unix -       -       n       -       1       proxymap
smtp      unix  -       -       y       -       -       smtp
relay     unix  -       -       y       -       -       smtp
        -o syslog_name=postfix/$service_name
# -O SMTP_HELO_TIMEOUT = 5 -O SMTP_CONNECT_TIMEOUT = 5
showq     unix  n       -       y       -       -       showq
error     unix  -       -       y       -       -       error
retry     unix  -       -       y       -       -       error
discard   unix  -       -       y       -       -       discard
local     unix  -       n       n       -       -       local
virtual   unix  -       n       n       -       -       virtual
lmtp      unix  -       -       y       -       -       lmtp
anvil     unix  -       -       y       -       1       anvil
scache    unix  -       -       y       -       1       scache
postlog   unix-dgram n  -       n       -       1       postlogd
# 
# =================================================== ===================
# Gränssnitt till programvara för icke-postfix. Var noga med att undersöka manualen
# Sidor i programvaran utan postfix för att ta reda på vilka alternativ den vill ha.
# 
# Många av följande tjänster använder leveransen PostFix (8)
# ombud.  Se Pipe (8) Woman Page för information om $ {Mottagare}
# och andra alternativ för meddelandeskuvert.
# =================================================== ===================
# 
# Maildrop. Se filen PostFix MailDrop_ReadMe för mer information.
# Ange också i main.cf: mailDrop_destination_recipient_limit = 1
# 
maildrop  unix  -       n       n       -       -       pipe
  flags=DRXhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
# 
# =================================================== ===================
# 
# Nya Cyrus -versioner kan använda den befintliga "LMTP" Master.cf -posten.
# 
# Ange i cyrus.conf:
# lmtp cmd = "lmtpd -a" lyssna = "localhost: lmtp" proto = tcp4
# 
# Ange i main.cf ett eller flera av följande:
# Mailbox_Transport = lmtp: inet: localhost
# virtual_transport = lmtp: inet: localhost
# 
# =================================================== ===================
# 
# Cyrus 2.1.5 (Amos Gouaux)
# Ange också i main.cf: cyrus_destination_recipient_limit = 1
# 
# Cyrus unix - n n - - rör
# flaggor = drx user = cyrus arg =/cyrus/bin/leverera -e -r $ {avsändare} -m $ {förlängning} $ {användare}
# 
# =================================================== ===================
# Gammalt exempel på leverans via Cyrus.
# 
# Gammal -Cyrus unix - n n - - rör
# flaggor = r user = cyrus argv =/cyrus/bin/leverera -e -m $ {förlängning} $ {användare}
# 
# =================================================== ===================
# 
# Se filen PostFIX UUCP_ReadMe för konfigurationsinformation.
# 
uucp      unix  -       n       n       -       -       pipe
  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
# 
# Andra externa leveransmetoder.
# 
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}
Och OpenDkim -konfigurationen. OpenDkim identifierar e -postservrar med domännycklar för att göra dem säkrare. Utan det är inte posten undertecknad och kanske inte kommer till en inkorg.

nano config/etc_default_opendkim
Lägg till dessa rader:

# Obs: Detta är en äldre konfigurationsfil. Det används inte av OpenDkim
# Systemd -tjänst. Använd motsvarande konfigurationsparametrar i
# /etc/opendkim.conf istället.
# 
# Tidigare skulle man redigera standardinställningarna här och sedan köra
# /lib/opendkim/opendkim.service.generera för att generera systemd åsidosätta filer till
# /etc/systemd/system/opendkim.service.d/override.conf och
# /etc/tmpfiles.d/opendkim.conf. Även om detta fortfarande är möjligt, är det nu
# Rekommenderas att justera inställningarna direkt i /etc/opendkim.conf.
# 
# Daemon_opts = ""
# Ändra till/var/spool/postfix/run/opendkim för att använda ett Unix -uttag med
# Postfix i en chroot:
# Rundir =/was/spool/postfix/run/opendkim
RUNDIR=/run/opendkim
# 
# Ummentar för att ange ett alternativt uttag
# Observera att inställning av detta kommer att åsidosätta alla socketvärde i OpenDkim.conf
# standard:
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
# Lyssna på alla gränssnitt på port 54321:
# Socket = inet: 54321
# Lyssna på Loopback på Port 12345:
# Socket = inet: 12345@localhost
# Lyssna är 192.0.2.1 är 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
Lägg till dessa rader:

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

# Standard VSZ (Virtual Memory Size) Begränsning för serviceprocesser. Detta är främst
# avsedd att fånga och döda processer som läcker minne innan de äter upp
# allt.
# standard_vsz_limit = 256m

# Inloggningsanvändare används internt av inloggningsprocesser. Detta är den mest opålitliga
# Användare i Dovecot -systemet. Det borde inte ha tillgång till någonting alls.
# default_login_user = dovenull

# Intern användare används av oförstörda processer. Det bör vara separat från
# Logga in användaren så att inloggningsprocesser inte kan störa andra processer.
# default_internal_user = dovecot

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

  # Antal anslutningar för att hantera innan du startar en ny process. Typiskt
  # De enda användbara värdena är 0 (obegränsad) eller 1. 1 är säkrare, men 0
  # är snabbare. <doc/wiki/loginprocess.txt>
  # service_count = 1

  # Antal processer för att alltid vänta på fler anslutningar.
  # Process_min_avail = 0

  # Om du ställer in service_count = 0 måste du förmodligen växa detta.
  # vsz_limit = $ default_vsz_limit
}

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

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

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

  # Skapa inet -lyssnare endast om du inte kan använda ovanstående UNIX -uttag
  # inet_lister lmtp {
    # Undvik att göra LMTP synlig för hela internet
    # Adress =
    # port =
  # }
}

service imap {
  # Det mesta av minnet går till mmap () ing filer. Du kan behöva öka detta
  # Begränsa om du har enorma brevlådor.
  # vsz_limit = $ default_vsz_limit

  # Max. Antal IMAP -processer (anslutningar)
  # process_limit = 1024
}

service pop3 {
  # Max. Antal POP3 -processer (anslutningar)
  # process_limit = 1024
}

service submission {
  # Max. Antal SMTP -inlämningsprocesser (anslutningar)
  # process_limit = 1024
}

service auth {
  # AUTH_SOCKET_PATH pekar på detta userDB -uttag som standard. Det är vanligtvis
  # Används av Dovecot-LLda, Doveadm, eventuellt IMAP-process, etc. Användare som har
  # Fullständiga behörigheter till detta uttag kan få en lista över alla användarnamn och
  # Få resultaten från allas userdb -uppslag.
  # 
  # Standard 0666 -läget gör det möjligt för vem som helst att ansluta till uttaget, men
  # userDB -uppslag kommer bara att lyckas om userdb returnerar ett "uid" -fält som
  # Matchar den som ringer processens UID. Även om samtalens UID eller GID matchar
  # Socket är UID eller GID uppslaget lyckas. Allt annat orsakar ett misslyckande.
  # 
  # För att ge de som ringer fullständiga behörigheter för att leta upp alla användare, ställ in läget till
  # något annat än 0666 och dovecot låter kärnan verkställa
  # Behörigheter (t.ex. 0777 tillåter alla fulla behörigheter).
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix
  }
}

service auth-worker {
  # Auth Worker -processen körs som rot som standard, så att den kan komma åt
  # /etc/skugga. Om detta inte är nödvändigt bör användaren ändras till
  # $ default_interal_user.
  # användare = rot
}

service dict {
  # Om DICT -proxy används bör postprocesser ha tillgång till uttaget.
  # Till exempel: läge = 0660, grupp = vmail och global mail_access_groups = vmail
  unix_listener dict {
    # Läge = 0600
    # Användare =
    # grupp =
  }
}
Återigen, se till att ersätta domänen i alla dessa filer, femmebabe.com, med den domän du valde. Redigera nästa fil, Dovecots config,

nano config/etc_dovecot_dovecot
Och lägg till dessa rader

## Äggkonfigurationsfil

# Om du har bråttom, se http://wiki2.dovecot.org/quickconfiguration

# "Doveconf -n" -kommandot ger en ren utgång av de ändrade inställningarna. Använda den
# Istället för att kopiera och klistra in filer när du publicerar på Dovecot -e -postlistan.

# '# 'Karaktär och allt efter det behandlas som kommentarer. Extrautrymmen
# och flikar ignoreras. Om du vill använda någon av dessa uttryckligen, lägg
# value inside quotes, eg.: key = "# char och släpande vitrum "

# De flesta (men inte alla) inställningar kan åsidosättas av olika protokoll och/eller
# Källa/destination IPS genom att placera inställningarna i avsnitten, till exempel:
# Protocol IMAP {}, Local 127.0.0.1 {}, fjärrkontroll 10.0.0.0/8 {}

# Standardvärden visas för varje inställning, det krävs inte att avkomma
# dessa. Detta är dock undantag från detta: Inga avsnitt (t.ex. namnutrymme {})
# eller plugininställningar läggs till som standard, de listas endast som exempel.
# Vägar är också bara exempel med de verkliga standardvärdena som är baserade på konfiguration
# alternativ. Vägarna som listas här är för konfigurering -PREFIX =/usr
# -sysconfdir =/etc--localstatedir =/var

# Aktivera installerade protokoll
!include_try /usr/share/dovecot/protocols.d/*.protocol

# En kommaseparerad lista över IPS eller värdar var du ska lyssna på anslutningar.
# "*" lyssnar i alla IPv4 -gränssnitt, "::" lyssnar i alla IPv6 -gränssnitt.
# Om du vill ange hamnar som inte är avfall eller något mer komplicerat,
# EDIT CONF.D/MASTER.CONF.
# Lyssna = *, ::

# Baskatalog var du ska lagra runtime -data.
# base_dir =/var/run/doecot/

# Namnet på den här instansen. I Multi Instance Setup Doveadm och andra kommandon
# kan använda -i <instans_name> för att välja vilken instans som används (ett alternativ
# till -c <config_path>). Instansnamnet läggs också till i Dovecot -processer
# i PS -utgång.
# Instans_name = dovecot

# Hälsningsmeddelande för klienter.
# LOGIN_GREETING = DOVECOT KLAR.

# Rymdseparerad lista över pålitliga nätverksintervall. Anslutningar från dessa
# IP: er får åsidosätta sina IP -adresser och portar (för avverkning och
# för autentiseringskontroller). inaktivera_plaintext_auth ignoreras också för
# Dessa nätverk. Vanligtvis skulle du ange dina IMAP -proxyservrar här.
# LOGIN_TRUSED_NETWORKS =

# Rymdseparerad lista över inloggningskontrolluttag (t.ex. TCPWRAP)
# LOGIN_ACCESS_SOCKETS =

# Med proxy_maybe = ja om proxy -destinationen matchar någon av dessa IP: er, gör inte
# proxying. Detta är inte nödvändigt normalt, men kan vara användbart om destinationen
# IP är t.ex. En lastbalansörs IP.
# auth_proxy_self =

# Visa mer ordförda processtitlar (i PS). Visar för närvarande användarnamn och
# IP -adress. Användbart för att se vem som faktiskt använder IMAP -processerna
# (t.ex. delade brevlådor eller om samma UID används för flera konton).
# verbose_proctitle = nej

# Om alla processer dödas när Dovecot master -process stängs av.
# Att ställa in detta till "nej" betyder att Dovecot kan uppgraderas utan
# tvinga befintliga klientanslutningar att stänga (även om det också kan vara
# Ett problem om uppgraderingen är t.ex. på grund av en säkerhetsfix).
# SHIVDOWN_CLIENTS = Ja

# Om icke-noll, kör e-postkommandon via dessa många anslutningar till Doveadm Server,
# istället för att köra dem direkt i samma process.
# doveadm_worker_count = 0
# Unix Socket eller Host: Port som används för att ansluta till Doveadm Server
# doveadm_socket_path = doveadm-server

# Space Separated List of Miljövariabler som bevaras på Dovecot
# Startup och övergick till alla sina barnprocesser. Du kan också ge
# KEY = Värdepar för att alltid ställa in specifika inställningar.
# Import_enVironment = TZ

## 
## Ordboksserverinställningar
## 

# Ordbok kan användas för att lagra nyckel = värdelistor. Detta används av flera
# plugins. Ordboken kan nås antingen direkt eller även om a
# Ordboksserver. Följande diktblockkartor ordboksnamn till URI: er
# När servern används. Dessa kan sedan hänvisas till med URI: er i format
# "Proxy :: <namn>".

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

# De flesta av den faktiska konfigurationen ingår nedan. Filnamnen är
# Först sorteras av deras ASCII -värde och analyserades i den ordningen. 00-prefixen
# i filnamn är avsedda att göra det lättare att förstå beställningen.
!include conf.d/*.conf

# En konfigurationsfil kan också försöka inkluderas utan att ge ett fel om
# det finns inte:
!include_try local.conf

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

protocols = imap pop3

# Tillåter Dovecot att lyssna på alla ingångsanslutningar (IPv4 / IPv6)

listen = *, ::
Lägg till ett lösenord för Dovecot -användaren:

nano config/etc_dovecot_passwd
Den första delen av filen, före kolon, är användarnamnet. Den sista delen, "YourPassword", anger lösenordet du vill ge din e -postserver.

team:{plain}yourpassword
Därefter OpenDkim -konfigurationen

nano config/etc_opendkim.conf
Och lägg till dessa rader:

# Detta är en grundläggande konfiguration för att signera och verifiera. Det kan lätt vara
# Anpassad för att passa en grundläggande installation. Se OpenDkim.Conf (5) och
# /usr/share/doc/opendkim/examples/opendkim.conf.Sample för komplett
# Dokumentation av tillgängliga konfigurationsparametrar.

Syslog			yes
SyslogSuccess		yes
# Logwhy nej

# Vanliga signerings- och verifieringsparametrar. I Debian är "från" -huvudet
# Övervakad, eftersom det ofta är identitetsnyckeln som används av rykte system
# och därmed något säkerhetskänsligt.
Canonicalization	relaxed/simple
Mode			s
SubDomains		no
OversignHeaders		From

# Signeringsdomän, väljare och nyckel (krävs). Utför till exempel signering
# För domän "exempel.com" med väljare "2020" (2020._domainkey.example.com),
# Använda den privata nyckeln lagrad i /etc/dkimkeys/example.private. Mer granulärt
# Inställningsalternativ finns i /usr/share/doc/opendkim/readme.opendkim.
# Domänexempel.com
# Väljare 2020
# KeyFile /etc/dkimkeys/example.private

# I Debian kör OpenDkim som användare "OpenDkim". En umask på 007 krävs när
# Använda ett lokalt uttag med MTA som får åtkomst till uttaget som en icke-privilegierad
# Användare (till exempel PostFix). Du kan behöva lägga till användar "postfix" i gruppen
# "OpenDkim" i så fall.
UserID			opendkim
UMask			007

# Uttag för MTA -anslutningen (krävs). Om MTA är inne i ett Chroot -fängelse,
# Det måste säkerställas att uttaget är tillgängligt. I Debian springer Postfix in
# en chroot i/var/spool/postfix, därför måste ett unix -uttag vara
# Konfigurerad som visas på den sista raden nedan.
# Socket Local: /run/opendkim/opendkim.sock
# Socket			inet:8891@localhost
# Socket			inet:8891
Socket			local:/var/spool/postfix/opendkim/opendkim.sock

PidFile			/run/opendkim/opendkim.pid

# Värdar för att underteckna snarare än att verifiera, standard är 127.0.0.1. Se den
# Operationssektion av OpenDkim (8) för mer information.
# InternalHosts 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12

# Förtroendeankaren möjliggör DNSSEC. I Debian tillhandahålls förtroendeförankringsfilen
# av paketet DNS-Root-data.
TrustAnchorFile		/usr/share/dns/root.key
# NAMESERVERS 127.0.0.1

# Kartomäner från adresser till nycklar som används för att underteckna meddelanden
KeyTable           refile:/etc/opendkim/key.table
SigningTable       refile:/etc/opendkim/signing.table

# En uppsättning interna värdar vars post ska undertecknas
InternalHosts       /etc/opendkim/trusted.hosts

nano config/etc_default_opendkim
Och lägg till dessa rader

# Obs: Detta är en äldre konfigurationsfil. Det används inte av OpenDkim
# Systemd -tjänst. Använd motsvarande konfigurationsparametrar i
# /etc/opendkim.conf istället.
# 
# Tidigare skulle man redigera standardinställningarna här och sedan köra
# /lib/opendkim/opendkim.service.generera för att generera systemd åsidosätta filer till
# /etc/systemd/system/opendkim.service.d/override.conf och
# /etc/tmpfiles.d/opendkim.conf. Även om detta fortfarande är möjligt, är det nu
# Rekommenderas att justera inställningarna direkt i /etc/opendkim.conf.
# 
# Daemon_opts = ""
# Ändra till/var/spool/postfix/run/opendkim för att använda ett Unix -uttag med
# Postfix i en chroot:
# Rundir =/was/spool/postfix/run/opendkim
RUNDIR=/run/opendkim
# 
# Ummentar för att ange ett alternativt uttag
# Observera att inställning av detta kommer att åsidosätta alla socketvärde i OpenDkim.conf
# standard:
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
# Lyssna på alla gränssnitt på port 54321:
# Socket = inet: 54321
# Lyssna på Loopback på Port 12345:
# Socket = inet: 12345@localhost
# Lyssna är 192.0.2.1 är port 12345:
# Socket = inet: 12345@192.0.2.1
USER=opendkim
GROUP=opendkim
PIDFILE=$RUNDIR/$NAME.pid
EXTRAAFTER=
När vi är redo att ställa in vår postfix -server kommer vi att köra koden nedan med lämpligt domännamn inbäddat. Börja med att skapa ett skript

touch scripts/postfixsetup
sudo chmod a+x scripts/postfixsetup
nano scripts/postfixsetup
Nu, i Nano, textredigeraren, redigera den här filen så att den innehåller ditt domännamn istället för femmebabe.com.

# ! / BIN / BASH
# Inställning 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}'
Kör nu det färdiga skriptet för att konfigurera PostFix, OpenDkim och Dovecot.

./scripts/postfixsetup
När detta skript har körts, kopiera den sista raden som den skriver ut och klistra in det i din DNS -konfiguration som värdet för Sendonly._domainkey. Detta är OpenDkim -nyckeln som används för att identifiera din domän när du skickar säker e -post. Fantastisk! Inom några dagar bör du kunna skicka e -post från servern förutsatt att allt är konfigurerat korrekt. Om du bara konfigurerade DNS för din e -postserver bör det ta mindre än 72 timmar för posten att uppdatera. Det är vanligtvis mycket snabbare. Du kan kontrollera om din server fungerar med det här kommandot, levererat din e -post:

echo “test” | mail -s “Test Email” youremail@gmail.com
Om allt verkar fungera korrekt bör du kunna skicka e -post med din server. Om det inte fungerar kan du försöka titta på loggarna för att se vad felet kan vara.

tail –lines 150 /var/log/mail.log
Detta kommer att erbjuda verbosinformation om e -post som skickas av servern och om den fungerar korrekt. Du bör också kunna se e -postmeddelandet i din inkorg, om den inte är där, kolla din skräppostmapp. Du måste också konfigurera dina inställningar i dina inställningar.py så att din e -postserver kan prata med din Django -app, projektet. Lägg till eller byt ut dessa rader i dina inställningar

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)
Lägg märke till att vi använder en konfigurationsfil för att få lösenordet. Låt oss ladda den här filen i inställningarna som så, i början av filen.:

import os
import json

# Öppna och ladda config
with open('/etc/config.json') as config_file:
    config = json.load(config_file)
Låt oss skapa den här filen och lägga till en hemlig nyckel till den såväl som e -postlösenordet. För att generera en hemlig nyckel, använd det här kommandot, med vilken längd du vill i slutet:

openssl rand -base64 64
Kopiera nu texten som OpenSSL genererade och redigerar /etc/config.json

sudo nano /etc/config.json
Lägg till följande rader i din fil, med nyckeln som OpenSSL genererade som den hemliga nyckeln.

{
	"SECRET_KEY": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX-generated-using-openssl)",
	"EMAIL_HOST_PASSWORD": "yourpassword"
}
JSON -format är enkelt och enkelt att använda, vi kan förklara andra nycklar som vi vill använda på vårt projekt på detta sätt också och hålla dem åtskilda från vår projektkatalog så att andra användare inte kan skriva till dem och så kan de inte läsas från vår projektkatalog ensam. Detta rekommenderas praxis för API -nycklar, av vilka vi kommer att använda mer än ett fåtal här. Du vill också säkerhetskopiera ditt projekt för att se till att allt sparas och du kan återställa ditt arbete senare även om du inte längre vill hyra en server.

sudo backup
Försök nu skicka ett HTML -e -post från webbservern, förutsatt att skicka en från kommandoraden fungerar. Fråga din användarinstans i skalet och skicka ett HTML -e -post till den användaren via Django. Ändra mitt namn i koden, Charlotte, till ditt användarnamn.

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()
Om det första kommandot inte fungerar, se till att använda

source venv/bin/activate
Förutsatt att allt är korrekt inställt, får du nu ett välkommet e -postmeddelande i din brevlåda som skickas av din webbapp. Bra jobb! Du har kommit långt. Jag ville lägga till, om du någonsin kämpar med några fel alls när du arbetar med ett projekt som detta, tveka inte att söka efter svar och be om hjälp. Google, bland andra sökmotorer, är stora resurser för att söka efter programmeringshjälp. Sök bara efter det fel du får, så kommer du att kunna se hur andra människor löser problemet. Du är också välkommen att kontakta mig, dina lärare (lärare, professorer, handledare), alla kamrater på internet som är tillgängliga för programmeringshjälp eller konsultera denna bok igen eller andra resurser för att hitta lösningar på de frågor du upplever. Jag förstår att detta inte är lätt, men även om du har läst i det här långt och inte skriver någon kod, lär du dig mycket om att bygga en webbapp från början. Klappa dig själv på ryggen, du gör en fantastiskjobb. Tack för att du tog dig tid att läsa denna tredje utgåva webbutvecklingsguide. I framtida utgåvor kommer jag att inkludera fler av de viktiga exemplen som diskuterades i början av dokumentet och vi kommer att dyka mycket djupare in i världen av programvara och hårdvaruutveckling. Håll ögonen öppna för vad som kommer, och jag ser fram emot att lära dig hur du bygger otrolig programvara. Vi ses i nästa






Nära
Sida 1
Hoppa
Se hela artikeln
Fortsätt läsa

Köpa | Köp med krypto



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


(Klicka eller tryck för att ladda ner bilden)
Professionell underhållning, foton, videor, ljud, livestreaming och casual gameplay, samt ID-skanning, webbutveckling och surrogatmödraskapstjänster.

Lämna mig ett tips i Bitcoin med denna adress: 3KhDWoSve2N627RiW8grj6XrsoPT7d6qyE

© Glam Girl X 2025

Användarvillkor