Praktisk nettbasert dyp læring og sikkerhet ved eksempel

Daisy's profilbilde

Ved Daisy

Praktisk nettbasert dyp læring og sikkerhet ved eksempel Tredje utgave Charlotte Harper 3. juli 2024 Forord: Sikkerhetshensyn i å bygge programvare for nettet er en viktig del av enhver webutviklers plan og utførelse mens du konstruerer en prototype som er pålitelig, stabil og nyttig for praktiske formål. DOM (Document Object Markup), med implementeringen av HTML, JavaScript og CSS, samt backend -programvare som implementerer Python, C/C ++, Java og Bash, gir nettutviklere frihet og makt til å lage et bredt utvalg av prosjekter som uttrykker Kreativitet, gir brukervennlighet og funksjonalitet, skildrer ydmykhet og karakter, og gir brukervennlighet samt bekvemmelighet og viktige tjenester som alle er attraktive for den gjennomsnittlige Joe, sluttbrukeren som ønsker å drepe tid eller få noe gjort på internett, Vanligvis på en smarttelefonenhet på berøringsskjerm. De fleste ville ikke engang vite hvor de skal begynne når de vil bygge et nettsted fra bunnen av,De vil ha en tendens til å starte på en annen persons nettsted og bygge noe begrenset i funksjonalitet, pålitelighet, brukervennlighet og spesielt kreativitet når de kunne ha hatt alle de nyeste kraftige verktøyene til disposisjon for å bygge noe nyttig uten å kaste bort tidspressknapper, og Spesielt å kaste bort penger som betaler for dyre abonnement på programvare, få mennesker ønsket å bruke uansett, gitt at det er begrensninger i brukervennlighet og fleksibilitet. Hvis du har noen minutter til å lese gjennom denne boken og lære hva jeg vil lære deg, eller til og med snakke med meg personlig om målene dine og få litt veiledning i riktig retning, og er motivert til å lære å kode og skrive din egen programvare Ta denne boken hjem og sett av litt tid til å lære å bygge den neste innflytelsesrike, kraftige, strømlinjeformede og viktige webapplikasjonen, et nettsted som er alt på deg og gjør akkurat det du vil og tilfredsstiller behovene til publikum. Om meg: Jeg er en programvareutvikler med en bredAnge av erfaring i C/C ++, Java, Python, HTML, CSS og JavaScript. Jeg bygger nettsteder folk vil bruke, vil besøke og til og med bli avhengige av å bruke bare for å lære, gjenskape og drepe tid, og viktigst av alt, jeg selger programvare. Hvis du hadde en ide om nøyaktig hvordan du ønsket at et nettsted skulle se og fungere, var du villig til å støtte meg slik at jeg kan møte mine egne behov mens jeg møter dine, og du er villig til å dekke kostnadene ved å drive et nettsted selv, selv, Jeg ville bygge deg den neste YouTube, Tiktok, Twitter, Google eller til og med en høyteknologisk sikkerhetsapp bare du har tilgang til. I stedet for å prøve å selge deg tiden min, prøver jeg å kjøpe din: Jeg vil snakke deg om å bygge en app (nettsted) selv med informasjonen som allerede eksisterer, og lære deg hva du trenger for å være en uavhengig programvareutvikler, gründer, som leder en vellykket karriere innen hvilket felt du ønsker. Og la meg være tydelig, utdannelsen jeg gir deg vil være uformell. Du kan gå på skolen og lære alt dette med enRMAL -utdanning, eller til og med les denne boken på skolen, fullfører oppgavene dine og tar bort mye fra utdannelsen din, men jeg vil ikke formelt sette deg i det varme setet og be deg om å fullføre oppgaver. Jeg er ikke din professor, du kan tenke på meg som en venn som vil veilede deg mot en karriere drevet av din egen personlige suksess. Og jeg selger ikke suksessen din heller, du må kjøpe den med tiden din. Å lære å kode har en bratt læringskurve og var aldri lett, eller til og med antatt å være. Du må jobbe så hardt som du kan og fortsette å prøve å mislykkes og prøve igjen selv når du er frustrert for å lære og bygge apper selv. Det er i selve koden. Kode drives av en kompilator som er designet for å gi programmererfeilmeldingene, og disse vil lære deg hvordan du skal kode, selv om du bare kopierer feilen i søkemotoren og leser andres eksempler. Og jeg må si, du trenger ikke å være ekstremt rik, smart, vellykket,en detaljorientert eller organisert for å bygge en app. Datamaskinen tar seg av den organisasjonen for deg. Du trenger bare å holde ut gjennom prøving og feiling, opprettholde fokus og jobbe hardt på det du gjør, og du vil ha en veldig vellykket karriere i hele det du gjør. Hvem jeg er: Jeg er klar over at den siste delen handlet mer om læring og at du tar vei fra denne boken. Hvem er jeg akkurat? Det er et komplisert spørsmål. Jeg er uklar på det selv, ettersom jeg lider av medisinske tilstander som kan gjøre det vanskelig for meg å til og med kode eller skrive denne boken til tider, mens jeg presenterer utfordringer med sosialisering og identitetsproblemer som gjør livet mitt vanskeligere når det gjelder å introdusere meg selv . Kort sagt, hvis du leser denne boken, tok du den med hjem fordi du snudde gjennom den og trodde den var nyttig, eller til og med hvis du bare leste så langt inne, for deg er jeg et lignende individ som vil se at du lykkes med alt du gjør. Jeg er ingeniør selv, en programvareutvikler, og en student, og jeg skriver denne boken for andre studenter som ønsker å gjøre livet lettere ved å ha en håndbok over programvaren de trenger å gjøre livet lettere ved å gi eksempler på å kopiere som passer sammen som et stort puslespill til en arbeid , nyttig, stor, funksjonell, sammenhengende og engasjerende app som kan drive suksess uansett virksomhetslinje. Stort sett er det dette jeg gjør: Jeg bygger apper for å hjelpe meg selv og andre mennesker til å lykkes. Jeg er også forfatter, selv om dette er min første publikasjon som jeg har tenkt å fullføre for å sette sammen porteføljen min i et nyttig dokument, og jeg er også kunstner. Jeg vil innrømme dette for deg, jeg er liksom en merkelig person. Jeg er ikke perfekt, jeg har hatt innløp med loven som til og med førte meg til å forlate høyskoler og universiteter og forlate stater for å prøve å gi et navn for meg selv med mer suksess. Jeg er en kvinne ved fødselen, jeg bruker sminke, tar bilder av meg selv, bruker kjoler og andre kvinneklær, og jeg holder meg bevisst på meg selv som enmann av natur. Jeg har hatt problemer med andre mennesker i det siste som fører til kamp med å skrive og bygge webapps, og jeg beklager at jeg ikke har klart å få denne boken i hendene før: du trengte dette. Du vil ønske å lese og skrive kode som ser ut som min og fungerer som min og gjør det samme, men enda bedre, for hvis du har råd til å kjøpe denne boken i stedet for å mase tastaturet ditt som jeg gjør bare for å lage en bok selv å spørre penger For det har du ressursene du trenger for å lykkes i livet ditt. Jeg hadde alle slags problemer med familieoppvekst, helsemessige forhold, leger, media og loven, og koden min gjenspeiler dypt kampen som er feminisme og kvinnelig natur i en delt og frustrert verden. Imidlertid er denne boken noe jeg bryr meg dypt om, babyen min, porteføljen min og levebrødet mitt, så jeg setter pris på din vurdering når du tar teksten hjem og porer nøye over den for å lære av meg. Husk at jeg ikke er perfekt,Boken vil ha feil, revisjoner og nye utgaver, og du må tenke med din logiske hjerne så godt du kan for å få en vellykket opplevelse med forfatteren min. Forstå også at jeg mener godt for deg selv når du møter utfordringer når du skriver. Tenk på det slik: Når du bare kan leie et datasystem for å gjøre alt du muligens kan forestille deg i det digitale rommet, lagre all informasjonen du møter, #$%! Yze og organiser det, og kom til å forstå det, vil du Uunngåelig møter vanskeligheter med informasjonen du inntar og til og med publiserer. Jeg forteller deg dette fordi jeg møter de samme vanskene. Bruk denne boken på egen risiko, arbeid med samfunnet og lokalsamfunnene dine som er tilgjengelige for å bygge programvare innen trygge omgivelser, og ikke ta ting til personlig når du mislykkes eller til og med lykkes på feil måte: det var slik jeg kom så langt , og hvorfor jeg kan gi deg denne teksten og hjelpe deg med å lykkes uten å avvike på en galskaps vei som forlaterJeg ødela, revet og frynsete mens jeg møter de vanlige problemene alle gjør i global skala takket være den paralellistiske globale skalaen til nettverket vi vil jobbe på, Internett. Du er kanskje ikke veldig kjent med hvem jeg er med bare noen få ord, men jeg oppfordrer deg til å lese videre, du vil bli kjent med meg når du fortsetter å lese og forstå meg mens du bygger dine egne prosjekter for å fullføre arbeidet ditt. Det vil ikke være noen lekser med denne boken, så lenge professorene eller lærerne dine ikke tildeler deg noe, men jeg oppfordrer deg til å bygge en portefølje av prosjekter selv når du leser med, i tillegg til et capstone -prosjekt som viser hvordan du kan Bruk det du har lært. Capstone -prosjektet mitt er grunnlaget for det meste av det du vil lese i denne boken, ettersom det inneholder kode fra mine tidligere prosjekter, kode jeg har laget og lært å skrive metodisk for hånd, og et bredt spekter av ideer og tips som har hjulpet meg lykkes til det punktet hvor jeg kan snurre opp en enkel app som erUlly omtalt og ser ut og oppfører seg som en populær app du kanskje ser vennen din eller familien din som bruker, på internett, annonsert for deg eller i nyhetene. Hva denne boka er: Denne boken er en tutorial ved eksempel. Du kan finne kode her, instruksjoner for hvordan du kan lære å kode, informasjon om feilsøkingskode og fikse feil, feilsøkingstrinn, instruksjoner om hvordan du kan sikkerhetskopiere og lagre koden din, distribuere hvis noen bryter koden din, sikre koden din, distribuere Koden din, bygg interaktive nettsteder som er underholdende, engasjerende og vanedannende, og du vil få en følelse av hvem jeg er, hvorfor dette er viktig, og hvordan du kan skildre deg selv, appen din og firmabildet, så vel som programvaren du bygger I det absolutt beste lyset for å være det mest attraktive som mulig for sluttbrukerne, nettstedets besøkende. I denne boken vil jeg demonstrere en rekke eksempler på programvaredesign med fokus på nettet som plattform så vel som si...
Praktisk nettbasert dyp læring og sikkerhet ved eksempel

Praktisk nettbasert dyp læring og sikkerhet ved eksempel Tredje utgave Charlotte Harper 3. juli 2024 Forord: Sikkerhetshensyn i å bygge programvare for nettet er en viktig del av enhver webutviklers plan og utførelse mens du konstruerer en prototype som er pålitelig, stabil og nyttig for praktiske formål. DOM (Document Object Markup), med implementeringen av HTML, JavaScript og CSS, samt backend -programvare som implementerer Python, C/C ++, Java og Bash, gir nettutviklere frihet og makt til å lage et bredt utvalg av prosjekter som uttrykker Kreativitet, gir brukervennlighet og funksjonalitet, skildrer ydmykhet og karakter, og gir brukervennlighet samt bekvemmelighet og viktige tjenester som alle er attraktive for den gjennomsnittlige Joe, sluttbrukeren som ønsker å drepe tid eller få noe gjort på internett, Vanligvis på en smarttelefonenhet på berøringsskjerm. De fleste ville ikke engang vite hvor de skal begynne når de vil bygge et nettsted fraSkrap, de vil ha en tendens til å starte på en annen persons nettsted og bygge noe begrenset i funksjonalitet, pålitelighet, brukervennlighet og spesielt kreativitet når de kunne hatt alle de nyeste kraftige verktøyene til disposisjon for å bygge noe nyttig uten å kaste bort tid på å trykke på knapper , og spesielt å kaste bort penger som betaler for dyre abonnement på programvare, få mennesker ønsket å bruke uansett, gitt det begrensninger med brukervennlighet og fleksibilitet. Hvis du har noen minutter til å lese gjennom denne boken og lære hva jeg vil lære deg, eller til og med snakke med meg personlig om målene dine og få litt veiledning i riktig retning, og er motivert til å lære å kode og skrive din egen programvare Ta denne boken hjem og sett av litt tid til å lære å bygge den neste innflytelsesrike, kraftige, strømlinjeformede og viktige webapplikasjonen, et nettsted som er alt på deg og gjør akkurat det du vil og tilfredsstiller behovene til publikum. Om meg: Jeg er programvareutvikler medRange erfaring i C/C ++, Java, Python, HTML, CSS og JavaScript. Jeg bygger nettsteder folk vil bruke, vil besøke og til og med bli avhengige av å bruke bare for å lære, gjenskape og drepe tid, og viktigst av alt, jeg selger programvare. Hvis du hadde en ide om nøyaktig hvordan du ønsket at et nettsted skulle se og fungere, var du villig til å støtte meg slik at jeg kan møte mine egne behov mens jeg møter dine, og du er villig til å dekke kostnadene ved å drive et nettsted selv, selv, Jeg ville bygge deg den neste YouTube, Tiktok, Twitter, Google eller til og med en høyteknologisk sikkerhetsapp bare du har tilgang til. I stedet for å prøve å selge deg tiden min, prøver jeg å kjøpe din: Jeg vil snakke deg om å bygge en app (nettsted) selv med informasjonen som allerede eksisterer, og lære deg hva du trenger for å være en uavhengig programvareutvikler, gründer, som leder en vellykket karriere innen hvilket felt du ønsker. Og la meg være tydelig, utdannelsen jeg gir deg vil være uformell. Du kan gå på skolen og lære alt dette med enFormell utdanning, eller til og med les denne boken på skolen, fullfører oppgavene dine og tar bort mye fra utdannelsen din, men jeg vil ikke formelt sette deg i det varme setet og be deg om å fullføre oppgaver. Jeg er ikke din professor, du kan tenke på meg som en venn som vil veilede deg mot en karriere drevet av din egen personlige suksess. Og jeg selger ikke suksessen din heller, du må kjøpe den med tiden din. Å lære å kode har en bratt læringskurve og var aldri lett, eller til og med antatt å være. Du må jobbe så hardt som du kan og fortsette å prøve å mislykkes og prøve igjen selv når du er frustrert for å lære og bygge apper selv. Det er i selve koden. Kode drives av en kompilator som er designet for å gi programmererfeilmeldingene, og disse vil lære deg hvordan du skal kode, selv om du bare kopierer feilen i søkemotoren og leser andres eksempler. Og jeg må si, du trenger ikke å være ekstremt rik, smart,Esselig, eller til og med detaljorientert eller organisert for å bygge en app. Datamaskinen tar seg av den organisasjonen for deg. Du trenger bare å holde ut gjennom prøving og feiling, opprettholde fokus og jobbe hardt på det du gjør, og du vil ha en veldig vellykket karriere i hele det du gjør. Hvem jeg er: Jeg er klar over at den siste delen handlet mer om læring og at du tar vei fra denne boken. Hvem er jeg akkurat? Det er et komplisert spørsmål. Jeg er uklar på det selv, ettersom jeg lider av medisinske tilstander som kan gjøre det vanskelig for meg å til og med kode eller skrive denne boken til tider, mens jeg presenterer utfordringer med sosialisering og identitetsproblemer som gjør livet mitt vanskeligere når det gjelder å introdusere meg selv . Kort sagt, hvis du leser denne boken, tok du den med hjem fordi du snudde gjennom den og trodde den var nyttig, eller til og med hvis du bare leste så langt inne, for deg er jeg et lignende individ som vil se at du lykkes med alt du gjør. Jeg er ingeniør selv,utvikler, og en student, og jeg skriver denne boken for andre studenter som ønsker å gjøre livet lettere ved å ha en håndbok over programvaren de trenger å gjøre livet lettere ved å gi eksempler på å kopiere som passer sammen som et stort puslespill til en arbeid , nyttig, stor, funksjonell, sammenhengende og engasjerende app som kan drive suksess uansett virksomhetslinje. Stort sett er det dette jeg gjør: Jeg bygger apper for å hjelpe meg selv og andre mennesker til å lykkes. Jeg er også forfatter, selv om dette er min første publikasjon som jeg har tenkt å fullføre for å sette sammen porteføljen min i et nyttig dokument, og jeg er også kunstner. Jeg vil innrømme dette for deg, jeg er liksom en merkelig person. Jeg er ikke perfekt, jeg har hatt innløp med loven som til og med førte meg til å forlate høyskoler og universiteter og forlate stater for å prøve å gi et navn for meg selv med mer suksess. Jeg er en kvinne ved fødselen, jeg bruker sminke, tar bilder av meg selv, bruker kjoler og andre kvinneklær, og jeg holder meg bevisst på meg selv som enkvinne av natur. Jeg har hatt problemer med andre mennesker i det siste som fører til kamp med å skrive og bygge webapps, og jeg beklager at jeg ikke har klart å få denne boken i hendene før: du trengte dette. Du vil ønske å lese og skrive kode som ser ut som min og fungerer som min og gjør det samme, men enda bedre, for hvis du har råd til å kjøpe denne boken i stedet for å mase tastaturet ditt som jeg gjør bare for å lage en bok selv å spørre penger For det har du ressursene du trenger for å lykkes i livet ditt. Jeg hadde alle slags problemer med familieoppvekst, helsemessige forhold, leger, media og loven, og koden min gjenspeiler dypt kampen som er feminisme og kvinnelig natur i en delt og frustrert verden. Imidlertid er denne boken noe jeg bryr meg dypt om, babyen min, porteføljen min og levebrødet mitt, så jeg setter pris på din vurdering når du tar teksten hjem og porer nøye over den for å lære av meg. Husk at jeg ikke er detECT, denne boka vil ha feil, revisjoner og nye utgaver, og du må tenke med din logiske hjerne så godt du kan for å få en vellykket opplevelse med forfatterskapet mitt. Forstå også at jeg mener godt for deg selv når du møter utfordringer når du skriver. Tenk på det slik: Når du bare kan leie et datasystem for å gjøre alt du muligens kan forestille deg i det digitale rommet, lagre all informasjonen du møter, #$%! Yze og organiser det, og kom til å forstå det, vil du Uunngåelig møter vanskeligheter med informasjonen du inntar og til og med publiserer. Jeg forteller deg dette fordi jeg møter de samme vanskene. Bruk denne boken på egen risiko, arbeid med samfunnet og lokalsamfunnene dine som er tilgjengelige for å bygge programvare innen trygge omgivelser, og ikke ta ting til personlig når du mislykkes eller til og med lykkes på feil måte: det var slik jeg kom så langt , og hvorfor jeg kan gi deg denne teksten og hjelpe deg med å lykkes uten å avvike på en galskaps veiAves meg ødelagt, revet og frynsete mens jeg møter de vanlige problemene alle gjør i global skala takket være den paralellistiske globale skalaen til nettverket vi vil jobbe, Internett. Du er kanskje ikke veldig kjent med hvem jeg er med bare noen få ord, men jeg oppfordrer deg til å lese videre, du vil bli kjent med meg når du fortsetter å lese og forstå meg mens du bygger dine egne prosjekter for å fullføre arbeidet ditt. Det vil ikke være noen lekser med denne boken, så lenge professorene eller lærerne dine ikke tildeler deg noe, men jeg oppfordrer deg til å bygge en portefølje av prosjekter selv når du leser med, i tillegg til et capstone -prosjekt som viser hvordan du kan Bruk det du har lært. Capstone -prosjektet mitt er grunnlaget for det meste av det du vil lese i denne boken, ettersom det inneholder kode fra mine tidligere prosjekter, kode jeg har laget og lært å skrive metodisk for hånd, og et bredt spekter av ideer og tips som har hjulpet meg lykkes til det punktet hvor jeg kan snurre opp en enkel app somFullt inneholdt og ser ut og oppfører seg som en populær app du kanskje ser vennen din eller familien din som bruker, på internett, annonsert til deg eller i nyhetene. Hva denne boka er: Denne boken er en tutorial ved eksempel. Du kan finne kode her, instruksjoner for hvordan du kan lære å kode, informasjon om feilsøkingskode og fikse feil, feilsøkingstrinn, instruksjoner om hvordan du kan sikkerhetskopiere og lagre koden din, distribuere hvis noen bryter koden din, sikre koden din, distribuere Koden din, bygg interaktive nettsteder som er underholdende, engasjerende og vanedannende, og du vil få en følelse av hvem jeg er, hvorfor dette er viktig, og hvordan du kan skildre deg selv, appen din og firmabildet, så vel som programvaren du bygger I det absolutt beste lyset for å være det mest attraktive som mulig for sluttbrukerne, nettstedets besøkende. I denne boken vil jeg demonstrere en rekke eksempler på programvaredesign med fokus på nettet som plattform så vel som sikkerhet. Vi vil sette i gang læringsopplevelsen ved å bygge en grunnleggendeOjekt ved bruk av UNIX -skallet, med sikkerhetskopierings- og skriptfunksjoner. Deretter vil vi undersøke et grunnleggende bloggnettsted, oppgradere bloggen vår med foto- og videofunksjoner, samt bruke disse funksjonene til å bruke sikkerhetsløsninger ved hjelp av gratis programvare, og sikre serveren vår ved hjelp av en pluggable autentiseringsmodul (PAM). Vi vil deretter gjennomgå filhåndtering og prosessering, utforske videoredigering, stemmedonasjon, strekkodeskanning og optisk karaktergjenkjenning, blant andre konsepter. Underveis vil vi undersøke API -er som vil hjelpe oss å gjøre programvaren vår mer nyttig og sikker, med gratis og betalte alternativer. Underveis vil vi utforske fysisk sikkerhet og militante verktøy som skytevåpen og ammunisjonsdesign og produksjon, inkludert tønne og repeaterdesign, tårn og dronedesign, og andre rektorer vi vil integrere med programvaren vår i det eksisterende nettverket for å beskytte programvaren vår og demonstrere selvforsvar og spenst. Vi tar pauser underveis for å bygge spill, 2D og 3DEnder motorer, og arbeid med innebygd maskinvare i casestudieeksempler på grunnleggende dimensjonal gjengivelsesprogramvare og en elektronisk vibrerende massasje støpt i henholdsvis silikongummi. Underveis vil vi også bruke maskinlæringsløsninger som allerede er tilgjengelige for å sikre programvaren vår bedre. Vi vil også bruke aksjeverktøy tilgjengelig for nettet for å effektivisere og sikre prosessen. Denne boken er en guide til din suksess med å bygge en webapplikasjon og integrere den med et profesjonelt nettverk av datamaskin og innebygde mekaniske systemer, og samlet sett en guide til å bygge programvare og innebygd maskinvare uten bakgrunnskunnskap eller tidligere erfaring. Hva denne boka er ikke: Hvis du virkelig vil ha et nettsted, kan du bare sette opp en enkel butikk og selge det du trenger, legge ut en blogg, legge ut bilder eller videoer eller på annen måte uten å skrive en eneste kodeinje. Denne boken er ikke det. Denne boken vil lære deg hvordan du bygger programvare som er mer nyttig, fullt utUtvalgte, funksjonelle og sikre enn noen programvare du allerede kan finne, fordi den distribuerer den nyeste programvaren som fremdeles er prototyper, kan være dyrt å kjøre i en skala eldre selskaper opererer på, og appellerer ikke til baklengs, innviklede selskaper som er satt opp til Tjen penger for folk som ikke virkelig gjør noe. Hvis du følger denne boken nøye, vil du skrive kode, forskningskode, bygge dine egne apper, og du vil tjene penger på det du gjør. Jeg vil tjene penger på denne boken, selv i tidlige stadier, fordi den inneholder informasjon folk trenger og vil lese, og allerede kjøper når de kjøper eller bruker appene mine. Denne boken vil ikke bygge en app for deg, men den vil peke deg i riktig retning og bevæpne deg med verktøyene du trenger og ferdighetene og tipsene som vil lette din egen suksess med å bygge programvare for nettet, med hver linje i Kode du må skrive som et eksempel, klar til å bli samlet inn i programvare du og dine støttespillere, gjester, klientell,Riends, familie, besøkende, entreprenører og menneskene på internett ønsker å bruke og støtte. Hva du vil lære: Denne boken vil lære deg hvordan du bygger og selger programvare, virkelig funksjonell, nyttig programvare, medieopptak, sikkerhetsfunksjoner som ansiktsgjenkjenning, maskinlesbar sone strekkodeskanning, web -API -er for å autentisere, registrere og gjengi video og bilder, og utveksle meldinger som Bluetooth og nær felt (NFC) kommunikasjon. Denne boken vil lære deg hvordan du bruker en nettverksdatamaskin, med fokus på Debian Linux, hvordan du bygger bash -kode for å lage installasjon og sikkerhetskopiering av programvaren din til en sømløs, automatisert bris, hvordan du bygger Python -kode som en backend for å tjene dynamiske meldinger, stil Ting som pent bruker CSS -stiler med Bootstrap, muliggjør brukerpålogginger og interaktivitet gjennom nettverksenheter, bygg interaktive medier og nettverk med andre nettsteder for å tilby sikkerhetsfunksjoner som tekstmeldinger for verifisering eller andre formål, ID -skanning, bilde og videomoderering, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data.Ransaksjoner for å holde programvaren din sikker, betalingsbehandling, cryptocurrency trading, asynkrone oppgaver og mer. Du lærer hvordan du bygger dine egne Bluetooth -enheter, med batterier, ladere, mikrokontrollere, kretsløp, motorer og sensorer, ved hjelp av lodde, ledning og 3D -trykt samt støpematerialer. Jeg vil demonstrere 3D -design rektorer brukt på additiv produksjon og verktøy og dø, slik at du kan produsere dine egne innebygde, maskinvareenheter med integrerte batterier, ladere, elektroniske kretsløp og funksjonelle utganger. og nettverk dem med Bluetooth og nettet. Spesifikt vil vi undersøke to casestudier, en vibrerende massasje og et hjemmelaget skytevåpen, begge programmert i OpenSCAD, som er tilgjengelig som et grafisk grensesnitt eller kommandolinjeverktøy og kan integreres i en nett for raskere resultater. Du lærer hvordan du bygger og distribuerer et nettsted fra grunnen av uten tidligere erfaring, gjør det funksjonelt, sikkert, vakkert, nyttig og mestMPORTANTITT PRAKTISK. Du lærer hvordan du bruker maskinlæring og datamaskinvisjon for å gjøre et nettsted sikkert og mer praktisk, spille inn video og lyd fra nettstedet ditt, donere stemmen din, lage musikk og modulere lyd for å lage nyttige prøver og hvordan du kan bryte gjennom støyen i Utnytte andre nettsteder for å bygge et best mulig nettverk av nettsteder som du kan koble direkte til ditt for å dele all nyttig informasjon du har å tilby, og enda viktigere bringe folk til programvaren og virksomheten din. Denne boken vil være fokusert mest på media, sikkerhet og maskinlæring, som er de viktigste tre komponentene som vil hjelpe deg med å bygge nyttig programvare for nettet ved å engasjere de rette brukerne og koble fra de gale på en måte som er realistisk, praktisk, Hender på og engasjerende mens de også er automatisk, og solid. Denne boken lærer UNIX, spesielt Debian (Ubuntu), Bash Shell, Python, HTML, CSS, JavaScript og en rekke nyttige programvarepakker forn Like forespørsler, så vel som nyttig bash -programvare som Git og FFMPEG. Jeg vil også lære deg hvordan du kan handle cryptocurrency automatisk, og ta betalinger i cryptocurrency eller fra vanlige debetkort, mens du til og med betaler ut besøkende en andel av inntektene dine hvis du velger å gjøre det. Jeg vil lære deg hvordan du også kan tjene penger på nettstedet ditt gjennom reklame søk som mulig. Jeg vil lære deg hvordan du selger programvaren din, annonserer den, appellerer til kunder som leter etter tjenestene dine og lager et navn for deg selv på internett gjennom veier som allerede eksisterer, er rimelige og fungerer bra. Jeg vil lære deg hvordan du kan lagre dataene dine på Cloud Computers som fungerer for deg og lagre dataene dine billig, hvordan du planlegger og bygger et nettsted som gjør det brukerne dine vil ha og hva du vil, og hvordan du kan holde brukerne dine engasjert avNettstedet et trykk bort på telefonene sine med varsler, e -post, tekstmeldinger, telefonsamtaler og flere veier for å bringe brukerne dine tilbake til nettstedet ditt til din disposisjon bak klikket på en knapp sikret til deg. Denne boken vil fokusere på det praktiske ved å publisere og distribuere medier i store mengder, fra tekst til bilder til videoer til lyd, gjøre et godt inntrykk på sluttbrukere (klientellet ditt) og selge deg selv på noen måte som du gjør for å lage Et nettsted, en app som bare er representativ for deg og deg, og får deg, programvaren din og selskapet ditt til å se bra ut på best mulig måte. Du vil også lære noen tips og triks fra meg, fra kodingstips, praktisk forfengelighet som sminke og fotografering, modellering og skuespill, og mer, noe som vil være viktig for å skildre deg selv og ditt selskap i best mulig lys ved å bruke alle tilgjengelige verktøy til deg mens du distribuerer så mye innhold som du trenger på tvers av en sunn balanse av plattformer for å bringe dine å utøve uten mer krefter, arbeid eller penger enn det som er nødvendig. Denne boken kalles “Practical Web Based Deep Learning and Security By eksempel” av en grunn: den omhandler læring å kode, spesielt for nettet, spesielt med fokus på sikkerhet, fra et praktisk synspunkt, med eksempler på arbeidskode som tjener de praktiske formålene som er skissert i teksten. Læringskomponenten i denne teksten omfatter også maskinlæring, koden jeg vil vise deg hvordan du skal kjøre for nettet som vil håndtere datamaskinvisjon, ansiktsgjenkjenning, bilde- og videomoderasjon, bildeforbedring, oppløsningsforbedring, bildetekst og andre oppgaver som som oppløsning Prediksjonsmålinger hentet fra bilder, for eksempel bildet av bildet som et autentisk, datamaskinoverført bilde, eller en optisk kopi (et bilde av et bilde, eller trykt bilde). Maskinlæring er veldig viktig når det gjelder sikkerhet og programvaresikkerhet, fordi det kan forhåndsformere oppgaver som ellers var umulige. Datamaskinen dinLogg deg inn med en passord, men det kan være tryggere å bruke den hvis den logger deg inn med ansiktet. Du kan lage en serverdatamaskin til denne safe, en datamaskin som normalt vil be deg om et brukernavn og passord og logge deg inn, kanskje med en bekreftelsestoken for hver ny innlogging eller ny IP -adresse, men hvis du bygger stor skala, er det enkelt å Bruk, grunnleggende sikre og kraftig programvare, dette kan være nok. Å binde programvaren din for tett til andres programvare, som en e -posttjeneste eller tekstmeldingstjeneste, er ikke nok til å gjøre programvaren din sikker, eller noen (et hvilket som helst nettsted du bruker). Alle som bygger programvare som er upåklagelig sikker, har en viss følelse av hva dette innebærer. Programvare er iboende usikker fordi enhetene og kontoene vi bruker for å få tilgang til den ikke alltid er til disposisjon, de kan være i hendene på alle med dårlig hensikt for programvaren og kan derfor utgjøre en risiko for selve programvaren. Dette er noe av fokuset i denne boken. En nettverks datamaskin er som standardSikret med en lang nøkkeltoken, kalt og SSH eller Secure Shell -tasten, og er ellers best sikret med en webserver, fordi webserveren gir åpen tilgang så vel som topp moderne sikkerhetsverktøy som kjører på selve serveren. Webserveren har tilgang til brukerens nettleser, som uten tvil er den kraftigste delen av brukerens enhet, fordi det er stedet der brukeren kan få tilgang til nettverksprogramvare. Denne verktøysettet kan gi tekst, websidene du ser, og kan også spille inn bilder, lyd og video (som et bilde av et ansikt eller en tilstands -ID), kan lese og skrive til Bluetooth Radio -enheter, og kan lese og skrive til Near Field Transponder -tagger, rimelige nøkkelkort, fobs, klistremerker, ringer og til og med chip -implantater med unike serienumre som kan leses og skrives til med data generert og validert av en webserver bundet til nettstedet. Ved å bruke alle verktøyene du har til rådighet, vil du med denne boken utstyre deg med kunnskapen til å bygge et sikkert nettsted, og samlet sett aUre nettverks datasystem som fungerer for deg, gir budene dine og ser ut og føles riktig. Hvor du skal begynne: Du er velkommen til å hoppe forbi delen jeg begynner denne boken med, eller en hvilken som helst seksjon, til den nøyaktige koden du trenger, spesielt hvis du har erfaring med koding før eller noen av de nevnte verktøyene jeg vil beskrive i detalj i denne boken som I tillegg til å dokumentere brukssaker og praktiske eksempler på disse. Hvis du ikke har erfaring med å skrive kode, anbefaler jeg at du leser all denne boken, og anbefaler spesielt at du leser de foregående seksjonene, for å sikre at denne boken passer for deg. Hvis denne boka ikke er riktig for deg, kan du vurdere å gi den til en venn eller slektning som kan være interessert i Lærer eller andre lærere gjorde det før meg. Start hvor du vil, vil hver del av denne boken være nyttig hvis du har tenkt å bygge en nyttigPP, og vurder at de beste appene er bygget med sluttbrukeren i tankene: Kjenn kunden din. Nå kjenner du meg, du kjenner denne boken, og du er klar til å begynne. For å starte, ta en datamaskin (til og med den billigste bærbare datamaskinen fra en boksebutikk, Amazon eller et gammelt stasjonære fungerer, og sett den opp på en måte som fungerer for deg. Hvordan lese denne boken: Tekst fremhevet, betegner at teksten tilhører en ledetekst, der du vil skrive koden du kjører. Kommandoprompet er tungt tastaturfokusert og krever lite eller ingen klikking, fremskynder arbeidsflyten og gjør ting enklere for deg. Komme i gang: La oss dykke inn. Vi starter med å bygge kode på en lokal maskin og begynne uten å bygge et nettsted koblet til Internett. Dette er tryggere til å begynne med, koster ingenting og er lett for deg. Avhengig av operativsystemet ditt, vil det være litt annerledes å komme inn i et bashell. For Mac OS, anbefaler jeg å installere en virtuell maskin på dette tidspunktet, da du vil få mest kompatibilitet medVirtuell maskin. Ulike leverandører som VirtualBox og Paralells kan kjøre en virtuell maskin for deg, selv om det også er mulig å installere Ubuntu direkte på maskinen, hvis du foretrekker å bruke et innfødt miljø som anbefales for å skape en rask, strømlinjeformet opplevelse. Hvis du bruker Linux eller Windows, som jeg anbefaler, skal det være ganske enkelt å lage et prosjekt. Åpne terminalen, juster størrelsen slik du ser passet, og begynn å følge trinn 2. Hvis du bruker Windows, kan du følge trinn 1. Trinn 1: - Bare Windows -brukere I Windows, Open Command -ledeteksten som administrator og type WSL –Install Trinn 2: - Fortsett her, eller hopp over trinn 1 til her hvis du ikke bruker Windows I en åpen terminal, (avhengig av OS, kalt Ubuntu i Windows, Terminal i Mac eller Linux, eller et lignende navn), begynner du med å lage et prosjekt. Vi gjør dette med mkdir -kommandoen, som oppretter en katalog. Hvis du trenger å lage en katalog for å lagre prosjektet ditt, som anbefales, brukCD -kommando for å endre til katalogen og og og CD/PATH/TO/DIRECTORY - The Path er mappene (filene) som går foran din destinasjonskatalog, din standardbane er ~ eller/Home/Brukernavn (der brukernavn er ditt brukernavn). For å endre til standardkatalogen, skriv CD eller CD ~ mkdir eksempel - erstatt "eksempel" med navnet på katalogen Nå har du en arbeidskatalog for prosjektet ditt. Som det er så viktig å få denne katalogen lagret i tilfelle du trenger å bytte til en annen maskin eller distribuere koden du skriver, så den er klar for nettet, vil vi bygge et skript for å sikkerhetskopiere katalogen din i de neste trinnene. Men å bygge et skript tar litt kode, og kode må automatiseres for å være så nyttig som mulig. Så la oss bygge et manus for å bygge skript først. La oss starte med å lage skriptet og gjøre det kjøres. Vi bruker sudo, chmod og berøring for dette, og ringer manuset


sudo touch /usr/bin/ascript
sudo chmod a+x /usr/bin/ascript
sudo nano /usr/bin/ascript
Nå har vi laget skriptet, gjort det kjøres og er klare til å redigere det. Nano er en tekstredigerer som lar deg redigere tekst uten å klikke, noe som er mye enklere enn å bruke et grafisk brukergrensesnitt. For å redigere en fil med Nano, bruk Nano og deretter banen til filen. For å lage et skript som lager et skript, er det ganske likt å lage skriptet vårt i utgangspunktet. Vi bruker den samme koden som ovenfor, og erstatter navnet på skriptet, "Ascript" med en argumentparameter, $ 1. Dette lar oss ringe skriptet ved å skrive ganske enkelt Sudo Ascript Newscript, på hvilket tidspunkt vi kan lage et nytt skript ved å erstatte "Newscript" med navnet på skriptet ditt. Koden i Nano skal se ut:

sudo touch /usr/bin/$1
sudo chmod a+x /usr/bin/$1
sudo nano /usr/bin/$1
Og for å lukke Nano, kan vi holde ned kontrollnøkkelen og trykke X, deretter Y for å betegne at vi lagrer filen og treffer retur. I stedet for å skrive disse tre kommandoene for å redigere et skript, vil vi kunne skrive Sudo Ascript Ascript for å redigere skriptet igjen. Dette fungerer! Og ethvert nytt skript kan kjøres enkelt ved å ringe det i skallet. La oss lagre arbeidet vårt nå: La oss skrive et sikkerhetskopieringsskript for å lagre det nye skriptet vårt og deretter sikkerhetskopiere det i prosjektkatalogen vår, samtidig som vi sikkerhetskopierer backup -skriptet.

sudo ascript backup
Nå, i Nano:

sudo cp /usr/bin/backup /path/to/directory/
sudo cp /usr/bin/ascript /path/to/directory/
Hvor/bane/til/katalog er veien til prosjektet du opprettet med MKDIR. Senere vil vi lære å kopiere gjentatte stier som denne med en sløyfe og en liste, som er mindre kode, men foreløpig la oss holde det enkelt og ha noen få linjer. For å kjøre dette skriptet og sikkerhetskopiere koden din, lagre filen i Nano med kontroll+x, y og returnerer, og skriv nedenfor i skallet ditt

backup
Hvis du i det hele tatt blir bedt om et passord mens du leser denne boken og følger med i skallet, vennligst skriv inn brukerpassordet ditt riktig, vil du ha tre forsøk før du trenger å kjøre kommandoen på nytt. Du kan bruke pilene opp og ned til å kjøre kommandoer og redigere dem, hvis du trenger å kjøre noe to ganger. Enkelt trykk opp og ned av og ned for å velge en kommando, før du redigerer kommandoen med høyre, venstre piler og slett tast så vel som tastatur, og kjører den med retur. Gratulerer! Du klarte å lage et fantastisk sikkerhetskopieringsskript som sikkerhetskopierer to viktige skallskript i arbeidskatalogen din. Vi kan flytte ting rundt senere etter hvert som prosjektet blir større, men dette fungerer for nå. La oss gå videre til sikkerhetskopiering i sky programvare når du gjør dem til en server, mensgjør det også mulig for deg å laste ned hele kopier av programvaren din bak et passord eller tast. Det er medvirkende til å lagre programvaren din, spesielt når vi migrerer til sikrede Linux -forekomster som noen ganger går i stykker når en enkelt kodelinje mislykkes, og lar deg være låst ut mens koden din kanskje ikke blir sikkerhetskopiert hvis du ikke får sjansen til å støtte den opp automatisk, som vi vil dekke. Hvis du ikke allerede bruker en Virtual Ubuntu Virtual Machine på dette tidspunktet, anbefaler jeg å bruke en Ubuntu Virtual Machine på dette tidspunktet fordi det vil gjøre livet ditt enklere når du installerer alle pakkene som er nødvendige for å bygge et fungerende nettsted og forme dyp læring drift på datamaskinen din. Vi vil flytte koden til en webserver i nær fremtid, men vi vil sørge for at det er minst noen få lag med sikkerhet bak webserveren vår som er motstandsdyktige mot phishing, og bruker en rekke Linux -pakker for å gjøre dette. Hvis du fremdeles vil bruke Mac OS, er du velkommen til å søke etter og installereE nødvendige pakker på nettet, men det er kanskje ikke alternativer for hver pakke denne boken eller serien vil dekke. La oss legge til noen få kommandoer for å begå vårt arbeid med sikkerhetskopieringsskriptet ved å kjøre kommandoen Sudo Ascript

# ...
git add –all
git commit -m “backup”
git push -u origin master
Nok en gang kan du kontrollere X for å lagre. Nå må vi gjøre en engangskonfigurasjon for dette prosjektet. Fordi det snart vil være et Git -prosjekt, trenger vi ikke å skrive hver kommando hver gang vi distribuerer fra et Git -depot, men vi får tak i dette når vi skriver distribusjonsskriptene våre. For å starte, la oss sørge for at vi er i riktig katalog og initialiserer Git -depotet og genererer SSH -tastene.

cd /path/to/directory
git init
git branch -m master
ssh-keygen
Etter at vi har skrevet SSH-KeyGen, bør den nye tasten lagres i hjemmemappen under en mappe kalt .SSH. Det kalles id_rsa.pub. La oss finne denne nøkkelen og kopiere den. Å se det,

cd ~
cat .ssh/id_rsa.pub
Kopier teksten som returneres av den siste kommandoen, og opprett en konto med din GIT -leverandør (ideelt GitHub), før du legger til SSH -tasten til kontoen din. Når du har en konto, klikker du på den øverste høyre menyen og angir innstillinger, før du legger til SSH -tasten i SSH- og GPG -tastene under tilgang i menyen. Velg Legg til en SSH -tast og legg til din ved å lime den inn og gi den en tittel, før du lagrer og går tilbake til Github for å opprette et nytt depot. Dette er likt for andre GIT -leverandører, du må lese dokumentasjonen deres. I den nye depotkonfigurasjonen, gi depotet ditt et beskrivende navn og bestemme om du vil publisere det, og sørg for å konfigurere ingen filer for inkludering ennå. Når depotet er opprettet, kopierer du klonen med SSH URL, og lim den inn i følgende kommando.

git remote add git://… (your remote URL)
Nå kan du flytte tilbake til depotet ditt med CD, du vil være kjent med dette. Prøv sikkerhetskopieringsskriptet ditt nå med sikkerhetskopi Stor! Nå kan vi virkelig få koding. La oss installere Django nå som vi har et godt grep om bash og git. Django vil la oss automatisk sikkerhetskopiere programvaren vår, Bash kan gjøre dette også, men Django bør ha en enklere tryggere implementering (den kan deaktiveres og konfigureres lettere). For å installere programvare i Ubuntu, bruker vi Sudo Apt-Fet-kommandoen. La oss først oppdatere og oppgradere programvaren vi allerede hadde. Dette kan gjøres med sudo apt-get update og sudo apt-get oppgradering -y. Neste, la oss installere Python og vårt virtuelle miljø, hjemmet til koden vår, med følgende kommando: sudo apt-get installere python-er-python3 python3-venv Dette er alt du trenger for å komme i gang med Django når det gjelder programvareinstallasjoner i Ubuntu -forekomsten. For Windows og Linux skal dette være ganske greit, men for Mac kan det være lurt å installere en virtuell maskin ogLinux på det ved å bruke et gratis eller betalt virtuelt miljø som VirtualBox eller Paralells Desktop og gjenskape trinnene over for å sette opp et Ubuntu -miljø. Ubuntu er kritisk i dette tilfellet fordi det er programvaren nettstedene kjører og det gjør dem i stand til å være vertskap for nettsteder med all den nevnte programvaren. La oss grave i Django. I katalogen vår igjen, med

python -m venv venv # Oppretter det virtuelle miljøet der kode lagres
source venv/bin/activate # Aktiverer det virtuelle miljøet
pip install Django
django-admin startproject mysite . # Hvor mysite er prosjektet jeg begynner i min nåværende katalog.
Django er bare i gang, fordi Django er vertskap for webserveren og gjør alt vi trenger for å få et grunnleggende lokalt nettsted i gang. Nå som vi har Django installert, la oss redigere innstillingene litt for å få det til å fungere hvordan vi trenger. La oss først lage en ny app

python manage.py startapp feed
Du vil merke at den første appen heter Feed. Appen skal kalles hva du vil, og vi oppretter nye apper, men navnet på hver app må være konsistent hver gang appen blir referert til i koden. For å legge til en ny app, vil vi alltid redigere innstillingene. Bruker nano,

nano app/settings.py
I innstillingene, finn installerte_apps og skill [] i 3 linjer. Bruk fire mellomrom på den tomme midtlinjen, legg til 'feed', eller navnet på appen din. Denne delen av innstillingene. Py skal se ut som:

INSTALLED_APPS = [
    'feed',
]
Før vi glemmer, la oss teste at Django fungerer. Ved å bruke kommandoen python administrere.py runserver 0.0.0.0:8000, kan vi kjøre serveren og deretter navigere i en nettleser på datamaskinen som kjører koden til http: // localhost: 8000 og se et eksempel på websiden (den fungerer!) Avslutt serveren med kontroll C, den samme som alle andre kommandoer. La oss nå grave i å skrive noen Python -kode. Django har tre hovedkomponenter, alle kjøres helt etter kode. Komponentene kalles modell, visning og mal, og hver er på henholdsvis et høyere og lavere nivå før websiden blir levert til brukeren. Modellen er koden som lagrer informasjon i databasen for henting, sortering og gjengivelse. Visningen bestemmer hvordan modellen blir gjengitt, manipulert og modifisert, nesten alle visninger vil bruke en modell direkte. Malen er HTML -koden med noen ekstra bjeller og fløyter som kalles malspråk. Malen er gjengitt av visningen der den er fylt med python -kode ogKontekst som modeller og informasjon (usuall strenger og heltall) fra visningen. Django har andre komponenter også, inkludert, men ikke begrenset til: Innstillinger, som konfigurerer appen som vi diskuterte. URL -er, som er mønstre som brukeren følger for å få tilgang til spesifikke deler av webapplikasjonen. Skjemaer, som definerer hvordan informasjon som sendes til serveren håndteres og gjengis til databasen så vel som til brukeren. Dette er grunnlaget for å behandle informasjon på serversiden, og kan godta enhver form for informasjon datamaskinbutikkene, spesielt tekststrenger, tall og sanne/falske booleanere (vanligvis avkrysningsruter). Maler, som er HTML -kode og malspråk og broer gapet mellom Python og HTML, noe som betyr at Python -informasjon kan serveres som HTML -kode som alle kan få tilgang til og kan sikre et nettsted med begrenset tilgang, samtidig som du gjør Python -koden tilgjengelig på nettet og nyttig for en rekke formål på en ekstern enhet som ikke gjør deteed for å være i nærheten av serveren. Statiske filer, som vanligvis er JavaScript og det er biblioteker som serveren serverer og er koblet inn med malen. Mediefiler, som serveren serverer eller er eksternt vert, eller nettopp skrevet til serveren før den blir behandlet og lagt ut til en annen server (en bøtte) for hosting. Middleware, som er kodebiter som kjøres samtidig som alle syner og anses som "inkludert" i visningen. Kontekstprosessorer, som behandler konteksten til hvert syn og brukes til å legge til ekstra kontekst. Tester, som validerer at brukeren eller forespørselen vedtar visse krav før visningen er gjengitt. Forbrukere, som dikterer hvordan websockets håndterer og reagerer på kommunikasjon. Administrator, som brukes til å registrere modeller slik at de kan manipuleres i detalj på Django Admin -siden, der databasen kan administreres gjennom et grafisk grensesnitt. Selleri, som definerer asynkrone oppgaver deler av Django -koden kan begynnenning før du umiddelbart fortsetter til neste oppgave eller kodelinje. Django kan ha mange andre komponenter, som vi vil diskutere i detalj her. Det er mange måter å gjøre Django mer funksjonelle, og legge til websockets, som er raske, strømlinjeformede kommunikasjonskanaler, selleri, som utfører asynkrone oppgaver, og et mangfold av andre programvare for å utvide Django, spesielt i visningsfunksjonene, der det meste av Koden utføres. Visningsfunksjoner er nøkkelen fordi de vanligvis erklærer hvert kode som er spesifikt for et spesifikt URL -mønster, eller en del av serveren. La oss først utforske visningsfunksjoner. Vis funksjoner begynner med import som betegner kode som vil bli brukt i visningen, og er definert ved hjelp av vanlige funksjonsdefinisjoner eller klasser. De enkleste visningene er definert av funksjonsdefinisjonen DEF, og returnerer en HttpResponse med en grunnleggende mal. La oss starte med å definere et grunnleggende visning for å returnere teksten “Hello World”. Husk at hver gang du legger tilFor en uttalelse som def, hvis du, for osv., må du legge til 4 mellomrom for hver av de foregående definisjonene du vil bruke på funksjonen din. Vi vil komme inn på hva hver av disse snart betyr. Fra nettstedets katalog, rediger Feed/Views.py -filen ved hjelp av Nano og legg til følgende linjer til slutten av

from django.http import HttpResponse

def hello(request):
    return HttpResponse('hello world')
Djangos HttpResponse svarer med en tekststreng, betegnet med åpningen og lukkingen. Hver gang du gir informasjon til en funksjon eller klasse, som forespørsel eller en streng, må du bruke parentes (, åpning og lukking). Dette er ikke alt vi trenger for å se vårt syn ennå. Vi har selvfølgelig ikke fortalt serveren hvor visningen er nøyaktig, vi må fortsatt definere en bane som visningen skal gjengi. La oss starte med å definere en grunnleggende vei i app/urls.py, og vi kommer inn i banegrupper senere. I app/urls.py, legg til en linje etter importuttalelsene etter at begynnelsen har importert visningen vi nettopp opprettet.

from feed import views as feed_views
La oss nå definere visningsmønsteret. Vismønstre har tre komponenter, banekomponenten, som forteller serveren hvor visningen eksisterer på serveren (URL -banen som brukeren skriver inn i navigasjonslinjen for å gå inn i websiden), visningskomponenten der visningen er spesifisert, og en Vennlig navn for visningen, så det er enkelt å hente mønsteret når du jobber med en mal, spesielt slik at navnet kan endres og oppdateres om nødvendig for å gi plass til en annen visning eller ta på seg et mer logisk navn. Det er fornuftig å gjøre ting på denne måten og være fleksibel, fordi kodebasen din vil være et stadig skiftende miljø som trenger fleksibilitet og improvisasjon for å være verdifull og enkel å jobbe med. Slik vil synet ditt se ut, du kan legge dette til UrlPatterns = [delen av appen/urls.py. Visemønsteret er definert med de tre komponentene beskrevet ovenfor, og en funksjon som kalles bane. URL -mønstrene dine er en liste, så sørg for alltid å avslutte hvert element i demmed et komma, fordi dette skiller hver enkelt. Hvert element skal også gå på en ny linje, nok en gang med fire mellomrom før den, akkurat som appen i innstillinger. Vi vil definere den første komponenten i visningen med en tom strengfunksjon, for å lage en visning som kjører på rotkatalogen til webserveren. Nettadressene dine skal nå se ut som

from feed import views as feed_views

urlpatterns = [
    path('', feed_views.hello, name='hello'),
]
Dette er grunnlaget for å opprette et nettsted med Django som er helt statisk. For å lage et mer dynamisk nettsted der vi kan begynne cacheinformasjon, som bilder, videoer, lyd og mer, må vi bruke modeller, som vi vil utforske neste gang. Foreløpig, la oss sjekke koden vår og kjøre serveren. For å sjekke koden for feil, kjør: Kjør:

python manage.py check
Hvis det er noen feilmeldinger, bør du nøye gjennomgå endringene du har gjort i appen din og se om det er noe som må løses, som et eksternt eller manglende rom, en ekstra karakter, en ikke -lukkede streng, hvilken som helst skrivefeil, en hvilken som helst ved et uhell slettet karakter, eller noe annet. Les gjennom feilmeldingen (hvis du har en), bør du kunne se veien til en fil du opprettet eller redigert sammen med et linjenummer, så se på den filen og linjen og se om du kan fikse noe som er der . Hvis du har løst problemet, kjør kommandoen ovenfor igjen. Når programvaren din er klar til å kjøre og fungerer, vil du se utdataene "Systemkontroll identifiserte ingen problemer." Nå er du klar til å dra. Kjør serveren med:

python manage.py runserver 0.0.0.0:8000
Nå åpner du en nettleser og navigerer til http: // localhost: 8000. Du bør se teksten som returneres i parentesen og sitater av HttpResponse -funksjonen etter ditt syn. Dette er bare et grunnleggende eksempel, men hvis du klarte det så langt, forstår du det grunnleggende om hvordan Linux, Bash, Python og Django fungerer. La oss grave dypere i noen databasemodellering, og utforske kraften til en Python -klasse når det gjelder lagring av informasjon. Deretter vil vi begynne å få tak i HTML og CSS før vi gjør nettstedet vårt fullt omtalt, fleksibelt og sikkert ved hjelp av JavaScript og maskinlæring. Klassene lagres i modellene. Bruk Nano, rediger app/modeller.py og legg til en ny klasse. En klasse er definert med klassedefinisjonen og sendes en superklasse som den arver fra, i dette tilfellet modeller. Modell. Navnet på klassen kommer etter klassedefinisjonen, og etter klassedefinisjonen A: (tykktarm) er brukt, før attributtene og funksjonsdefinisjonene knyttet til klassen er betegnet nedenfor. Klassen vårTrenger en ID vi kan bruke for å hente den og holde den unik, og den trenger også et tekstfelt for å lagre litt informasjon. Senere kan vi legge til en tidsstempel, filer, booleanere (sanne eller falske definisjoner som kan hjelpe koden vår med å ta beslutninger om hva vi skal gjøre med modellen, og kan brukes til å sortere den), en forekomst for å knytte modellen til en brukerlogget inn i serveren, og mer. La oss pakke ut koden

from django.db import models # Importen som brukes til å definere klassen vår og den er attributter

class Post(models.Model): # Definisjonen av klassen vår
    id = models.AutoField(primary_key=True) # IDen til modellen vår, en automatisk generert nøkkel som lar oss spørre modellen, holde den unik og er nyttig når vi trenger å samhandle med modellen når den er opprettet.
    text = models.TextField(default='') # Attributtet våre klassebutikker, i dette tilfellet, noen tekst, som misligholder en tom streng.
Lukk og lagre filen som vi gjorde før for å fullføre. Det er mange andre felt og alternativer vi vil utforske når vi oppdaterer denne klassen når appen vår utvikler seg, men dette er de grunnleggende nødvendighetene ved å lage en app for å legge ut litt tekst. Imidlertid vil denne modellen ikke fungere alene. Som beskrevet tidligere, trenger vi en tilpasset visning og tilpasset URL -mønster for å få denne modellen til å fungere, og vi trenger også et skjema sammen med en mal. La oss utforske skjemaet først. For å definere et skjema, rediger APP/Forms.py med Nano og legg til følgende linjer. Vi trenger to importer, vår skjema -klasse, så vel som modellen vi opprettet (Feed.Models.post), en klassedefinisjon som ligner på modellen, og et felt sammen med en underklasse kalt Meta som vil definere modellen formen samhandler med. Skjemaet kan også ha en initialiseringsfunksjon som setter den opp basert på informasjon i forespørselen, modellen eller på annen måte, vi vil utforske dette senere. Modellformer er så nyttige fordi de kan lage en modell eller også redigere en modell,Så vi vil bruke dem til begge deler. La oss definere en i forms.py

from django import forms
from feed.models import Post

class PostForm(forms.ModelForm):
    text = forms.CharField(widget=forms.Textarea)
    class Meta:
        model = Post
        fields = ('text',)
Dette er det grunnleggende om hvordan en form og modell ser ut. Denne modellskjemaet kan brukes til å instantisere eller redigere et innlegg, og endre teksten den inneholder. Vi ser på å integrere dette skjemaet i en visning neste. La oss først gjøre migrasjonene og migrere databasen slik at koden vår kan samhandle med modellen når den kjører. For å gjøre dette, kjør følgende kommandoer:

python manage.py makemigrations
python manage.py migrate
Dette vil ta et øyeblikk å utføre, men når det gjør det, vil det gi deg tilgang til modellen i visningene, mellomvaren eller hvor som helst ellers i programvaren. La oss fortsette med å gjøre et syn der vi kan se modellen vår. Rediger feed/views.py og legg til følgende kode, som nevnt. Du trenger ikke å legge til noe etter # tegnet, den koden er kommentarer som brukes til å betegne informasjon om koden. Vi starter med å importere modellen vår i visningene, og legge den til en kontekst der vi kan gjengi den i en mal som en liste for visning. Deretter vil vi legge til en mal der vi kan gjengi skjemaet og modellen med en knapp for å opprette et nytt objekt basert på modellen og legge den ut på serveren. Dette høres komplisert ut, så la oss bare ta det trinn for trinn. Før vi er ferdig med visningen, la oss lage en mal som bare gjengir modellen og sørger for at vi kan se den ved å lage et nytt innlegg i skallet. Slik skal den visningen 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() # Spør alle innleggene i databasen så langt
    return render(request, 'feed/feed.html', {
        'posts': posts,
    })
Alt dette ser ganske enkelt ut til vi kommer til bunns. Gjengivelse, verdien som er returnert av funksjonen i stedet for i et HTTP -svar som det forrige eksemplet, tar alltid en forespørsel som den første inngangen, godtar en kontekst (i dette tilfellet innleggene i databasen), som nå kan gjengis i malen , og returnerer malen som er definert i funksjonen. Malen kommer til å være et HTML -dokument med litt av et språk som heter Jinja2, som gjør Python -informasjon til HTML. For å begynne å lage maler, lag to kataloger i feed.

mkdir feed/templates
mkdir feed/templates/feed
Deretter redigerer du en mal i katalogen ovenfor, feed/maler/feed, og legg til koden for dette eksemplet. La oss se på malen for dette eksemplet.
 
<!doctype HTML>
<html>
<body>
<legend>Feed</legend>
<hr>
{% for post in posts %}
<p>{{ post.text }}</p>
{% endfor %}
</body>
</html>
 
Dette er en veldig enkel mal. Den definerer åpnings- og lukking malen. Dette er alt som trengs for å gjengi innlegg, men det er ingen i databasen ennå. La oss lage noen med skallet. Vi kan kjøre skallet med Manage.py

python manage.py shell
La oss nå importere innleggsmodellen vår

from feed.models import Post
Deretter lager vi et enkelt innlegg med en streng og avslutter skallet. Strengen kan være hva som helst, så lenge det er gyldig tekst.

Post.objects.create(text='hello world')
exit()
Til slutt må vi legge til et URL -mønster i feeden vår. Fordi feed -appen vår vil bruke flere nettadresser og vi ønsker å holde filstørrelser små, la oss lage en lokal nettadresser i fôrappen vår som ser slik ut:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.feed, name='feed'),
]
Vi må også redigere nettadressene i basen, uansett hva vi bestemte oss for å kalle det, dette var den første katalogen vi opprettet. Rediger app/app.py og legg til følgende i URL -mønstrene

from django.urls import include # øverst

urlpatterns = [
    # ... Forrige kode her
    path('feed/', include(('feed.urls'), namespace='feed')),
]
Når vi kjører serveren med Python Administrer.py Runserver, vil vi se siden vi opprettet fordi vi har modell, visning og mal så vel som URL -mønster, sammen med elementer i databasen. La oss deretter implementere skjemaet vi opprettet og begynne å lage våre egne innlegg. Men før vi skriver for mye kode, la oss lage en sikkerhetskopi ved hjelp av skriptet vi skrev tidligere, sikkerhetskopiering. Kjør dette skriptet i skallet, vent noen få øyeblikk, og all koden vil bli sikkerhetskopiert til Git -depotet vårt.

backup
Å implementere skjemaet er relativt enkelt. Vi vil importere skjemaet vårt, legge til en postforespørsel til visningen og lagre innlegget i databasen før vi omdirigerer til samme visning. Vi kan bruke viderekoblingsfunksjonen vi allerede importerte, og en annen funksjon som heter Reverse for å få URL -en for visningsmønsteret. Vi spør om dette med strengen 'Feed: Feed' fordi navneområdet til det inkluderte mønsteret er fôr, og utsikten kalles også fôr.

from feed.forms import PostForm

def feed(request):
    posts = Post.objects.all() # Spør alle innleggene i databasen så langt
    if request.method == 'POST': # Håndtere innleggsforespørselen
        form = PostForm(request.POST) # Opprett en forekomst av skjemaet og lagre dataene i det
        if form.is_valid(): # Valider skjemaet
            form.save() # Lagre det nye objektet
        return redirect(reverse('feed:feed')) # Omdirigere til den samme URLen med en get -forespørsel
    return render(request, 'feed/feed.html', {
        'form': PostForm(), # Sørg for å gi skjemaet inn i konteksten slik at vi kan gjengi den.
        'posts': posts,
    })
Nå må vi oppdatere malen for å gjøre rede for det nye skjemaet. Vi kan gjøre dette ved å bruke
Tag i HTML og gjengi skjemaet i HTML -malen med en innsendingsknapp. Vi trenger også et CSRF -token, et token som forhindrer eksterne steder i å legge ut til skjemaet uten først å laste en side.
 
<!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>
 
La oss bryte dette ned. Det er en ny formklasse, et symbol, selve skjemaet og en innsendingsknapp. Ganske enkelt, men når vi ser på det, kan det være lurt å få det til å se bedre ut. Det fungerer, vi kan legge ut nye innlegg med skjemaet, og de er nå lagret i databasen. Det er noen få ting som skjer her. Vi bruker HTML -tagger for å erklære at dokumentet er et HTML -dokument, vi bruker en malkode ({ % ... %}) for å gjengi token for skjemaet, og en annen, {{…}} for å gjengi skjemaet. Vi har også en løkke for å gjengi teksten ved hjelp av blokkmerker og en malkode. Blokkmerker er veldig viktige fordi vi kan definere hvordan seksjoner av malen blir gjengitt med dem, og malmerker er grunnlaget for hvordan vi legger variabler i koden vår. Nå må vi få appen til å se bedre ut, for nå ser den veldig grunnleggende ut. Vi kan gjøre dette ved å bruke CSS, enten inline, eller i klasser knyttet til hvert objekt i dokumentet. CSS er veldig hyggelig fordi det forteller alt på siden hvordan det skal se ut,og kan få det til å se veldig bra ut. Det er noen få biblioteker som kan gjøre dette, men min personlige går til er Bootstrap. Bootstrap kan lastes ned fra nettstedet deres,getbootstrap.com/. Når du er der, trykk på knappen for å lese installasjonsdokumentene, og kopiere koden fra Include via CDN -delen. Du trenger denne koden øverst i HTML -dokumentet ditt, i et kode som heter Head. La oss også gå foran og opprette en base mal slik at vi ikke trenger å gjenskape disse koblingene i hver mal. Lag en ny katalog som heter maler med MKDIR -maler, og rediger deretter maler/base.html. Det skal se slik ut:
 
<!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>
 
Sørg for å kopiere CSS og JavaScript, .css- og .js -filene, fordi vi trenger JavaScript for å gjøre nettstedet vårt mer funksjonelt i fremtiden. La oss nå komme tilbake til bashskallet og kjøre en rask kommando. Husk at hvis du noen gang trenger tilgang til det virtuelle miljøet, skriver du kilden VENV/BIN/Aktiver. Dette lar deg installere Python -pakker lokalt på en måte som lar Django få tilgang til dem. For å gi våre skjemaer generert av Django Bootstrap -klasser, vil vi bruke en Python -pakke kalt Crispy Forms. Vi kan laste ned dette med følgende kommando

pip install django-crispy-forms
Når dette er installert, kan du legge den til innstillingene.

INSTALLED_APPS = [
    # ... Forrige kode her
    'crispy_forms',
]
Nå, tilbake i feedmalen vår, kan vi fjerne noen ting. La oss fjerne begynnelsen og slutten av dokumentet og erstatte det med arv fra basismalen vår, ved hjelp av utvidelse og blokkeringsdefinisjonen. Vi vil også legge til en malfilterimport med belastning og et malfilter til skjemaet. Til slutt, la oss legge til en bootstrap -klasse i knappen på skjemaet for å få den til å se mer ut som en knapp. Det skal se slik ut:
 
{% 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 %}
 
Vakker! Det er ganske mye kode allerede. Deretter bør vi teste det ut og sørge for at vi kan se at alt ser fint ut, og også være sikker på at alt fungerer som det skal. Kjør serveren i henhold til tidligere instruksjoner og sørg for at nettstedet ser ut og fungerer i orden. Flott jobb! Du er klar til å gå videre til neste trinn, der vi vil legge til brukerpåloggingsfunksjonalitet ved å bruke lignende nettadresser, skjemaer, visninger og maler. Basismalen er viktig, og vi vil fortsette å endre den og gjøre endringer etter behov, men foreløpig la oss fokusere på å gjøre nettstedet vårt sikrere, ved å gjøre det mulig for brukere å logge på med et brukernavn og passord, og til slutt enda viktigere informasjon som vil bidra til å holde appen din sikker og din egen konto tilgjengelig bare av deg. For å gjøre dette, må vi bruke brukermodellen innebygd i Django. Brukermodellen er en databasemodell, som vårt innlegg, som kan gjengis for å logge en bruker på nettstedet. I fremtiden, før vi distribuerer nettstedet til internett, vil viUtvid denne modellen med andre modeller som tilskrives den, og bygg ytterligere sikkerhetstiltak for innloggingen som er motstandsdyktige mot phishing. Vi begynner med å bruke noen innebygde påloggingsformer som Django gir. La oss først opprette en ny app som vi vil bruke for å gjengi malene og visningene for den grunnleggende påloggingssiden. Vi vil også lage andre apper for å representere de fortsatte påloggingsutfordringene for å sikre appen, inkludert en Pincode, ansiktsgjenkjenning, nær feltkommunikasjon, eksterne enheter, multi -faktorautentisering og fingeravtrykkgjenkjenning. Vi snakket allerede om å starte en app. Fra katalogen vår, i det virtuelle miljøet, pass administrer.py disse

python manage.py startapp users
Nå skal vi ha en katalog for den nye appen. La oss starte med å lage en visning i den katalogen som tilsvarer brukerpålogging. Django har innebygd visninger for brukerpålogginger, men disse vil ikke være egnet for oss fordi vi trenger en tilpasset visning, noe som helst gjøres med en definisjon. I denne visningen vil vi starte med å se etter en etterforespørsel, passforespørsel. Post til en påloggingsform importert fra Django, autentisere brukerkontoen og logg inn brukeren før vi omdirigerer dem til feed -appen vår. I brukere/visninger.py, legg til følgende kode

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å brukernavn og passord fra innleggsforespørselen
        password = request.POST['password'] # Autentiser brukeren
        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()})
Dette er alt du trenger for en grunnleggende påloggingsvisning. La oss nå lage et skjema for visningen ved å utvide basemalen. Vi starter med å opprette en ny katalog for maler i brukermappen.

mkdir users/templates
mkdir users/templates/users
Nå skal vi kunne redigere brukere/maler/brukere/login.html. Mens vi er inne på det, oppretter vi en mal for å la brukeren også registrere seg.

nano users/templates/users/login.html
Nå, i malen,
 
{% 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 %}
 
Dette er det grunnleggende i en påloggingsmal. Det er egentlig akkurat som den andre malen i struktur, men den ser litt annerledes ut når den er gjengitt. Vi kan kopiere denne koden for å bygge en annen veldig lignende mal kalt register.html, hvor vi vil endre ordlyden og bruke et nytt skjema vi bygger. La oss lage malen først. Rediger brukere/maler/brukere/register.html og legg til følgende kode:
 
{% 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 %}
 
La oss nå bygge et skjema for vår brukerregistrering og sirkel tilbake til visningene før vi oppgraderer brukerloggene våre med en modell. Vi vil gjøre dette skjemaet grunnleggende til å begynne med, men innlemme flere detaljer og sikkerhetsfunksjoner som avtaler og CAPTCHA i fremtiden. Rediger skjemaene med Nano -brukere/forms.py, og legg til følgende kode.

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 annen form her, som fungerer ganske enkelt. Det er et brukerregisterskjema med et brukernavn, e -post og passord, samt et bekrefte passordfelt. Merk at dette skjemaet ikke utvider de vanlige skjemaene. Formeklassen, det er en modellform som betyr at den har en meta. Ett felt er definert akkurat det samme, og klassemeta definerer modellen skjemaet tilsvarer resten av informasjonen som vil bli skrevet til skjemaet. Det meste av dette eksisterer allerede i Djangos innebygde brukerkreasjonsform, så vi vil bruke det som grunnlag for klassen (passert i parentesen). Deretter vil vi undersøke visningen for å registrere en bruker, nå som vi har et skjema og en mal. Dette er en modelform, akkurat som den i den nye postvisningen. Rediger brukere/visninger.py og legg til følgende kode:

# ... beløp
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})
Dette er alt vi trenger for å få en bruker registrert, men vi bør ha mer informasjon. Vi ønsker å vite tiden brukeren registrerte, hvilken tid de var sist på nettstedet, noe informasjon om dem, som en biografi, tidssone osv. Også vi må oppdatere feedmodellen vår, post, for å gjøre rede for brukeren modell- og attributtinnlegg til hver bruker. For å gjøre det, vil vi oppdatere modellene.py i begge appene. La oss starte med å redigere feedmodellen. Det skal se slik ut nå:

from django.db import models # ... beløp
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') # Legg til denne linjen
    text = models.TextField(default='')
Vær oppmerksom på den andre linjen som ble lagt til filen. Dette er en utenlandsk nøkkel, som vil tilskrive hvert innlegg til en enkelt bruker per innlegg, slik at vi kan sørge for at vi lagrer innleggene på bruker-per-brukerbasis og at det ikke kan gjøres noe innlegg uten å tilskrive det til en bruker. Vi definerer denne utenlandske nøkkelen med klassen den representerer, et slett argument for å sikre at innlegg blir slettet med brukere, null og blanke argumenter for å sikre at vi kan fjerne brukeren om nødvendig, og for å imøtekomme mangelen på en bruker på innlegg vi allerede opprettet, og et beslektet navn, som vi kan bruke for å referere til innleggsobjektene brukeren oppretter. Dette relaterte navnet, i motsetning til Post.author, forfatteren av innlegget, gir oss bruker som la ut selve innlegget. Vi kan nå få innleggene en bruker laget av Running User.posts.all (), eller forfatter.posts.all (). La oss nå gjøre påloggingene våre mer spenstige. Vi kan allerede gjøre nettstedet vårt mye mindre sårbart for phishing ved ganske enkelt å begrense antall ganger vi vil tillate en pålogging tilNettsted, dette er ganske enkelt. La oss også begynne å lagre litt informasjon om hver bruker før når vi fortsetter å utvikle appen vår. Redigering av brukere/modeller.Py, legg til følgende

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='')
Merk at denne modellen er ganske lik innleggsmodellen. Vi har en ekstra import, tidssone, som lar oss angi standardverdier på datetime -feltene, og vi har også en karakterfeild og tekstfelt som innlegget. Ved å bruke alle disse tidsstempelene hjelper oss med å sikre nettstedet og forstå bruken av det, og tekstfeltene lar oss gi informasjon om hver bruker eller forfatter på nettstedet. OneToonefield skal være den eneste mindre hensynet, den oppfører seg nøyaktig den samme som en foreginke, men med bare en per påfølgende modell. På denne måten har brukeren bare en profil, mens de kan ha mange innlegg. La oss nå forbedre innloggingen og registrere visninger for å redegjøre for profilen. Først rediger brukere/visninger. Py og fokuser på registervisningen:

# ... beløp
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) # Sørg for å legge til denne linjen, for å opprette en profil for brukeren
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
Dette oppretter ganske enkelt en profil for brukeren, uten å fylle ut noe av informasjonen. Nå vil vi sørge for at brukerkontoen ikke kan logges inn for ofte, eller at passord i det minste ikke kan prøves for ofte, så la oss oppdatere påloggingsvisningen.

# ... beløp
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(): # Merk at vi nå sjekker om brukeren kan logge inn
            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: # Hvis påloggingen ikke var vellykket,
            messages.warning(request, 'Username or password incorrect. Please try again.')
            user = User.objects.filter(username=username).first() # Dette er den delen der vi oppdaterer brukerprofilen
            if user: 
                profile = user.profile
                profile.can_login = timezone.now() + datetime.timedelta(seconds=15) # Så de kan ikke logge inn igjen i noen sekunder
                profile.save()
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
Dette er det grunnleggende grunnleggende av sikkerhet. Forsikre deg om at nettstedet ikke er sårbart for noen som bare prøver alle mulige passordkombinasjon, eller til og med noen få av dem samtidig. Dette vil ikke være frustrerende for den vanlige brukeren som kjenner passordet og bare logger seg på noen få enheter, men det vil holde mange phishing -roboter utenfor appen. Merk at vi la til en IF -uttalelse med en variabel, can_login, det skal være en tid i fortiden, og oppdatere den med hver mislykket pålogging ved å bruke det samme brukernavnet. På denne måten vil en ondsinnet bruker ikke kunne gjette et passord hvor som helst like raskt. Antall sekunder i datetime.timedelta () kan også oppdateres, og nettstedet vil være mer spenstig, men likevel litt mindre brukbart med flere sekunder. Jeg anbefaler 15 til å begynne med. Husk at vi bygde et sikkerhetskopieringsskript for å redde arbeidet vårt, så la oss gå foran det vi har så langt for å sikre at vi har alt lagret. Kjør kommandoen:

sudo backup
Nok en gang vil dette spare arbeidet ditt så langt. Jeg anbefaler å kjøre hyppige sikkerhetskopier for å lagre arbeidet ditt, og du vil kanskje til og med kjøre en backupjobb automatisk. Du kan gjøre dette ved hjelp av et UNIX -verktøy som heter Cron. For å aktivere dette verktøyet, kjør følgende kommando og skriv inn passordet ditt:

sudo crontab -e
Hvis du ikke allerede har valgt alternativ 1 for Nano, bør tekstredigereren du allerede skal være kjent med, og bla til bunnen av filen ved hjelp av piltastene. Legg til følgende linje:

0 * * * * sudo backup
Cron bruker formatet Minute, Hour, Day of Month, Month, Day of Week, hvor et * eller et tall representerer når du skal kjøre kommandoen. Ved å bruke en 0 for minuttet og * for resten av alternativene, kan vi kjøre en kommando det første minuttet av hver time i starten av minuttet. Dette lar oss sikkerhetskopiere koden automatisk. Alle CRONs jobber når de utføres med sudo -løp som rot, så vi trenger ikke å skrive inn et passord hver time. For å gjøre det lettere å sikkerhetskopiere koden vår uten å bruke et passord, la oss deaktivere passordet for sikkerhetskopieringskommandoen vår. Vi vil gjøre dette ved å utføre følgende kommando og legge inn et passord:

sudo visudo
La oss nå bla til bunnen av filen og legge til en annen linje:

ALL ALL=NOPASSWD: /bin/backup
Dette lar oss kjøre kommandoen "sikkerhetskopi" som enhver bruker, uten passord. Formatet for dette er enkelt, bare prefiks linjen med "All alle = nopasswd:/bin/" og avslutt med kommandoen, for eksempel/bin/backup, som finnes i/usr/bin/. La oss nå begynne å jobbe med e -post. E -post er veldig viktig for nettsteder, fordi det er en måte å holde et nettsted sikrere, bekrefte at brukere er virkelige mennesker, og til og med markedsprodukter eller tjenester til kundene. Mange mennesker som hyppig sjekker e -posten deres daglig, og mottar alle slags markedsføringsmail om produkter og tjenester de er interessert i. Det er noen få alternativer når det gjelder å aktivere e -post på et Django -nettsted, og du er velkommen til å velge Uansett hva som fungerer best for deg. Først kan du betale for en e -posttjeneste som lar deg sende e -post fra domenet ditt og krever minimal kode. Det er mange tjenester som tilbyr dette, for eksempel Google Workspace, SendinBlue, Mailgun og mer. Ellers har du det bra med å byggeDin egen e -posttjeneste på serveren din fra bunnen av. Jeg anbefaler dette alternativet, selv om det er mer kode og kan kreve spesiell hosting. Du vil ikke kunne starte en e -postserver fra hjemme -datamaskinen din mest sannsynlig, så la oss gå foran og undersøke konfigurasjonen og koden for å sende e -post før vi starter en server i skyen og oppretter vår egen e -postserver innen. Først, rediger innstillinger.py med følgende

nano app/settings.py
Hvor appen er navnet på appen du opprettet med StartApp. Legg til følgende linjer:

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)
Sørg for å endre disse når du er klar til å distribuere appen din, vi vil se på dette senere. Innstillingen e -post_adress skal være e -posten du vil sende fra, og passordet (e -post_host_password) skal settes til passordet du genererer for serveren. Jeg laster inn passordet fra en konfigurasjonsfil for å holde den utenfor koden ved å bruke følgende logikk, over disse linjene i innstillinger.

import os
import json
with open('/etc/config.json') as config_file:
    config = json.load(config_file)
Deretter har jeg satt opp en JSON -fil med konfigurasjonen i /etc/config.json ved å bruke Nano som følger. For å redigere filen:

sudo nano /etc/config.json
Legg til følgende linjer:

{
	“EMAIL_HOST_PASSWORD”: “<some password here>”
}
Vi vil fortsette å redigere konfigurasjonsfilen og legge til alle passord og nøkler vi bruker i appen. Foreløpig, la oss raskt undersøke hvordan du sender e -post ved hjelp av Python. La oss først opprette en mal for en verifisering -e -post vi kan sende til brukerne våre, og legge den inn i brukermalkatalogen. Denne malen vil bli skrevet 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>
 
Denne e -posten er ganske enkel. Det tar en kontekst av en bruker, basis -URL for nettstedet, og en bruker -ID og token som brukes til å bekrefte brukerens e -post. Sørg for å definere basis -URL -en i innstillinger. Gå videre og legg til følgende linjer i app/innstillinger.py, nær begynnelsen.

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

BASE_URL = PROTOCOL + '://' + DOMAIN
Etter hvert, når nettstedet ditt er klart for internett og du distribuerer det, vil du definere domenet ditt som domenenavnet du kjøper for å representere nettstedet. Dette er navnet du vil skrive inn navbaren for å få tilgang til nettstedet ditt. Foreløpig kan du la domenet være tomt eller bruke en plassholder. Du vil også ønske å endre nettstedets navn til et navn du vil gi nettstedet ditt, du velger. Før vi sender e -post, la oss opprette en token -generator slik at vi kan ha en kontoaktiveringstoken som aldri utløper. Vi kan gjøre dette ved å bygge og importere en kontoaktiveringstoken som ser ut som følgende. Rediger filen:

nano users/tokens.py
Legg til følgende kode:

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()
Denne grunnleggende tokengeneratoren genererer et token vi kan sende brukeren i en URL og brukeren kan bruke til å bekrefte e -posten deres og aktivere kontoen sin. La oss deretter se hvordan du sender en e -post. Bruke Nano, rediger brukere/e -post.py.

nano users/email.py
Å sende verifiseringen HTML -e -post vil se slik ut:

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)
Dette er ganske enkelt. Vi importerer funksjonene vi trenger for å sende e -posten, gjengi e -posten med maler og innstillingene våre, og deretter definerer vi e -posten med malnavnet og sender den til brukeren ved hjelp av en funksjon. Du vil merke at vi ikke har definert funksjonen for å sende posten, send_html_email, men la oss skrive dette under koden vi allerede har lagt til brukere/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()
Dette er litt mer sammensatt, og vi er ikke klare til å kjøre all denne koden ennå. Legg merke til at vi definerer en unsub_link, lenken brukeren kan bruke til å melde seg ut fra e -postene våre. Dette er viktig, fordi brukere må være i stand til å velge bort e -postene våre med mindre de når som helst vil se dem. Vi legger også til et tekstalternativ til meldingen vår, som er HTML -meldingen som er strippet for HTML -tagger. Til slutt sjekker vi om e -posten som ble sendt, og hvis den ikke gjorde det, markerer vi i brukerens profil at e -posten deres ikke er gyldig. La oss flytte tilbake til brukermodellene slik at vi kan få dette til å fungere. Vi må definere en funksjon for å generere en lenke til å avslutte abonnementet, og definere et boolsk felt for å merke at brukerens e -post ikke er gyldig. Først må du legge til følgende import til toppen av brukere/modeller.

nano users/models.py

# ...
from django.core.signing import TimestampSigner, BadSignature, SignatureExpired
from django.urls import reverse
La oss deretter legge til funksjoner i brukermodellen for å lage tokenet og sjekke tokenet som brukes til å aktivere e -posten, så vel som feltet for å spare om brukeren lykkes med å motta e -posten. I brukere/modeller.

# ...
    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) # Gyldig i 30 dager
        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,})
Dette er ganske enkelt, vi bruker en tidsstempler, som er et grunnleggende kryptografiverktøy, for å lage et symbol som vil utløpe etter en viss tid, og vi bruker også en annen funksjon for å sjekke om det er gyldig. Vi bruker disse symbolene to ganger, en gang for å bekrefte e -posten, og en gang for en avmeldingslenke. Nå som vi har disse, er det siste av arbeidet vi trenger å gjøre i synspunktene. Innenfor brukere/visninger.Py, la oss legge til visninger for å bekrefte e -postadressen, og for å melde deg av.

nano users/views.py
Først må du legge til følgende import. Jeg kastet inn noen ekstra ekstra, så vi slipper å importere flere varer igjen senere.

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 # Sørg for å importere verifiserings -e -postsendingsfunksjonen
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 har kanskje allerede noen av disse importen, men det skader ikke å gjenta dem. Du trenger å importere verifiserings -e -postsendingsfunksjonen, samt konto_aktivering_token fra brukere.tokens, blant annet import. Nå, nederst i filen, legger du til følgende kode:

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)):
        # Avslutt dem
        profile = user.profile
        profile.subscribed = False
        profile.save()
        return render(request, 'users/unsubscribe.html')
    # Ellers omdirigerer til påloggingsside
    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 (forespørsel, bruker)
        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})
Dette er mye kode. La oss bryte det ned. Den første funksjonen, rene og enkel, avslutter brukeren fra adresselisten. Den andre funksjonen aktiverer e -posten deres, og du vil merke at jeg la til en kommentert funksjon, SendWelcomeEmail. Du er velkommen til å bruke en definisjon av e -postmal og funksjon for å sende en velkomst -e -post, det har jeg ennå ikke ennå. Den siste funksjonen jeg kastet inn er viktig, fordi aktivering av e -post går ut. Derfor må vi sende aktivering av aktivering på e -post til noe av tiden. Vi kan bruke en grunnleggende form for dette, og ringe funksjonen for å sende bekreftelses -e -posten. Før vi gjør dette, la oss sørge for at det blir sendt i utgangspunktet, ved å legge til en funksjonsanrop til registervisningen. Legg til denne linjen rett før omdirigering i registervisningen, DEF -registeret, i brukere/visninger.

nano users/views.py

# ... (etter) def register (forespørsel):
            send_verification_email(user)
# ... (før) omdirigere (
Du trenger ikke å legge til de første og siste linjene i kodebiten, bare sørg for at registervisningen sender bekreftelses -e -posten til brukeren. Det skal se slik ut:

# ... beløp
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) # Sørg for å legge til denne linjen!
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
Nå må vi legge til et skjema for å sende aktiverings -e -posten på nytt. I brukere/skjemaer.Py, legg til følgende skjema:

# ... (beløp)
class ResendActivationEmailForm(forms.Form):
    email = forms.EmailField(required=True)
Vi vil også trenge en mal som tilsvarer dette skjemaet for aktivering av e -post. La oss legge til denne malen i. Rediger filen:

nano users/templates/users/resend_activation.html
Deretter legger du til følgende kode 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 er mye! Når vi distribuerer koden til serveren vår, vil vi kunne sende HTML -e -post og aktivere brukerkontoer med et klikk i e -posten. Vi vil kanskje også sende en enkel velkomst -e -post, så la oss se hvordan vi gjør det. Tilbake i brukere/e -post.py, legg til følgende kode:

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 trenger også en mal for å gjengi all denne informasjonen. På nettstedet mitt ser malen ut som nedenfor, men du er velkommen til å formatere den slik du vil.
 
<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>
 
Merk at vi ikke har lukkende kropps- eller HTML -tagger, fordi vi legger disse til når vi legger til HTML -avmeldingslenken. Disse er viktige, men vi vil ikke definere dem to ganger. Så hva er det neste? Vi har kommet langt. Virkelig, vi bør være klare til å distribuere nettstedet til en server. Vi kan legge til @login_required Decorator og gjøre visningene våre sikre, ta brukeroppmeldinger, sende kompatibel e -post og cacheinformasjon, som er grunnlaget for hva et nettsted må gjøre for å holde deg relevant. Vi vil legge til noen flere nyttige funksjoner, og deretter bygge et grunnlag for å distribuere koden vår til en ekstern server, sette opp en postserver, domenekonfigurasjon og filtre for å gjøre nettstedet vårt sikkert og passende. Vi trenger også en tilbakestilling av passord, så la oss legge til det veldig raskt. Djangos innebygde tilbakestillingsvisning av passord er ødelagt i noen funksjoner, men vi ser på hvordan vi skal skrive vår egen visning, e -postmal, skjemaer og URL -mønstre. Her er hvordan visningen ser ut, i brukere/visninger.py

# ... beløp
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)
Dette skjemaet er innebygd i Django, men vi trenger en mal for å bekrefte tilbakestillingen av passordet, brukere/maler/brukere/passord_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 også en mal for å sende en tilbakestilling av passord, med et enkelt skjema, hos brukere/maler/brukere/passord_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 %}
 
Malen for selve e -posten er enkel, det er en grunnleggende HTML -fil som gjengir en lenke for å tilbakestille passordet, hos brukere/maler/brukere/passord_reset_email.html. Django vil automatisk tolke denne 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 trenger også to maler til. Den første er å bekrefte at e -posten er sendt. Visninger for disse er allerede i Django, så vi trenger bare å adressere dem i nettadressene.py. Denne malen er lokalisert hos brukere/maler/brukere/passord_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 %}
 
Og til slutt, for å bekrefte at tilbakestillingen av passordet er fullført, bruker bruker/maler/brukere/passord_reset_complete.html
 
{% extends 'base.html' %}
{% block content %}
 <div class="media-body">
    <div class="alert alert-info">
        Your password has been set.
    </div>
    <a href="{% url 'users:login' %}">Sign In Here</a>
  </div>
{% endblock content %}
 
Nå trenger vi URL -mønstre for disse visningene. I brukere/urls.py, legg til følgende URL -mønstre:

urlpatterns = [
    # ... Tidligere nettadresser her
    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'),
]
Fire maler, det er mye! Men nå kan vi være sikre på å kunne tilbakestille brukerens passord når som helst vi trenger, alt fra nettleseren. Jeg forstår at dette er mye kode. Hvis det virker litt over hodet, er det OK. Du vil forbedre deg, forståelsen din vil bli bedre, og du vil bli mye mer kompetent med kode ganske snart. Hvis du er helt tapt, anbefaler jeg at jeg kommer tilbake til denne programvaren senere etter å ha jobbet med et selvtydelig å lære å kode kurs på nettet. Disse er vanligvis gratis å komme i gang, og vil guide deg gjennom alt du trenger for å lykkes når du kommer tilbake til dette prosjektet. Hvis du føler at du er klar til å fortsette, lese videre, neste, vil vi dekke distribusjonen til en ekstern server og sette opp en e -postserver, samt automatisere distribusjonen din ved hjelp av bash, slik at du alltid kan sette opp et nytt prosjekt med noen få enkle kommandoer. Det siste vi trenger å gjøre før vi distribuerer til en ekstern server er å gjøre nettstedet vårt litt sikrere. Du vilLegg merke til at påloggingsvisningen bare tar et brukernavn og passord, og det er ingen multifaktorautentisering eller en tidskode. Dette er en enkel løsning, og med samme kode kan vi få nettstedet vårt til å sende tekstmeldinger og til og med være lydhør over tekstmeldinger sendt til serveren. For å starte, vil vi gå tilbake i brukermodellene og legge til en tidsstempel som vil representere hver pålogging. Vi vil også legge til en unik, roterende identifikator til brukermodellen som vil bli brukt til å legge til ekstra sikkerhet til innloggingen vår. Redigering av brukermodellene, brukere/modeller.Py, legg til følgende

from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
# Sørg for å importere UUID, Timestamp Signer og URL Generator (omvendt)
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='')
    # Legg til denne koden her
    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)

    # Og legg til denne funksjonen
    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) # Gyldig i 3 minutter
        except (BadSignature, SignatureExpired):
            return False
        return True
Forsikre deg om at brukerne/modellene dine ser slik ut, i tillegg til kommentarene (kode på linjene med #). Å bryte dette ned, det er enkelt. Vi har noen få importer, en tidsstempelssigner som er et kryptografisk verktøy som kan generere en sikker kode og bekrefte den for å sikre at den er gyldig, bare blitt brukt en gang, og ikke eldre enn et visst antall sekunder. Vi bruker også en UUID, som er en unik identifikator som identifiserer vår bruker i signeringen av tokenet, og i URL -en der tokenet sendes til brukeren. Vi bruker denne grunnleggende kryptografien til å bygge en tofaktor autentiseringsvisning. Før vi gjør noe annet, la oss kjøre migrasjonene slik at brukermodellene våre blir oppdatert. I katalogen med administrasjon.py, kjør følgende kommandoer for å gjøre og fullføre migrasjonene.

source venv/bin/activate
python manage.py makemigrations && python manage.py migrate
Dette er viktig fordi hver gang vi gjør endringer i modellene, må vi lage tabellene og oppdatere databasen med standardverdier før vi faktisk kan bruke modellene. La oss deretter improvisere innloggingsvisningen vår for å omdirigere til et sekundært autentiseringsvisning. Hos brukere/visninger.

# ... beløp

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(): # Merk at vi nå sjekker om brukeren kan logge inn
            # Fjern auth_loginfunksjonen som var her
            messages.success(request, 'Your password was accepted. Please continue.')
            if user.profile.mfa_enabled:
                return redirect(user.profile.create_auth_url()) # Merk at vi omdirigerer til en ny url her
            else: # Hvis brukeren ikke bruker multifaktorautentisering, er det bare å logge dem inn.
                auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
                return redirect('feed:feed')
        else: # Hvis påloggingen ikke var vellykket,
            messages.warning(request, 'Username or password incorrect. Please try again.')
            user = User.objects.filter(username=username).first() # Dette er den delen der vi oppdaterer brukerprofilen
            if user: 
                profile = user.profile
                profile.can_login = timezone.now() + datetime.timedelta(seconds=15) # Så de kan ikke logge inn igjen i noen sekunder
                profile.save()
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
Så dette er ganske enkelt, vi har nå en måte å omdirigere til de to faktorautentiseringsvisningen når vi oppretter det. Vi har også en tilbakeslag i tilfelle brukeren ikke har lagt til et telefonnummer. Vi vil legge til en grunnleggende visning for å legge til et telefonnummer snart og logge inn med en tekstmelding snart. Først trenger vi en enkel måte å sende en tekstmelding fra koden vår. For å gjøre dette kan vi velge mellom en rekke API -er, men den enkleste etter min mening er Twilio. De tilbyr også gode priser for mindre prosjekter, samt bulkrabatter. Opprett en konto på Twilio.com, fyll ut noen detaljer om prosjektet ditt, kjøp et telefonnummer og kopier API -nøklene til innstillingene dine. Deretter legger du til denne koden under en ny fil, brukere/sms.py.

nano users/sms.py

# Importer alle nødvendige pakker
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

# Denne koden sender teksten 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 hjelperfunksjon for å få et tall med så mange sifre
def get_num_length(num, length):
    n = ''
    for x in range(length):
        n = n + str(num)
    return int(n)

# Send teksten for å bekrefte brukeren
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)))

# Send en bruker hvilken som helst tekst med denne funksjonen
def send_user_text(user, text):
    send_text(user.profile.phone_number, text)

# Valider koden med denne funksjonen
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

# Valider tiden
def check_verification_time(user):
    result = user.profile.mfa_code_expires > timezone.now()
    return result
Sørg for å endre innstillingene på riktig måte, legg til disse linjene med nøklene dine:

# Sørg for å kopiere disse fra Twilio -dashbordet ditt
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 # Antall minutter TFA -siden er aktiv når du er instantiert
Først vil vi trenge skjemaer for våre to faktorautentiseringsvisninger. Redigerer brukere/skjemaer. Py, legg til følgende kode.

# ... beløp
from django import forms

# Et skjema for å legge inn telefonnummeret vårt
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

# Et skjema for autentisering
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.'
    }
Neste, la oss lage visningene i brukere/visninger.py

# ... beløp
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 trenger også maler for begge disse visningene. La oss legge til MFA -malen først.

nano users/templates/users/mfa.html
Legg til denne HTML -koden i malen
 
{% 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 %}
 
Dette er ganske selvforklarende. Skjemaet sender enten en kode eller en tom kode, og du vil legge merke til i visningen vi sender koden hvis vi mottar en tom kode. Da har vi bare to innsendingsknapper, og på denne måten kan vi sende koden med begge knappene. Deretter legger vi til et enkelt skjema for å legge til et telefonnummer.

nano users/templates/users/mfa_onboarding.html
Legg til følgende 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 %}
 
Dette skjemaet er mye enklere, det gjengir bare telefonnummerskjemaet vi opprettet og lar brukeren legge til et telefonnummer. Dette ser veldig bra ut! Så lenge alt er riktig satt opp, skal vi kunne sende meldinger og logge brukeren inn med telefonnummeret sitt så snart vi legger til URL -mønstrene. Det siste vi trenger å sette opp er en profilvisning, slik at vi kan sørge for at brukeren kan endre telefonnummeret uten å bli logget inn. Også, til slutt vil vi legge til et "stopp for å avslutte" -alternativet, så brukeren kan tekst “Stopp” for å velge bort fremtidige tekstmeldinger. La oss legge til en profilvisning til brukerne/visningene. Denne visningen vil oppdatere brukerens biograf, e -post, brukernavn og telefonnummer, samt tillate oss å aktivere autentisering av flere faktor. Først trenger vi to skjemaer til i brukere/skjemaer.

# ... beløp
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']
Deretter kan vi lage et syn på å bruke begge disse skjemaene. Rediger brukere/visninger.py og legg til visningen.

# Legg til denne importen
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 trenger også en mal for denne visningen.

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 vil merke at dette er en ganske enkel form, men har noe JavaScript i seg som automatisk legger inn innholdet i skjemaet når de er oppdatert. Dette er nyttig å ha, slik at du kan gjøre redigeringer uten å måtte trykke på innsending hver gang. Deretter trenger vi nettadresser som representerer alle disse visningene i brukerens URL -klaffer. Rediger brukere/urls.py og legg til denne koden:

# ... tidligere kode, import
from django.urls import path
from . import views

app_name='users'

urlpatterns = [
# ... URL -mønstre vi tidligere har skrevet inn, legger til de tre neste linjene
    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'),
]
Nå er det et godt tidspunkt å teste ut prosjektet vårt. Men først, la oss kjøre en ny sikkerhetskopi.

backup
Og kjør serveren. Før vi distribuerer til en Linux -server, er det en god idé å aktivere to faktorautentisering på kontoen. Vi vil gjøre dette til å gå til profil -URL -en,/brukere/profil/, og merke av i boksen for å aktivere autentisering etter å ha lagt inn telefonnummeret vårt, og deretter sende inn skjemaet.

python manage.py runserver localhost:8000
Besøk nettsiden ved å gå til nettleseren din, jeg bruker Google Chrome i dette eksemplet, og skriv inn URL -URL -er: // LocalHost: 8000/Accounts/Profile/ Du vil kunne logge inn om nødvendig og aktivere to faktorautentisering. Dette prosjektet trenger en server for å kjøre på, slik at det virkelig kan sende post. Men først trenger vi en måte å se feil på. Du vil merke at hvis du kjører serveren i feilsøkingsmodus, med innstillinger. DEBUG lik True, viser serveren feil automatisk. For å vise feil uten å bruke feilsøkingsmodus, som er utrygg på en produksjonsserver, bør vi legge til en visning for det. De viktigste feilene vi trenger å kunne håndtere er: Feil 500 - Et problem med koden vår Feil 404 - En side som ikke ble funnet (ødelagt url) Feil 403 - En tillatelse nektet feil La oss legge til en ny app for å håndtere disse feilene, kalt feil.

python manage.py startapp errors
Legg dette til innstillingene.

handler404 = 'errors.views.handler404'
handler500 = 'errors.views.handler500'
handler403 = 'errors.views.handler403'
Dette er alt vi trenger foruten feilvisninger, maler og litt mellomvare. La oss definere dem som det:

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

# Lag dine synspunkter her.
@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.'})
La oss deretter definere mellomvaren for å håndtere disse feilene. Vi vil gjøre dette ved først å legge til mellomvare_klasser i innstillinger.py, med navnet på mellomvaren vår.

MIDDLEWARE_CLASSES = [
    # ... Tidligere mellomvare
    'errors.middleware.ExceptionVerboseMiddleware,
]
Neste, la oss legge til mellomvare.

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 legger til en funksjon for å få det nåværende unntaket ved å bruke en trådlokal, som hjelper oss å spore eventuelle feil i koden vår. Når det gjelder maler, trenger vi bare en, fordi vi dynamisk definerer tittelen i visningen. Malen trenger bare å gjengi tittelen og "spore", vår feilsporing fra konteksten.

nano errors/templates/errors/error.html
 
{% extends 'base.html' %}
{% block content %}
<h1>{{ pagetitle }}</h1>
<p>{{ trace }}</p>
{% endblock %}
 
Dette er vår enkleste mal ennå, men det er hvor lett det er å se feilene i prosjektet vårt. La oss deretter deaktivere feilsøking i innstillinger.

nano app/settings.py
Finn denne linjen der den er satt til sann, og endre den til falsk

DEBUG = False
Gå videre og ta sikkerhetskopi av appen nå. Vi er klare til å distribuere til en ekstern Linux -server, og fortsetter å legge til funksjoner derfra.

sudo backup
Før vi legger ut denne koden på en server, bør vi vurdere at det kan være noen problemer med koden. Avhengig av saken, vil nettsteder som godtar informasjon som er lagt ut til dem, ha problemer med at spam blir lagt ut og vanskeligheter med å fjerne spam. Dette skal ikke skje umiddelbart, men hvis det skjer, vil vi senere undersøke hvordan du automatisk skal moderere spam på nettstedet og gjøre det tøffere for roboter å få tilgang til nettstedet, sammen med hvordan du deaktiverer brukerkontoer, og verifiserer en brukers identitet med En skanning av deres ID eller en biometrisk skanning, som et fingeravtrykk eller ansiktsgjenkjenning. Når du ser på multifaktor -autentiseringseksemplet vi undersøkte, i produksjon, kan ting være annerledes. Legg merke til hvordan vi er prisbegrensende pålogginger og utløpende symboler. Hvis roboter får tilgang til et nettsted, kan to faktorautentisering være vanskeligere, da de kan legge inn koder samtidig som brukeren er. For å bekjempe dette, la oss bruke en modell i brukermodellene, og erklærer hvordan vi samhandler med nettstedet når vi erAutentisering ved hjelp av autentisering av flere faktor med et telefonnummer. Vi vil også legge til et alternativ for å autentisere med e -post. Start med å redigere brukermodellene med

nano users/models.py
Dette er slik modellen vi legger til, skal se ut. Vi trenger ingen metoder, bare variabler for å lagre en ID, brukeren, tidsstempel, utløp, lengde og forsøk mot en hvilken som helst autentisering av flere faktor (en kode som 123456 sendt til en telefon eller e -post).

# Et grunnleggende token pleide å logge inn på nettstedet
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)
La oss også legge til et privilegium til vår bruker, og vi vil stille det manuelt for nå, før vi til slutt migrerer til å verve privilegerte brukere automatisk. I brukermodellene, legg til denne linjen i profilen:

    vendor = models.BooleanField(default=False)
Som med alle endringer i databasen, må vi gjøre migrasjoner og migrere databasen når vi redigerer en modeller.py -fil i Django. Husk at for å gjøre dette bruker vi kilden først (hvis den ikke har blitt brukt allerede siden terminalen var åpen) og deretter python administrere.py for å gjøre migrasjonene og migrere.

cd project-directory-you-named # (om nødvendig)
source venv/bin/activate
python manage.py makemigrations && python manage.py migrate
Foreløpig kan du verve alle kontoer du har opprettet som leverandører ved å bruke skallet.

python manage.py shell
from users.models import Profile
p = Profile.objects.get(user__username='Charlotte')
p.vendor = True
p.save()
exit()
La oss nå utvikle vår autentiseringsvisning for flere faktor for å bruke dette tokenet. Først må vi endre MFA -hjelperverktøyene våre. Bruker 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

# Autentiser brukeren ved å bruke 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() # Filtrer tokenet med verdien som er gitt i nettadressen (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)) # Hvis denne økten ikke er opprettet, oppretter du den
    user = User.objects.filter(id=token.user.id).first() # Få brukeren fra tokenet
    if not user and request.user.is_authenticated: return redirect(reverse('feed:home')) # Hvis de allerede er autentisert, logg dem inn
    if not user: raise PermissionDenied() # Nekte hvis ingen bruker ble funnet
    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): # Sjekk authentetokenet
        auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Logg inn brukeren hvis de ikke allerede er logget inn
        user.profile.mfa_expires = timezone.now() + datetime.timedelta(minutes=settings.LOGIN_VALID_MINUTES) # Angi en utløp på autentisering av flere faktor
        user.profile.save()
        return HttpResponseRedirect(next if next != '' else reverse('landing:landing')) # Omdirigere brukeren til neste side
    if not user.profile.mfa_enabled: # Sjekk om MFA er aktivert
        if not check_verification_time(user, token): # Sjekk tiden
            user.profile.mfa_enabled = False # Fjern telefonnummeret
            user.profile.enable_two_factor_authentication = True # Aktiver MFA
            user.profile.phone_number = '+1' # Deaktiver telefonnummeret
            user.profile.save() # Lagre profilen
            auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Logg brukeren inn hvis deres MFA ikke er aktivert
            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): # Hvis forespørselen er en etterforespørsel
        form = TfaForm(request.POST) # Øyeblikkelig skjemaet
        code = str(form.data.get('code', None)) # Få koden
        if code and code != '' and code != None: # Forsikre deg om at det ikke er tomt
            token_validated = user.profile.check_auth_token(usertoken) # Sjekk authentetokenet
            p = user.profile
            is_verified = check_verification_code(user, token, code) # Sjekk koden
            p.mfa_authenticated = is_verified
            if token_validated: # Hvis alt
                if is_verified: # Er i orden
                    user.profile.mfa_enabled = True # Aktiver MFA (hvis ikke allerede aktivert)
                    user.profile.save()
                    auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Logg inn brukeren
                    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 spørring for neste parameter (hvis noen)
                        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) # Omdirigere
                    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: # Hvis tokenet var ugyldig
                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: # Hvis det var for mange forsø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): # Send e -posten (eller tekst)
                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('/'))
    # Gjengi skjemaet (for få forespørsler)
    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 legger til denne koden, må du sørge for å importere funksjonen for å sende en e -post. Øverst i filen vises brukeren (med annen import), legg til

from .mfa import send_verification_email as send_mfa_verification_email
Nå må vi skrive den funksjonen før noe av dette vil fungere. Den skal utvide vår Send -e -postfunksjon, og bare sende en e -post til brukeren med bekreftelseskoden.

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å alt dette fungerer bra, nå har vi et autentiseringssystem for flere faktor som avhenger av et telefonnummer eller e -post for å logge inn. Men vi trenger også en måte å fjerne, eller i det minste skjule brukere som ikke samarbeider med vilkårene våre. Dette kan være spammere, roboter eller alle som ikke betyr godt for vårt arbeid. Ta en titt på en visning jeg har for å overvåke brukere på nettstedet mitt:

# Import
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å lage denne testen

@login_required
@user_passes_test(is_superuser_or_vendor)
def users(request):
    # Få liste over brukere
    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', { # Returner brukere i en mal
        'title': 'All Accounts',
        'users': User.objects.all(),
        'new_today': new_today,
        'new_this_month': new_this_month,
        'subscribers': subscribers
    })
Merk at denne koden bruker en test, vi må erklære denne testen i en tester.py -fil og importere den. Redigering av brukere/tester. Py, la oss opprette testen.

def is_superuser_or_vendor(user):
    return user.profile.vendor or user.is_superuser
Dette er i forbindelse med brukerne/brukerne.html -malen, som ser ut som dette:
 
{% 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 %}
 
Merk at malen inkluderer en annen mal, brukere/_user.html. Når du bruker en mal som har en subtemplate og ikke bruker utvides, er det en god idé å legge til en understrek (_) før navnet på filen som skal utvides, for å skille maler. Merk at dette er mye jinja, det er ikke sikkert at du har alle disse variablene definert. Men slik ser koden min 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 trenger også en annen subtemplate, Toggle_active.html. Denne malen skal være et skjema som lar oss veksle om en bruker er 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 må også legge til en visning til å veksle brukeraktivitet og passende URL -mønstre. Mens vi er inne på det, la oss legge til en visning for å slette en bruker i tilfelle vi trenger 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>')


# Beløp
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.views.generic import DeleteView

class UserDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    model = User
    success_url = '/' # Omdirigering av suksess -url
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        return context

    def test_func(self): # Test om brukeren er superbruker og har tillatelse til å slette
        user = self.get_object()
        if self.request.user != user and self.request.user.is_superuser:
            return True
        return False
Selv om dette er praktisk når det er nødvendig, bør du slette en bruker ikke være nødvendig mesteparten av tiden, kan vi bare bytte synligheten til brukere som besøker nettstedet hvis vi trenger å avvise dem. URL -mønstrene vi la til ser slik ut. Med Nano, rediger brukere/urls.py og legg til disse linjene:

nano users/urls.py
Linjene skal gå i listen over stier i brukervisningene, før avslutningen “]”, men etter begynnelsen “[”.

# ...
    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'),
# ...
Sørg for å sikkerhetskopiere nettstedet slik at du kan laste ned det på webserveren vi fortsetter å jobbe med. Fra kommandolinjen,

sudo backup
Nå er nettstedet vårt sikkerhetskopiert. Så nå har vi noen flere nyttige funksjoner. Men hva med det store bildet her? Denne koden er fremdeles ikke tilgjengelig fra Internett, vi har ingen e -postserver ennå, og vi må utvide appen vår til å omfatte omfattende verifiseringsprosess samt glatte oppsett for å hjelpe oss med å utforske nettstedet, sammen med sikre protokoller for autentisering av privilegerte brukere . Vi kommer til alt dette. Det viktigste for nå vil bare være å få denne koden på nettet, noe vi kan gjøre med bare noen få linjer med bash på en Ubuntu -server. Du må leie en server for dette, med mindre du har en server hjemme og et virksomhetsinternettabonnement som lar deg åpne porter. Jeg personlig kjører nettstedet mitt på en HP Z440 som er installert i leiligheten min, men det er vanligvis mye billigere for grunnleggende behov for å leie en virtuell privat server (VPS). Husk at koden vi kjører nå er relativt tynn, den må opprettholdes og forbedres før vi erKlar til å bruke det vi har for å bygge et produkt. Sørg for å være forsiktig med hva du gjør med Internett, sørg for at hvis du distribuerer dette nettstedet offentlig til nettet på en Linux -server, har du en plan for å blokkere uønskede interaksjoner med nettstedet ditt. Dette vil sannsynligvis ikke være et problem med det første, men vi vil se på en rekke løsninger for å bekjempe dette, inkludert maskinlæring, kunstig intelligens og datasyn. Når det blir et problem, kan du se nærmere i denne teksten for en løsning. Når det gjelder å leie en VPS, er det mange steder du kan gå. Google Cloud har VPS -servere, Ionos, Kamatera, Amazon AWS, og flere leverandører tilbyr skyserverløsninger som passer våre behov. Du må klikke gjennom skjemaene deres og velge en plan for å komme i gang. Du kan gå med en grunnleggende plan med hvilken som helst leverandør, men sørg for at leverandøren lar deg åpne Port Mail Server -porter for å sende e -post (dette skal være port 587 og port 25), noen leverandører blokkerer disse portene. Så langt har jeg hattEST Erfaring med Ionos og Kamatera, begge vil tillate meg å sende ubegrenset e -post, og prisene deres er ganske billig. Du vil koble deg til den nye serveren din over en protokoll som heter SSH eller Secure Shell, som lar deg eksternt grensesnitt med serveren akkurat som din personlige datamaskin, fra din personlige datamaskin. Når du setter opp serveren, vil vertsleverandøren sannsynligvis be deg om å legge til en SSH -nøkkel, ellers vil de gi deg et brukernavn og passord. SSH -tasten er hvordan du vil logge deg på serveren fra kommandolinjen for å redigere koden. Bruk de nedenfor SSH-Keygen-alternativene for å generere en SSH

ssh-keygen
Lagre filen og overskriv den hvis du trenger det, det er godt å rotere SSH -tastene hvis du ikke allerede har gjort det. Nå kan du bruke følgende kommando for å se SSH -tasten din. Du vil kopiere den til den eksterne serveren din, slik at du kan bruke den til å autentisere.

cat ~/.ssh/id_rsa.pub
Hvis du ikke kunne se en SSH-tast når du skriver den kommandoen (en lang streng med sifre og bokstaver som starter med "SSH-RSA AAA"), kan du prøve å generere en RSA-tast (de er sikrere, så jeg anbefaler å bruke dem .) Følgende kode vil generere en 4096 -bit RSA SSH -tast.

ssh-keygen -t rsa -b 4096
Lag en VPS som kjører Ubuntu, men du planlegger å gjøre dette. Når du har opprettet en VPS ved å klikke gjennom skjemaene på leverandørens nettsted (kamatera.com, ionos.com eller lignende), vil du logge inn. For å gjøre dette, bruk SSH -kommandoen med IP -adressen din (adressen Det ser ut som xx.xx.xx.xx). Du må også være følsom for standard brukernavn på serveren vi opprettet, for eksempel Ubuntu.

ssh ubuntu@XX.XX.XX.XX
Du kan bli bedt om et passord. La oss starte med å legge til en ny SSHD_CONFIG -fil, som forteller serveren hvordan du bruker SSH.

nano sshd_config

# Dette er SSHD-serverens systemomfattende konfigurasjonsfil.  Se
# sshd_config (5) for mer informasjon.

# Denne SSHD ble satt sammen med Path =/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

# Strategien som brukes til alternativer i standard SSHD_CONFIG sendt med
# OpenSSH skal spesifisere alternativer med standardverdien der
# mulig, men la dem kommentert.  Uformidlet alternativer overstyrer
# Standardverdi.

# Port 22
# Adressefamilie noen
# Listeadresse 0.0.0.0
# Lytt Adress ::

# HostKey/etc/ssh/ssh_host_rsa_key
# HostKey/etc/ssh/ssh_host_ecdsa_key
# HostKey/etc/ssh/ssh_host_ed25519_key

# Chiffer og tasting
# REKEYLIMIT standard ingen

# Logging
# SyslogFacility Auth
# LOGLEVEL INFO

# Autentisering:

# LogringRacetime 2M
# Tillatootlogin Forbudsmessig pass
# StrictModes Ja
# Maxauthtries 6
# Maxessions 10

PubkeyAuthentication yes

# Forvent .SSH/Authorised_Keys2 som blir sett bort fra som standard i fremtiden.
AuthorizedKeysFile	.ssh/authorized_keys .ssh/authorized_keys2

# Autorisert PrincipalsFile Ingen

# AutorisertKeyScommand ingen
# AutorizedKeyScommanduser ingen

# For at dette skal fungere, trenger du også vertsnøkler i/etc/ssh/ssh_neknede_hosts
# HostbasedAuthentication nr
# Endre til ja hvis du ikke stoler på ~/.ssh/kjente_hosts for
# HostbasedAuthentication
# IgnoreUsernknytterne nr
# Ikke les brukerens ~/.rhosts og ~/.hosts -filer
# Ignorerehosts ja

# For å deaktivere tunnelerte klare tekstpassord, endre til nei her!
PasswordAuthentication no
# TillatelsePassord nr

# Endre til Ja for å aktivere passord for utfordringer-svar (pass på problemer med
# noen PAM -moduler og tråder)
KbdInteractiveAuthentication no

# Kerberos -alternativer
# Kerberosauthentication nr
# KerberosorlocalPasswd Ja
# Kerberosticketcleanup Ja
# Kerberoscotted Rod No

# GSSAPI -alternativer
# Gssapiauthentication nr
# GSSAPICLEANUPCredentials Ja
# Gssapistrictacceptorcheck ja
# GSSAPIKEYEXCHANGE NO

# Sett dette til 'ja' for å aktivere PAM -godkjenning, kontobehandling,
# og øktbehandling. Hvis dette er aktivert, vil PAM -godkjenning
# få lov til gjennom kbdinteractiveauthentication og
# Passordauthentication.  Avhengig av PAM -konfigurasjonen din,
# PAM -godkjenning via KBDInteractiveAuthentication kan bypass
# Innstillingen av "tillatelserootlogin utenpassord".
# Hvis du bare vil at PAM -kontoen og øktkontrollene skal kjøre uten
# PAM -godkjenning, så aktiver dette, men angi passordauthentication
# og kbdinteractiveauthentication til 'nei'.
UsePAM yes

# Tillat om fremover ja
# Tillater ja
# Gatewayports nr
X11Forwarding yes
# X11DisplayOffset 10
# X11uselocalhost ja
# Permittty ja
PrintMotd no
# Printlastlog ja
# Tcpkeepalive ja
# Permittuen miljø i
# Komprimering forsinket
# Klientaliv intervall 0
# Clientalivecountmax 3
# Brukt i
# Pidfile /run/sshd.pid
# MaxStartups 10: 30: 100
# Pemittunl nr
# Chrootdirectory Ingen
# Versjon tillegg ingen

# Ingen standard bannersti
Banner /etc/banner

# La kunden passere lokale variabler variabler
AcceptEnv LANG LC_*

# overstyre standard for ingen delsystemer
Subsystem	sftp	/usr/lib/openssh/sftp-server

# Eksempel på overordnede innstillinger per brukerbasis
# Match brukeranoncvs
# X11forwarding nei
# Tillater nei
# Godty In
# ForceCommand CVS Server
PermitRootLogin no
Husk at Ctrl+X og Y for å lagre filen. La oss deretter skrive et grunnleggende skript som heter Initialize (alt i standard Home Directory til vår bruker).

nano initialize
Legg disse linjene i filen, og erstattetMed din SSH -tast fant du ved hjelp av CAT. (.SSH/ID_RSA.PUB)

# !
sudo apt install -y nano git openssh-server
sudo cp sshd_config /etc/ssh/sshd_config
sudo service ssh restart
sudo service sshd restart
echo "/root/.ssh/id_rsa" | sudo su root -c "ssh-keygen -t rsa -N ''"
echo "root ssh key:"
sudo su root -c "cat /root/.ssh/id_rsa.pub"
sudo adduser --disabled-password --gecos "" team
sudo passwd -d team
sudo usermod -aG sudo team
echo "/home/team/.ssh/id_rsa" | su team -c "ssh-keygen -t rsa -N ''"
cat /home/team/.ssh/id_rsa.pub >> /home/team/.ssh/authorized_keys
echo '<key here>' >> /home/team/.ssh/authorized_keys
echo "team ssh key:"
cat /home/team/.ssh/id_rsa.pub
For å lede deg gjennom denne filen, la oss starte linje for linje. Den første linjen forteller kompilatoren at dette er et bashskript. Så installerer vi avhengigheter, kopierer SSHD_Config til riktig katalog, starter på SSH, genererer SSH -nøkler for Root, legger til brukeren 'Team' (du kan velge et navn du liker for dette, bruk adduser -kommandoen med navnet sitt og deaktivert passord for passord for passord for passord for passord for passord for nå). Vi legger også til team i sudo -gruppen, genererer SSH -nøkkelen, legger til nøkkelen til autoriserte nøkler og deres også, og skriver ut nøkkelen. Denne nye brukeren vil være hvordan vi logger på nettstedet. I en ny terminal, fortsett og åpne serveren igjen.

ssh team@XX.XX.XX.XX
Du bør ikke trenge et passord denne gangen, være som du har en SSH -nøkkel. Vi har også deaktivert pålogging med passord for å holde nettstedet sikrere. Nå starter denne serveren helt tom uten informasjon om den. La oss starte med å klone prosjektet vårt fra Git slik at vi kan laste ned og kjøre det på den eksterne maskinen. På den eksterne serveren som er koblet over SSH, skriv først ut SSH -tasten:

cat ~/.ssh/id_rsa.pub
Deretter lim inn denne tasten i Git -innstillingene som vi gjorde før for å sette opp Git -depotet vårt. Vi kan nå klone prosjektet vårt direkte til serveren. Forsikre deg om at du har sikkerhetskopiert prosjektet lokalt først, så det er på Git -serveren å laste ned.

git clone git://github.com/you/yourproject.git
Perfekt. Nå er alle filene her. Vi kan se dem med LS

ls
La oss nå begynne å sette opp serveren. Først kopierer du prosjektkatalogen din til et enkelt, minneverdig navn vi vil bruke til prosjektet.

cp -r yourproject whatyoucalledit
Hvor "WhatDyoucalledit" er det nye navnet på prosjektet ditt. Deretter må vi bygge et grunnleggende verktøy for å sette opp serveren. Vi vil lagre dette verktøyet og bruke det i fremtiden. For å bygge dette verktøyet, la oss opprette en brukerbinær for å definere hvordan vi redigerer et skript. Bruke bash, redigering/usr/bin/ascript

sudo nano /usr/bin/ascript
Sørg for å bruke sudo der, slik at du har tillatelser til å redigere filen. I filen, legg til disse linjene:

# !
if [ ! -f /usr/bin/$1 ]; then
    sudo touch /usr/bin/$1
    echo "# !
    sudo chmod a+x /usr/bin/$1
    sudo nano /usr/bin/$1
    echo $1 | sudo tee -a /etc/ascripts
else
    sudo chmod a+x /usr/bin/$1
    sudo nano /usr/bin/$1
fi
Husk at dette skriptet tar et argument, skriptnavnet, som $ 1. Først sjekker den om filen eksisterer, eller på annen måte oppretter den, legger til den første linjen som erklærer at skriptet er bash, endrer tillatelser, redigerer den og legger navnet til /etc /ascripts som lar oss lagre navnene på skriptene vi skaper. Hvis filen allerede eksisterer, kan du bare endre tillatelser og redigere den. Lagre filen, og neste vil vi endre tillatelser. Så lenge vi bruker dette skriptet, trenger vi ikke å gjøre det igjen.

sudo chmod a+x /usr/bin/ascript
Perfekt. La oss nå lage et skript som heter Setup. Først for ikke å overvelde deg, men se på hvordan oppsettskriptet mitt ser ut. Vi vil gå gjennom hvordan dette skriptet skal se ut i prosjektet ditt, du trenger ikke alt i manuset mitt til å begynne med.

# !
SECONDS=0
PYTHON_VERSION=3.12
echo "femmebabe installer initialized."
# sudo chmod a+x skript/brukere
# ./scripts/usersetup
# Ssh-keyen
# Prosjektkatalog
DIR="/home/team/femmebabe"
USER="team"
# Loggkommandoer
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
# Oppdater og installer
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
# Aktiver clamav antivirus
echo "Starting antivirus"
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Sett vertsnavn
echo "127.0.0.1 femmebabe" | sudo tee -a /etc/hosts
sudo hostnamectl set-hostname localhost
# Oppsett 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;"
# Sett opp sikkerhetskopi -database
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
# Deaktiverte 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
# Installer 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
# Oppsett 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
# Lage 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
# Sett opp VirtueAlenv
cd $DIR
echo "Creating virtual environment"
python -m venv venv
source venv/bin/activate
# Få og bygge avhengigheter
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
# Sett brannmurregler
cd $DIR
# Installer PYPI -avhengigheter
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
# Installer 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
# Kjør certbot
sudo certbot --apache --non-interactive --agree-tos --domains femmebabe.com --email jasper.camber.holton@gmail.com
# Last inn e -postserver på nytt
sudo systemctl restart opendkim postfix dovecot
# Kopier sertifikater
# sudo cp /etc/letsencrypt/live/femmebabe.com/privkey.pem privkey.pem
# sudo cp /etc/lettesencrypt/live/femmebabe.com/cert.pem cert.pem
# Lapp
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"
#  Set user settings
sudo gpasswd -a www-data users
# Angi tillatelser
echo "Setting permissions"
sudo chown -R team:users cache/
sudo chmod a+rwx -R cache/
# sudo chown -r team: brukere/var/løp/
# 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: brukere 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
# Kopier konfigurasjon og sett tillatelser
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
# Databaseoppsett
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"
# Injiser Pam Config og fjerne feil SSH -konfigurasjon
# sudo sed -i '' -e '$ d' /tc/pam.d/sshd
# Sudo sed -i '' -and $ 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
# Kopier søppelskript og angi tillatelser
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
# Last inn og aktiverer tjenester på nytt
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
# Aktiver 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
# Deaktiver standardside
sudo a2dissite 000-default
sudo a2dissite 000-default-le-ssl
# Aktiver for nettstedet
sudo a2ensite femmebabe-le-ssl
# Last ned Daemon og start Apache, Postfix og OpenDkim
sudo systemctl daemon-reload
sudo systemctl restart apache2
sudo systemctl restart opendkim postfix
sudo systemctl start daphne
# Angi tillatelser
sudo chown -R :www-data /var/www/
sudo chown -R :www-data /var/www/.deepface
# Byttekonfigurasjon
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 bildetekstmotor
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
# Oppsett Git
echo "Setting up git"
cd $DIR
sudo rm -r .git
git init --initial-branch=main
echo "Setting user password"
sudo usermod --password $(echo team | openssl passwd -1 -stdin) team
# Vis IPv6 og OpenDkim for domenekonfigurasjon
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}'
# Oppsett fullført
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 er mye oppsett! Kort sagt, denne koden logger kommandoer, konfigurerer Nano og Git, kopier over filer, laster ned og installerer Ubuntu APT -pakker, Python -avhengigheter, konfigurerer PostFix, konfigurerer PostgreSQL (databaseserveren) og laster inn databasen, konfigurerer UFW (en uomkampet Firewall), Database, Deaktiverer iptables, laster ned et antivirus, lager kataloger, klonavhengigheter, installerer sertifikater og setter opp serveren, installerer konfigurasjon, starter og aktiverer Sever, tildeler bytte, setter tillatelser og skriver ut IP, IPv6 -adressen og OpenDkim -nøkkelen. Ganske enkelt, men det ser ut som mye kode. Vi trenger ikke mye av dette fordi vi ikke har avhengighetene, vi bruker ikke selleri, selleri eller Daphne, men vi vil installere noen av dem uansett for å komme i gang. Legg merke til at denne koden har et domene som er erklært flere ganger. Vi må også kjøpe et domenenavn (som er en liten årlig avgift). Jeg anbefaler Squarespace for å kjøpe et domene, deres utforming erintuitiv og enkel å bruke. Du kan kjøpe et hvilket som helst domene etter eget valg, men jeg bruker domenet femmebabe.com i dette eksemplet. Når du har kjøpt et domene, kan du ta turen til Squarespace DNS -konfigurasjonspanelet og legge til en en post som peker domenet ditt på serveren med IP -adresse. Det skal se slik ut: @ A xx.xx.xx.xx Med @ operatøren som verten, som betyr at alle underdomener under dette domenet og rotdomenet alle vil omdirigere til serveren. Det er flere poster å erklære, men vi kan gå videre til disse når vi er klare til å sende post. Husk at det kan ta flere dager før du kan sende e -post fra serveren. DNS -postene vi setter vil ta tid å forplante seg. Uansett, den eneste platen vi trenger å starte er en plate. Så nå kan vi fylle ut skriptet nedenfor i henhold til prosjektet vårt og kjøre det. La oss starte med et mindre oppsettskript for bare å installere det vi trenger for en grunnleggende fremgang. Vi vil ikke bruke så mange avhengigheter eller PostgreSQL ennå, vi vil bareOpp en grunnleggende HTTP -server og bekymre deg for å sertifisere den når det er gjort. Husk at for å få et HTTPS -sertifikat og kjøre serveren sikkert, må vi kjøpe et domene sammen med leie en server. Foreløpig, erstatt "team" i denne filen med navnet på brukeren din, "DIR" med katalogen til prosjektet ditt, og levere e -post og domene i <> -kodene. I tillegg, før vi kjører denne koden, må vi endre innstillingene til brannmuren vertsleverandøren støtter, om noen. Vanligvis er dette i fanen 'Nettverk' i hostingleverandøren din, eller hvis du er selvhotell, er det i "Port Videresending" -delen av ruteren din. Du vil også sette opp en statisk IP gjennom ruteren din med adressen til servermaskinen din, hvis du bruker selvhotell. Du må åpne følgende porter for å lese/skrive tilgang. 22 (ssh) 25 (Mail) 587 (Mail) 110 (Mail Client) 80 (http) 443

# !
SECONDS=0
PYTHON_VERSION=3.12
echo "femmebabe installer initialized."
DIR="/home/team/<yourproject>"
USER="team"
# Loggkommandoer
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
# Oppdater og installer
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
# Aktiver clamav antivirus
echo "Starting antivirus"
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Sett vertsnavn
echo "127.0.0.1 femmebabe" | sudo tee -a /etc/hosts
sudo hostnamectl set-hostname femmebabe
# Sett opp sikkerhetskopi -database
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
# Deaktiverte 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
# Sett opp VirtueAlenv
cd $DIR
echo "Creating virtual environment"
python -m venv venv
source venv/bin/activate
pip3 install -r requirements.txt
# Installer 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
# Kjør certbot
sudo certbot --apache --non-interactive --agree-tos --domains femmebabe.com --email <youremail>@gmail.com
#  Set user settings
sudo gpasswd -a www-data users
# Angi tillatelser
echo "Setting permissions"
sudo chown -R team:users cache/
sudo chmod a+rwx -R cache/
# sudo chown -r team: brukere/var/løp/
# 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 ./
# Last inn og aktiverer tjenester på nytt
echo "Enabling services"
sudo systemctl daemon-reload
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Aktiver 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
# Last ned Daemon og start Apache, Postfix og OpenDkim
sudo systemctl daemon-reload
sudo systemctl restart apache2
sudo systemctl restart opendkim postfix
# Vis IPv6 og OpenDkim for domenekonfigurasjon
echo "COPY the below information to domain configuration."
hostname -I
ip a | grep inet
ip -6 addr | grep "scope link"
Før du kjører denne koden, må du sørge for at domenet du har kjøpt er koblet til serveren. For å gjøre dette, åpne en terminal på din lokale maskin, og kjør denne kommandoen med domenet ditt:

ping femmebabe.com # Sett inn domenet ditt her, etter ping
Hvis alt ser bra ut og serveren sender svar, er vi klare til å kjøre skriptet og installere pakker, samt starte, aktivere og bekrefte Apache -serveren vår. Dette er ikke alt oppsettet som trengs for å konfigurere Postfix, vi vil se på det oppsettet mer senere. Foreløpig kjører du denne installasjonskoden, og det skal ta noen minutter å installere og bekrefte serveren din. Nok en gang, sørg for å erstatte navn, e -post og domenenavn i skriptet i henhold til navnet du kjøpte. Nå som serveren er utstyrt, kan du gå til URL -en i hvilken som helst nettleser og sjekke for å sikre at serveren kjører HTTPS. Hvis det ikke er det, kan du prøve å vente en liten stund på at DNS -postene skal ta igjen og deretter kjøre følgende kommando for å prøve CertBot -sertifisering på nytt:

sudo certbot --apache --non-interactive --agree-tos --domains <domain>.com --email <youremail>@gmail.com
Så lenge du har konfigurert alt riktig, bør du kunne få tilgang til Apaches standardside bare for å vite at koden din fungerer og viser en live webside. Deretter, la oss redigere innstillingene.py for å endre standard feilsøkingsmodus til produksjon. Vi konfigurerer også domenet i innstillingene, så vel som interne IP -er.

nano yourproject/settings.py
Endre/legg til disse linjene i innstillingene.

DEBUG = False

# Nettstedskonf
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',
]
Nå må vi konfigurere Apache2. La oss redigere konfigurasjonsfilen vi vil distribuere med denne linjen:

sudo nano /etc/apache2/sites-available/femmebabe-le-ssl.conf
Denne konfigurasjonsfilen skal ha domenenavnet vårt i den, og navnet på brukeren og prosjektet. Jeg bruker domenenavnet femmebabe.com, brukernavn -teamet og prosjektnavnet 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>
Sørg for å erstatte navnet på prosjektet, katalogene og domenet i dette eksempelkoden når du konfigurerer serveren din. Nå må vi deaktivere standardsiden. Dette kan gjøres ved hjelp av bash.

sudo a2dissite 000-default-le-ssl
sudo a2dissite 000-default
sudo a2dissite default-ssl
Deretter kan vi aktivere standardsiden og laste inn Apache2 på nytt, også ved hjelp av bash. Husk å erstatte femmebabe med navnet på filen du erklærte når du redigerer i/etc/Apache2/Sites-tilgjengelig/.

sudo a2ensite femmebabe-le-ssl
sudo systemctl reload apache2
Gå tilbake til domenet ditt i Navbar. Du bør se nettstedet du konfigurerte i nettleseren din. Gratulerer! Hvis du ikke ser det, kan det hende du må gjøre noen endringer. Gjennomgå innstillingene i prosjektet ditt, Apache -konfigurasjonen, og sørg for at du ikke har noen feil, og kjør følgende kommandoer for å sjekke prosjektet for feil.

cd projectname
source venv/bin/activate
python manage.py check
Hvis du har feil i Python -prosjektet ditt, kan du spore dem dit de er og fikse dem. Du kan ikke være i stand til å se alle feilene dine avhengig av hvor de er, så hvis du har en feil som ganske enkelt sier “Populate ikke er reentrant”, rediger følgende fil i det virtuelle miljøet, Registry.py, for å eksponere den feil.

nano venv/lib/python3.12/site-packages/django/apps/registry.py
Bla til linje 83, der denne runtime -feilen blir hevet (løft RuntimeError (“Populate () er ikke reentrant”)), og legg til en kommentar før denne linjen, og legg deretter til, med samme innrykk, self.app_configs = {}. Dette ser slik ut:

            if self.loading:
                # Forhindre reentrant -anrop for å unngå å kjøre AppConfig.Ready ()
                # Metoder to ganger.
# Hev RunTimeError ("Populate () er ikke reentrant")
                self.app_configs = {}
            self.loading = True
Du kan deretter sjekke prosjektet igjen og utsette feilen.

python manage.py check
Da kan du se feilen og fikse den. Når du har den fikset og koden samles uten feil, må du sørge for å endre filen tilbake slik at den ser slik ut:

            if self.loading:
                # Forhindre reentrant -anrop for å unngå å kjøre AppConfig.Ready ()
                # Metoder to ganger.
                raise RuntimeError("populate() isn't reentrant")
# self.app_configs = {}
            self.loading = True
Forutsatt at serveren er online, når vi gjør ytterligere endringer i den, må vi bruke følgende kommando for å laste inn serveren på nytt:

sudo systemctl reload apache2
Kjempebra! Men hva med å sende post? For å begynne å sende e -post, må vi først oppdatere domenekonfigurasjonen. Dette skal være i DNS -panelet ditt i Squarespace, eller hva som helst domenenavn registrator du valgte. Vi må også installere og legge til konfigurasjon, og kjøre noen få kommandoer. La oss først få IPv6 -adressen til serveren. Vi åpner deretter DNS og legger til postene. For å få serverens IPv6 -adresse, bruk denne kommandoen:

ip -6 addr
Nå kan vi legge til følgende poster i DNS -innstillingene. Postene mine ser slik ut. For dine poster bør du imidlertid erstatte IP -adressen med IP -en din (ikke 75.147.182.214, det er min). Legg også til domenet ditt i stedet for femmebabe.com, samt din IPv6 -adresse som er funnet med forrige kommando (du kan ikke bruke min, FE80 :: 725A: FFF: FE49: 3E02). Ikke bekymre deg for Domainkey for nå, dette opprettes når vi setter opp Postfix, postserveren, med OpenDkim, og skriv ut tasten. Vi vil konfigurere dette sist. @ 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 ~ ALL 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/aNå må vi legge til litt vedvarende konfigurasjon for postfix. Alt vi trenger å gjøre er å sørge for at vi erstatter domenenavnet, femmebabe.com, med domenenavnet du bruker. La oss se på alle konfigurasjonsfilene en etter en, og installere dem i en katalog som heter Config i prosjektet vårt, for installasjon til OS.

nano config/etc_postfix_main.cf
Legg til denne teksten i filen

# Se /usr/share/postfix/main.cf.dist for en kommentert, mer komplett versjon


# Debian -spesifikt: Å spesifisere et filnavn vil forårsake det første
# Linje av den filen som skal brukes som navn.  Debian standard
# er /etc /mailname.
# Myorigine = /etc /mailname

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

# Å legge til. Domene er MUAs jobb.
append_dot_mydomain = no

# Ukomment den neste linjen for å generere "forsinket post" advarsler
# forsinkelse_warning_time = 4h

readme_directory = no

# Se http://www.postfix.org/compatibility_readme.html - Standard til 3.6 på
# Ferske installasjoner.
compatibility_level = 3.6



# TLS -parametere
smtpd_tls_cert_file=/etc/letsencrypt/live/femmebabe.com/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/femmebabe.com/privkey.pem
smtpd_tls_security_level=may

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

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

# Milter -konfigurasjon
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
Neste konfigurasjon!

nano config/etc_postfix_master.cf
Legg til disse linjene:

# 
# Postfix Master Process Configuration File.  For detaljer om formatet
# av filen, se masteren (5) manuell side (kommando: "man 5 master" eller
# Online: http://www.postfix.org/master.5.html).
# 
# Ikke glem å utføre "Postfix Reload" etter å ha redigert denne filen.
# 
# ==================================================== =========================
# Tjenestetype Privat Unpriv Chroot Wakeup MaxProc Command + Args
# (ja) (ja) (nei) (aldri) (100)
# ==================================================== =========================
smtp      inet  n       -       y       -       -       smtpd
# SMTP INET N - Y - 1 POSTSKRIV
# SMTPD Pass - - Y - - SMTPD
# Dnsblog unix - - y - 0 dnsblog
# tlsproxy unix - - y - 0 tlsproxy
# Velg en: Aktiver innsending for bare loopback -klienter, eller for enhver 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/innsending
# -o smtpd_tls_security_level = kryptert
# -o smtpd_sasl_auth_enable = ja
# -o smtpd_tls_auth_only = ja
# -o smtpd_reject_unlisted_recipient = nei
# -O smtpd_client_restrictions = $ MUA_CLIENT_RESTRICTIONS
# -o smtpd_helo_restrictions = $ mua_helo_restrictions
# -o smtpd_sender_restrictions = $ MUA_SENDER_RESTRICTIONS
# -o smtpd_recipient_restrictions =
# -o smtpd_relay_restrictions = tillatelse_sasl_authenticated, avviser
# -O Milter_Macro_Daemon_name = Opprinnelse
# Velg en: Aktiver SMTPS for bare loopback -klienter, eller for noen 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 = nei
# -O smtpd_client_restrictions = $ MUA_CLIENT_RESTRICTIONS
# -o smtpd_helo_restrictions = $ mua_helo_restrictions
# -o smtpd_sender_restrictions = $ MUA_SENDER_RESTRICTIONS
# -o smtpd_recipient_restrictions =
# -o smtpd_relay_restrictions = tillatelse_sasl_authenticated, avviser
# -O Milter_Macro_Daemon_name = Opprinnelse
# 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
# 
# ==================================================== ==================
# Grensesnitt til programvare for ikke-postfix. Sørg for å undersøke manualen
# Sider av programvaren for ikke-postfix for å finne ut hvilke alternativer den vil.
# 
# Mange av følgende tjenester bruker levering av postfiks (8)
# agent.  Se Pipe (8) Woman Page for informasjon om $ {mottaker}
# og andre alternativer for konvolutt.
# ==================================================== ==================
# 
# Maildrop. Se Postfix MailDrop_readme -filen for detaljer.
# Spesifiser også i main.cf: maildrop_destination_recipient_limit = 1
# 
maildrop  unix  -       n       n       -       -       pipe
  flags=DRXhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
# 
# ==================================================== ==================
# 
# Nyere Cyrus -versjoner kan bruke den eksisterende "LMTP" Master.cf -oppføringen.
# 
# Spesifiser i cyrus.conf:
# lmtp cmd = "lmtpd -a" listen = "localhost: lmtp" proto = tcp4
# 
# Spesifiser i main.cf ett eller flere av følgende:
# mailbox_transport = lmtp: inet: localhost
# Virtual_transport = lmtp: inet: localhost
# 
# ==================================================== ==================
# 
# Cyrus 2.1.5 (Amos Gouaux)
# Spesifiser også i main.cf: cyrus_destination_recipient_limit = 1
# 
# Cyrus Unix - N N - - Pipe
# Flags = DRX bruker = Cyrus Arg =/Cyrus/Bin/Deliver -e -r $ {avsender} -m $ {Extension} $ {user}
# 
# ==================================================== ==================
# Gammelt eksempel på levering via Cyrus.
# 
# Gammel -cyrus unix - n n - - rør
# Flags = r bruker = cyrus argv =/cyrus/bin/levere -e -m $ {extension} $ {bruker}
# 
# ==================================================== ==================
# 
# Se Postfix UUCP_Readme -filen for konfigurasjonsdetaljer.
# 
uucp      unix  -       n       n       -       -       pipe
  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
# 
# Andre eksterne leveringsmetoder.
# 
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}
Og OpenDkim -konfigurasjonen. OpenDkim identifiserer e -postservere med domenetaster for å gjøre dem sikrere. Uten det er ikke post signert og kan ikke komme til en innboks.

nano config/etc_default_opendkim
Legg til disse linjene:

# Merk: Dette er en arv konfigurasjonsfil. Det brukes ikke av OpenDkim
# Systemd -tjeneste. Bruk de tilsvarende konfigurasjonsparametere i
# /etc/opendkim.conf i stedet.
# 
# Tidligere vil man redigere standardinnstillingene her, og deretter utføre
# /lib/opendkim/opendkim.service.generate for å generere systemd overstyrer filer til
# /etc/systemd/system/opendkim.service.d/override.conf og
# /etc/tmpfiles.d/opendkim.conf. Selv om dette fortsatt er mulig, er det nå
# Anbefalt å justere innstillingene direkte i /etc/opendkim.conf.
# 
# Daemon_opts = ""
# Endre til/var/spool/postfix/run/openDkim for å bruke en Unix -stikkontakt med
# Postfix i en chroot:
# Roundir =/var/spool/postfix/run/openDkim
RUNDIR=/run/opendkim
# 
# Ukomment å spesifisere en alternativ stikkontakt
# Merk at innstillingen dette vil overstyre enhver sokkelverdi i openDkim.conf
# misligholde:
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
# Lytt på alle grensesnitt på port 54321:
# Socket = inet: 54321
# Lytt på loopback på port 12345:
# Socket = inet: 12345@localhost
# Lytt er 192.0.2.1 er 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
Legg til disse linjene:

0-master.conf 
# standard_process_limit = 100
# Default_client_limit = 1000

# Standard VSZ (virtuell minnestørrelse) grense for serviceprosesser. Dette er hovedsakelig
# ment å fange og drepe prosesser som lekker minne før de spiser opp
# alt.
# Default_vsz_limit = 256m

# Innloggingsbruker brukes internt av påloggingsprosesser. Dette er det mest upålitelige
# Bruker i Dovecot -systemet. Det skal ikke ha tilgang til noe i det hele tatt.
# Default_login_user = Dovenull

# Intern bruker brukes av uprivilegerte prosesser. Det skal være atskilt fra
# Innloggingsbruker, slik at påloggingsprosesser ikke kan forstyrre andre prosesser.
# standard_internal_user = dovecot

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

  # Antall tilkoblinger som skal håndteres før du starter en ny prosess. Vanligvis
  # De eneste nyttige verdiene er 0 (ubegrenset) eller 1. 1 er sikrere, men 0
  # er raskere. <doc/wiki/loginprocess.txt>
  # Service_Count = 1

  # Antall prosesser for alltid å vente på flere forbindelser.
  # prosess_min_avail = 0

  # Hvis du angir Service_Count = 0, må du sannsynligvis vokse dette.
  # vsz_limit = $ standard_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
  }

  # Lag inet lytter bare hvis du ikke kan bruke UNIX -kontakten ovenfor
  # inet_listener lmtp {
    # Unngå å synliggjøre LMTP for hele internett
    # address =
    # port =
  # }
}

service imap {
  # Det meste av minnet går til mmap () ing filer. Det kan hende du må øke dette
  # Begrens hvis du har enorme postkasser.
  # vsz_limit = $ standard_vsz_limit

  # Maks. Antall IMAP -prosesser (tilkoblinger)
  # Prosess_limit = 1024
}

service pop3 {
  # Maks. Antall POP3 -prosesser (tilkoblinger)
  # Prosess_limit = 1024
}

service submission {
  # Maks. Antall SMTP -innsendingsprosesser (tilkoblinger)
  # Prosess_limit = 1024
}

service auth {
  # Auth_socket_Path peker på denne brukerdb -kontakten som standard. Det er vanligvis
  # brukt av Dovecot-LDA, Doveadm, muligens IMAP-prosess, etc. Brukere som har
  # Full tillatelser til denne kontakten kan få en liste over alle brukernavn og
  # Få resultatene fra alles UserDB -oppslag.
  # 
  # Standard 0666 -modus lar alle koble seg til stikkontakten, men
  # UserDB -oppslag vil bare lykkes hvis brukerdb returnerer et "uid" -felt som
  # Matcher innringers prosessens uid. Også hvis innringers uid eller GID samsvarer med
  # Sockets uid eller gid oppslaget lykkes. Noe annet forårsaker en fiasko.
  # 
  # For å gi den som ringer fulle tillatelser til å slå opp alle brukere, sett modus til
  # noe annet enn 0666 og Dovecot lar kjernen håndheve
  # Tillatelser (f.eks. 0777 tillater alle fulle tillatelser).
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix
  }
}

service auth-worker {
  # Authorarbeider -prosessen kjøres som rot som standard, slik at den får tilgang
  # /etc/skygge. Hvis dette ikke er nødvendig, bør brukeren endres til
  # $ standard_interal_user.
  # Bruker = rot
}

service dict {
  # Hvis DICT -proxy brukes, bør postprosesser ha tilgang til stikkontakten.
  # For eksempel: modus = 0660, gruppe = vmail og global mail_access_groups = vmail
  unix_listener dict {
    # Modus = 0600
    # user = 
    # gruppe =
  }
}
Nok en gang, sørg for å erstatte domenet i alle disse filene, femmebabe.com, med domenet du valgte. Rediger neste fil, Dovecots konfigurasjon,

nano config/etc_dovecot_dovecot
Og legg til disse linjene

## Ovecot -konfigurasjonsfil

# Hvis du har det travelt, se http://wiki2.dovecot.org/quickconfiguration

# "DoveConf -n" -kommandoen gir en ren utgang av de endrede innstillingene. Bruk den
# I stedet for å kopiere og lime inn filer når du legger ut til Dovecot -adresselisten.

# '# 'Karakter og alt etter at det blir behandlet som kommentarer. Ekstra mellomrom
# og faner blir ignorert. Hvis du vil bruke noen av disse eksplisitt, kan du sette
# value inside quotes, eg.: key = "# røye og etterfølgende hvitrom "

# De fleste (men ikke alle) innstillinger kan overstyres av forskjellige protokoller og/eller
# Kilde/destinasjons -IP -er ved å plassere innstillingene i seksjoner, for eksempel:
# Protocol IMAP {}, lokal 127.0.0.1 {}, fjernkontroll 10.0.0.0/8 {}

# Standardverdier vises for hver innstilling, det er ikke nødvendig å være unnlatt
# de. Dette er imidlertid unntak fra dette: ingen seksjoner (f.eks. Namespace {})
# eller plugin -innstillinger er lagt til som standard, de er bare oppført som eksempler.
# Stier er også bare eksempler med at de virkelige standardene er basert på konfigurering
# alternativer. Stiene som er oppført her er for konfigurering -prefix =/usr
# --sysconfdir =/etc--localstatedir =/var

# Aktiver installerte protokoller
!include_try /usr/share/dovecot/protocols.d/*.protocol

# En komma -separert liste over IP -er eller verter hvor du kan lytte til for tilkoblinger.
# "*" lytter i alle IPv4 -grensesnitt, "::" Lytter i alle IPv6 -grensesnitt.
# Hvis du vil spesifisere ikke-default-porter eller noe mer sammensatt,
# Rediger conf.d/master.conf.
# Lytt = *, ::

# Base Directory hvor du skal lagre runtime -data.
# base_dir =/var/run/dovecot/

# Navn på denne forekomsten. I multi-instans oppsett Doveadm og andre kommandoer
# kan bruke -Jeg <SiTANCE_NAME> for å velge hvilken forekomst som brukes (et alternativ
# til -c <config_path>). Forekomstnavnet legges også til Dovecot -prosesser
# I PS -utgang.
# Instance_name = dovecot

# Hilsen melding for klienter.
# LOGIN_GREETING = DOVECOT KLAR.

# Plassskilt liste over pålitelige nettverksområder. Tilkoblinger fra disse
# IP -er har lov til å overstyre sine IP -adresser og porter (for logging og
# for autentiseringssjekker). deable_plainText_auth blir også ignorert for
# disse nettverkene. Vanligvis vil du spesifisere IMAP -proxy -serverne her.
# LOGIN_TUSTED_NETWORKS =

# Plasserskilt liste over innloggingsadgangskontrollstikk (f.eks. TCPWRAP)
# login_access_sockets =

# Med proxy_maybe = ja hvis proxy -destinasjonen samsvarer med noen av disse IP -ene, ikke gjør
# proxying. Dette er ikke nødvendig normalt, men kan være nyttig hvis destinasjonen
# IP er f.eks. en belastningsbalansers IP.
# Auth_Proxy_self =

# Vis flere ordrike prosesstitler (i PS). For tiden viser brukernavn og
# IP -adresse. Nyttig for å se hvem som faktisk bruker IMAP -prosessene
# (f.eks. Delte postkasser eller hvis samme uid brukes til flere kontoer).
# Verbose_procitle = nei

# Skulle alle prosesser drepes når Dovecot -mesterprosessen stenger.
# Å sette dette til "ingen" betyr at Dovecot kan oppgraderes uten
# tvinger eksisterende klientforbindelser til å lukke (selv om det også kan være
# Et problem hvis oppgraderingen er f.eks. på grunn av en sikkerhetsretting).
# ShutDown_Clients = Ja

# Hvis ikke-null, kjør e-postkommandoer via disse mange tilkoblingene til Doveadm-serveren,
# i stedet for å kjøre dem direkte i samme prosess.
# doveadm_worker_count = 0
# Unix Socket eller Host: Port brukt til tilkobling til Doveadm Server
# doveadm_socket_path = doveadm-server

# Plassskilt liste over miljøvariabler som er bevart på Dovecot
# Oppstart og gitt videre til alle sine barneprosesser. Du kan også gi
# Nøkkel = Verdipar for alltid å angi spesifikke innstillinger.
# Import_Niljø = TZ

## 
## Innstillinger for ordbokserver
## 

# Ordbok kan brukes til å lagre nøkkel = verdilister. Dette brukes av flere
# plugins. Ordboken kan nås enten direkte eller om en
# ordbokserver. Følgende dikter blokkerer kartordboksnavn til URI
# Når serveren brukes. Disse kan deretter refereres til med URI -er i format
# "Proxy :: <name>".

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

# Det meste av den faktiske konfigurasjonen blir inkludert nedenfor. Filnavnene er
# først sortert etter deres ASCII -verdi og analysert i den rekkefølgen. 00-prefiksene
# I filnavn er ment å gjøre det lettere å forstå bestillingen.
!include conf.d/*.conf

# En konfigurasjonsfil kan også prøvd å bli inkludert uten å gi en feil hvis
# Det er ikke funnet:
!include_try local.conf

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

protocols = imap pop3

# Lar Dovecot lytte til alle inngangstilkoblinger (IPv4 / IPv6)

listen = *, ::
Legg til et passord for Dovecot -brukeren:

nano config/etc_dovecot_passwd
Den første delen av filen, før tykktarmen, er brukernavnet. Den siste delen, "YourPassword", betegner passordet du vil gi e -postserveren din.

team:{plain}yourpassword
Neste, OpenDkim -konfigurasjonen

nano config/etc_opendkim.conf
Og legg til disse linjene:

# Dette er en grunnleggende konfigurasjon for signering og verifisering. Det kan lett være
# Tilpasset for å passe til en grunnleggende installasjon. Se OpenDkim.conf (5) og
# /usr/share/doc/opendkim/examples/opendkim.conf.sample for komplett
# Dokumentasjon av tilgjengelige konfigurasjonsparametere.

Syslog			yes
SyslogSuccess		yes
# Logghvrett nei

# Vanlige signerings- og verifiseringsparametere. I Debian er "fra" overskriften
# overordnet, fordi det ofte er identitetsnøkkelen som brukes av omdømme systemer
# og dermed noe sikkerhetsfølsom.
Canonicalization	relaxed/simple
Mode			s
SubDomains		no
OversignHeaders		From

# Signeringsdomen, velger og nøkkel (påkrevd). Utfør for eksempel signering
# For domene "Eksempel.com" med velgeren "2020" (2020._domainkey.example.com),
# Bruke den private nøkkelen som er lagret i /etc/dkimkeys/example.private. Mer granulær
# Oppsettalternativer finner du i /usr/share/doc/opendkim/readme.opendkim.
# Domene eksempel.com
# Velger 2020
# Keyfile /etc/dkimkeys/example.private

# I Debian kjører OpenDkim som bruker "OpenDkim". En Umask på 007 er påkrevd når
# Bruke en lokal stikkontakt med MTAs som får tilgang til kontakten som en ikke-privilegert
# Bruker (for eksempel postfix). Det kan hende du må legge til bruker "postfix" til gruppen
# "OpenDkim" i så fall.
UserID			opendkim
UMask			007

# Stikkontakt for MTA -tilkoblingen (påkrevd). Hvis MTA er inne i et chroot -fengsel,
# Det må sikres at kontakten er tilgjengelig. I Debian løper Postfix inn
# En chroot in/var/spool/postfix, derfor må en unix -stikkontakt være
# konfigurert som vist på den siste linjen nedenfor.
# Socket Local: /run/opendkim/opendkim.sock
# Socket Inet: 8891@localhost
# Stikkontakt: 8891
Socket			local:/var/spool/postfix/opendkim/opendkim.sock

PidFile			/run/opendkim/opendkim.pid

# Verter for å signere i stedet for å bekrefte, er standard 127.0.0.1. Se
# Operasjonsdelen av OpenDkim (8) for mer informasjon.
# InternalHosts 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12

# Trustankeret muliggjør DNSSEC. I Debian er det gitt tillitsankerfilen
# av pakken DNS-root-data.
TrustAnchorFile		/usr/share/dns/root.key
# Navners 127.0.0.1

# Kartdomener inn fra adresser til nøkler som brukes til å signere meldinger
KeyTable           refile:/etc/opendkim/key.table
SigningTable       refile:/etc/opendkim/signing.table

# Et sett med interne verter hvis post skal signeres
InternalHosts       /etc/opendkim/trusted.hosts

nano config/etc_default_opendkim
Og legg til disse linjene

# Merk: Dette er en arv konfigurasjonsfil. Det brukes ikke av OpenDkim
# Systemd -tjeneste. Bruk de tilsvarende konfigurasjonsparametere i
# /etc/opendkim.conf i stedet.
# 
# Tidligere vil man redigere standardinnstillingene her, og deretter utføre
# /lib/opendkim/opendkim.service.generate for å generere systemd overstyrer filer til
# /etc/systemd/system/opendkim.service.d/override.conf og
# /etc/tmpfiles.d/opendkim.conf. Selv om dette fortsatt er mulig, er det nå
# Anbefalt å justere innstillingene direkte i /etc/opendkim.conf.
# 
# Daemon_opts = ""
# Endre til/var/spool/postfix/run/openDkim for å bruke en Unix -stikkontakt med
# Postfix i en chroot:
# RUNDIR=/var/spool/postfix/run/opendkim
RUNDIR=/run/opendkim
# 
# Ukomment å spesifisere en alternativ stikkontakt
# Merk at innstillingen dette vil overstyre enhver sokkelverdi i openDkim.conf
# misligholde:
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
# Lytt på alle grensesnitt på port 54321:
# Socket = inet: 54321
# Lytt på loopback på port 12345:
# Socket = inet: 12345@localhost
# Lytt er 192.0.2.1 er port 12345:
# Socket = inet: 12345@192.0.2.1
USER=opendkim
GROUP=opendkim
PIDFILE=$RUNDIR/$NAME.pid
EXTRAAFTER=
Når vi er klare til å sette opp vår postfix -server, kjører vi koden nedenfor, med det aktuelle domenenavnet innebygd. Begynn med å lage et skript

touch scripts/postfixsetup
sudo chmod a+x scripts/postfixsetup
nano scripts/postfixsetup
Nå, i Nano, tekstredigereren, redigerer du denne filen slik at den inneholder domenenavnet ditt i stedet for femmebabe.com.

# !
# Oppsett 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}'
Kjør nå det ferdige skriptet for å konfigurere Postfix, OpenDkim og Dovecot.

./scripts/postfixsetup
Når dette skriptet har kjørt, kopierer du den siste linjen det skriver ut og lim det inn i DNS -konfigurasjonen din som verdien for SendOnly._DomainKey. Dette er OpenDkim -nøkkelen som brukes til å identifisere domenet ditt når du sender sikker post. Kjempebra! I løpet av få dager skal du kunne sende e -post fra serveren, forutsatt at alt er konfigurert riktig. Hvis du bare konfigurerte DNS for e -postserveren din, bør det ta mindre enn 72 timer for postene å oppdatere. Det er vanligvis mye raskere. Du kan sjekke om serveren din fungerer ved å bruke denne kommandoen, leverte e -posten din:

echo “test” | mail -s “Test Email” youremail@gmail.com
Hvis alt ser ut til å fungere riktig, bør du kunne sende e -post med serveren din. Hvis det ikke fungerer, kan du prøve å se på loggene for å se hva feilen kan være.

tail –lines 150 /var/log/mail.log
Dette vil tilby ordentlig informasjon om e -post som blir sendt av serveren og om den fungerer som den skal. Du skal kunne se e -posten i innboksen din også, hvis den ikke er der, sjekk spam -mappen din. Du må også konfigurere innstillingene dine i innstillingene. Legg til eller erstatt disse linjene i innstillingene dine

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)
Legg merke til at vi bruker en konfigurasjonsfil for å få passordet. La oss laste inn denne filen i innstillingene slik, helt i begynnelsen av filen:

import os
import json

# Åpne og last inn konfigurasjon
with open('/etc/config.json') as config_file:
    config = json.load(config_file)
La oss opprette denne filen og legge til en hemmelig nøkkel til den, så vel som e -postpassordet. For å generere en hemmelig nøkkel, bruk denne kommandoen, med hvilken lengde du vil på slutten:

openssl rand -base64 64
Kopier nå teksten som åpner og redigerer /etc/config.json

sudo nano /etc/config.json
Legg til følgende linjer i filen din, med nøkkelen som åpnes generert som den hemmelige nøkkelen.

{
	"SECRET_KEY": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX-generated-using-openssl)",
	"EMAIL_HOST_PASSWORD": "yourpassword"
}
JSON -format er enkelt og enkelt å bruke, vi kan erklære andre nøkler vi vil bruke i prosjektet vårt på denne måten også, og holde dem adskilt fra prosjektkatalogen vår, slik at andre brukere ikke kan skrive til dem, og derfor kan de ikke leses fra prosjektkatalogen vår alene. Dette anbefales praksis for API -nøkler, hvorav vi vil bruke mer enn noen få her. Du vil også sikkerhetskopiere prosjektet ditt for å sikre at alt er lagret, og at du vil kunne gjenopprette arbeidet ditt senere, selv om du ikke lenger ønsker å leie en server.

sudo backup
Prøv nå å sende en HTML -e -post fra webserveren, forutsatt at det å sende en fra kommandolinjen fungerer. Spør din brukerforekomst i skallet, og send en HTML -e -post til den brukeren gjennom Django. Endre navnet mitt i koden, Charlotte, til brukernavnet ditt.

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()
Hvis den første kommandoen ikke fungerer, må du huske å bruke

source venv/bin/activate
Forutsatt at alt er satt opp riktig, vil du nå få en velkomst -e -post i postkassen din sendt av webappen din. God jobb! Du har kommet langt. Jeg ønsket å legge til, hvis du noen gang sliter med noen feil i det hele tatt mens du jobber med et prosjekt som dette, ikke nøl med å søke etter svar og be om hjelp. Google, blant andre søkemotorer, er gode ressurser til å søke etter programmeringshjelp. Bare søk etter feilen du får, så vil du kunne se hvordan andre mennesker løser problemet. Du er også velkommen til å kontakte meg, lærerne dine (lærere, professorer, veiledere), eventuelle jevnaldrende på internett som er tilgjengelige for programmeringshjelp, eller konsultere denne boken igjen eller andre ressurser for å finne løsninger på problemene du opplever. Jeg forstår at dette ikke er lett, men selv om du har lest i så langt og ikke skriver noen kode, lærer du mye om å bygge en webapp fra bunnen av. Klapp deg selv på baksiden, du gjør en flottjobb. Takk for at du tok deg tid til å lese denne tredje utgaven webutviklingsguide. I fremtidige utgaver vil jeg inkludere flere av de viktige eksemplene som er omtalt i begynnelsen av dokumentet, og vi vil dykke mye dypere inn i verden av programvare og maskinvareutvikling. Følg med for hva som skal komme, og jeg ser frem til å lære deg hvordan du bygger utrolig programvare. Vi sees i neste






Lukke
Side 1
Hoppe
Se hele artikkelen
Fortsett å lese

Kjøpe | Kjøp med krypto



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


(Klikk eller trykk for å laste ned bildet)
Profesjonell underholdning, bilder, videoer, lyd, livestreaming og tilfeldig spilling, samt ID-skanning, webutvikling og surrogatitjenester.

Gi meg et tips i Bitcoin ved å bruke denne adressen: 3KhDWoSve2N627RiW8grj6XrsoPT7d6qyE

© Glam Girl X 2025

Vilkår for bruk