การเรียนรู้เชิงลึกและการรักษาความปลอดภัยบนเว็บเชิงปฏิบัติตามตัวอย่าง

Daisyรูปโปรไฟล์

โดย Daisy

การเรียนรู้อย่างลึกซึ้งบนเว็บที่ใช้งานได้จริงโดยตัวอย่าง ฉบับที่สาม Charlotte Harper 3 กรกฎาคม 2567 คำนำ: ข้อควรพิจารณาด้านความปลอดภัยในการสร้างซอฟต์แวร์สำหรับเว็บเป็นส่วนสำคัญของแผนและการดำเนินการของนักพัฒนาเว็บใด ๆ ในขณะที่วิศวกรรมต้นแบบที่เชื่อถือได้มั่นคงและมีประโยชน์สำหรับวัตถุประสงค์ในทางปฏิบัติ มาร์กอัป DOM (เอกสารมาร์กอัป) โดยมีการใช้งานของ HTML, JavaScript และ CSS รวมถึงซอฟต์แวร์แบ็กเอนด์ที่ใช้ Python, C/C ++, Java และ Bash ทำให้นักพัฒนาเว็บมีอิสระและพลังในการสร้างโครงการที่หลากหลาย ความคิดสร้างสรรค์ให้ความสะดวกในการใช้งานและฟังก์ชั่นการพรรณนาถึงความอ่อนน้อมถ่อมตนและตัวละครและให้ความสะดวกในการใช้งานรวมถึงความสะดวกสบายและบริการที่สำคัญที่น่าสนใจสำหรับ Joe โดยเฉลี่ยผู้ใช้ปลายทางที่ต้องการฆ่าเวลาหรือทำอะไรบางอย่างบนอินเทอร์เน็ต มักจะอยู่บนอุปกรณ์สมาร์ทโฟนหน้าจอสัมผัส คนส่วนใหญ่ไม่รู้ด้วยซ้ำว่าจะเริ่มต้นตรงไหนเมื่อพวกเขาต้องการสร้างเว็บไซต์ตั้งแต่เริ่มต้นพวกเขามักจะเริ่มต้นในเว็บไซต์ของบุคคลอื่นและสร้างสิ่งที่ จำกัด ในการใช้งานความน่าเชื่อถือความสะดวกในการใช้งานและความคิดสร้างสรรค์โดยเฉพาะอย่างยิ่งเมื่อพวกเขามีเครื่องมือที่ทรงพลังล่าสุดทั้งหมดในการกำจัดของพวกเขาเพื่อสร้างสิ่งที่มีประโยชน์โดยไม่ต้องเสียเวลากดปุ่มและ โดยเฉพาะอย่างยิ่งการเสียเงินจ่ายเงินสำหรับการสมัครสมาชิกราคาแพงให้กับซอฟต์แวร์ไม่กี่คนที่ต้องการใช้ต่อไปเนื่องจากข้อ จำกัด ในการใช้งานและความยืดหยุ่น หากคุณมีเวลาไม่กี่นาทีในการอ่านหนังสือเล่มนี้และเรียนรู้สิ่งที่ฉันต้องการสอนคุณหรือพูดคุยกับฉันเกี่ยวกับเป้าหมายของคุณและได้รับคำแนะนำในทิศทางที่ถูกต้องและมีแรงจูงใจในการเรียนรู้ที่จะเขียนโค้ดและเขียนซอฟต์แวร์ของคุณเอง นำหนังสือเล่มนี้กลับบ้านและจัดสรรเวลาสักครู่เพื่อเรียนรู้ที่จะสร้างเว็บแอปพลิเคชันที่มีอิทธิพลมีประสิทธิภาพมีความคล่องตัวและสำคัญต่อไปเว็บไซต์ที่มีอยู่ในตัวคุณและทำสิ่งที่คุณต้องการและตอบสนองความต้องการของผู้ชมของคุณ เกี่ยวกับฉัน: ฉันเป็นนักพัฒนาซอฟต์แวร์ที่มีความกว้างAnge of Experience ใน C/C ++, Java, Python, HTML, CSS และ JavaScript ฉันสร้างเว็บไซต์ที่ผู้คนต้องการใช้ต้องการเยี่ยมชมและแม้กระทั่งติดอยู่กับการใช้เพียงเพื่อเรียนรู้สร้างและฆ่าเวลาและที่สำคัญที่สุดคือฉันขายซอฟต์แวร์ หากคุณมีความคิดว่าคุณต้องการให้เว็บไซต์ดูและฟังก์ชั่นอย่างไรคุณยินดีที่จะสนับสนุนฉันเพื่อที่ฉันจะได้ตอบสนองความต้องการของตัวเองในขณะที่ฉันพบคุณและคุณยินดีที่จะครอบคลุมค่าใช้จ่ายในการเรียกใช้เว็บไซต์ด้วยตัวเอง ฉันจะสร้าง YouTube, Tiktok, Twitter, Google หรือแม้แต่แอพรักษาความปลอดภัยไฮเทคต่อไปเท่านั้นที่คุณสามารถเข้าถึงได้ แทนที่จะพยายามขายเวลาให้คุณฉันพยายามซื้อของคุณ: ฉันต้องการพูดคุยกับคุณในการสร้างแอพ (เว็บไซต์) ด้วยตัวคุณเองด้วยข้อมูลที่มีอยู่แล้วและสอนสิ่งที่คุณต้องเป็นนักพัฒนาซอฟต์แวร์อิสระ ผู้ประกอบการเป็นผู้นำอาชีพที่ประสบความสำเร็จในสาขาใดก็ตามที่คุณต้องการ และให้ฉันชัดเจนการศึกษาที่ฉันให้คุณจะไม่เป็นทางการ คุณสามารถไปโรงเรียนและเรียนรู้ทั้งหมดนี้ด้วยไฟล์การศึกษาของ RMAL หรือแม้แต่อ่านหนังสือเล่มนี้ในโรงเรียนให้เสร็จสิ้นการมอบหมายของคุณและนำข้อตกลงมากมายจากการศึกษาของคุณ แต่ฉันจะไม่ทำให้คุณอยู่ในที่นั่งร้อนแรงและขอให้คุณทำงานที่ได้รับมอบหมายให้เสร็จสมบูรณ์ ฉันไม่ใช่อาจารย์ของคุณคุณสามารถนึกถึงฉันเหมือนเพื่อนที่ต้องการนำทางคุณไปสู่อาชีพที่ขับเคลื่อนด้วยความสำเร็จส่วนตัวของคุณเอง และฉันก็ไม่ได้ขายให้คุณประสบความสำเร็จเช่นกันคุณจะต้องซื้อด้วยเวลาของคุณ การเรียนรู้ที่จะเขียนรหัสมีช่วงการเรียนรู้ที่สูงชันและไม่ง่ายหรือแม้แต่ควรจะเป็น คุณต้องทำงานหนักที่สุดเท่าที่จะทำได้และพยายามต่อไปและล้มเหลวและลองอีกครั้งแม้ว่าคุณจะรู้สึกหงุดหงิดเพื่อเรียนรู้และสร้างแอพด้วยตัวเอง นั่นคือลักษณะของรหัส รหัสดำเนินการโดยคอมไพเลอร์ที่ออกแบบมาเพื่อให้ข้อความแสดงข้อผิดพลาดโปรแกรมเมอร์และสิ่งเหล่านี้จะสอนวิธีการเขียนโค้ดแม้ว่าคุณจะเพียงแค่คัดลอกข้อผิดพลาดลงในเครื่องมือค้นหาของคุณและอ่านตัวอย่างของคนอื่น และฉันต้องบอกว่าคุณไม่จำเป็นต้องรวยมากฉลาดและประสบความสำเร็จรายละเอียดที่มุ่งเน้นหรือจัดระเบียบเพื่อสร้างแอพ คอมพิวเตอร์ดูแลองค์กรนั้นให้คุณ คุณเพียงแค่ต้องอดทนผ่านการทดลองและข้อผิดพลาดรักษาโฟกัสและทำงานอย่างหนักในสิ่งที่คุณทำและคุณจะมีอาชีพที่ประสบความสำเร็จอย่างมากในสิ่งที่คุณทำ ฉันเป็นใคร: ฉันรู้ว่าส่วนสุดท้ายเกี่ยวกับการเรียนรู้มากขึ้นและคุณใช้วิธีจากหนังสือเล่มนี้ ฉันเป็นใครกันแน่? นั่นเป็นคำถามที่ซับซ้อน ฉันไม่ชัดเจนว่าตัวเองเพราะฉันต้องทนทุกข์ทรมานจากเงื่อนไขทางการแพทย์ที่อาจทำให้มันยากสำหรับฉันที่จะเขียนโค้ดหรือเขียนหนังสือเล่มนี้ในบางครั้งในขณะที่นำเสนอความท้าทายเกี่ยวกับปัญหาการขัดเกลาทางสังคมและตัวตนที่ทำให้ชีวิตของฉันยากขึ้นเมื่อพูดถึงการแนะนำตัวเอง . ในระยะสั้นถ้าคุณกำลังอ่านหนังสือเล่มนี้คุณนำมันกลับบ้านเพราะคุณพลิกมันและคิดว่ามันมีประโยชน์หรือแม้ว่าคุณจะอ่านมาไกลขนาดนี้กับคุณ ทุกสิ่งที่คุณทำ ฉันเป็นวิศวกรด้วยตัวเองซอฟต์แวร์นักพัฒนาและนักเรียนและฉันกำลังเขียนหนังสือเล่มนี้สำหรับนักเรียนคนอื่น ๆ ที่ต้องการทำให้ชีวิตของพวกเขาง่ายขึ้นโดยมีคู่มือของซอฟต์แวร์ที่พวกเขาต้องการทำให้ชีวิตของพวกเขาง่ายขึ้นโดยให้ตัวอย่างเพื่อคัดลอกเข้าด้วยกันเหมือนปริศนาขนาดใหญ่ในการทำงาน , มีประโยชน์, มีขนาดใหญ่, ใช้งานได้, ใช้งานได้และมีส่วนร่วมที่สามารถขับเคลื่อนความสำเร็จไม่ว่าจะเป็นธุรกิจ ส่วนใหญ่นี่คือสิ่งที่ฉันทำ: ฉันสร้างแอพเพื่อช่วยตัวเองและคนอื่น ๆ ให้ประสบความสำเร็จ ฉันเป็นนักเขียนเช่นกันถึงแม้ว่านี่จะเป็นสิ่งพิมพ์ครั้งแรกของฉันที่ฉันตั้งใจจะทำให้เสร็จเพื่อนำผลงานของฉันเข้าด้วยกันในเอกสารที่มีประโยชน์และฉันก็เป็นศิลปินเช่นกัน ฉันจะยอมรับสิ่งนี้กับคุณฉันเป็นคนแปลก ฉันไม่สมบูรณ์แบบฉันได้ดำเนินการตามกฎหมายแม้จะนำฉันออกจากวิทยาลัยและมหาวิทยาลัยและออกจากรัฐเพื่อพยายามสร้างชื่อให้ตัวเองด้วยความสำเร็จมากขึ้น ฉันเป็นผู้หญิงตั้งแต่แรกเกิดฉันสวมแต่งหน้าถ่ายรูปตัวเองสวมชุดและเสื้อผ้าสตรีอื่น ๆ และฉันก็ยังคงตระหนักถึงตัวเองในฐานะชายโดยธรรมชาติ ฉันเคยมีปัญหากับคนอื่น ๆ ในอดีตที่นำไปสู่การต่อสู้กับการเขียนและการสร้างเว็บแอปและฉันขอโทษที่ฉันไม่สามารถรับหนังสือเล่มนี้ในมือของคุณได้เร็วขึ้น: คุณต้องการสิ่งนี้ คุณจะต้องอ่านและเขียนโค้ดที่ดูเหมือนของฉันและทำงานเหมือนของฉันและทำสิ่งเดียวกัน แต่ดียิ่งขึ้นเพราะถ้าคุณสามารถซื้อหนังสือเล่มนี้ได้แทนที่จะบดแป้นแป้นพิมพ์ของคุณเหมือนที่ฉันทำเพื่อสร้างหนังสือด้วยตัวเอง สำหรับมันคุณมีทรัพยากรที่คุณต้องประสบความสำเร็จในชีวิตของคุณ ฉันมีปัญหาทุกเรื่องเกี่ยวกับครอบครัวที่เติบโตขึ้นสภาพสุขภาพแพทย์สื่อและกฎหมายและรหัสของฉันสะท้อนให้เห็นถึงการต่อสู้ที่เป็นสตรีและธรรมชาติของผู้หญิงในโลกที่ถูกแบ่งแยกและผิดหวัง อย่างไรก็ตามหนังสือเล่มนี้เป็นสิ่งที่ฉันใส่ใจอย่างลึกซึ้งลูกน้อยพอร์ตโฟลิโอและวิถีชีวิตของฉันดังนั้นฉันขอขอบคุณการพิจารณาของคุณเมื่อคุณนำข้อความกลับบ้านและรูขุมขนอย่างระมัดระวังเพื่อเรียนรู้จากฉัน โปรดจำไว้ว่าฉันไม่สมบูรณ์แบบหนังสือจะมีข้อผิดพลาดการแก้ไขและฉบับใหม่และคุณจะต้องคิดกับสมองเชิงตรรกะของคุณให้ดีที่สุดเท่าที่จะทำได้เพื่อให้ได้ประสบการณ์ที่ประสบความสำเร็จกับงานเขียนของฉัน นอกจากนี้ยังเข้าใจว่าฉันหมายถึงดีสำหรับคุณแม้ว่าคุณจะเผชิญกับความท้าทายเมื่อเขียน คิดเกี่ยวกับสิ่งนี้: เมื่อคุณสามารถเช่าระบบคอมพิวเตอร์เพื่อทำทุกอย่างที่คุณสามารถจินตนาการได้ในพื้นที่ดิจิตอลเก็บข้อมูลทั้งหมดที่คุณพบ #$%! yze และจัดระเบียบและเข้าใจมัน พบปัญหากับข้อมูลที่คุณบริโภคและแม้แต่การเผยแพร่อย่างหลีกเลี่ยงไม่ได้ ฉันบอกคุณเรื่องนี้เพราะฉันพบปัญหาเดียวกัน ใช้หนังสือเล่มนี้ด้วยความเสี่ยงของคุณเองทำงานร่วมกับชุมชนและชุมชนของคุณที่มีให้คุณสร้างซอฟต์แวร์ภายในสภาพแวดล้อมที่ปลอดภัยและอย่านำสิ่งต่าง ๆ ไปใช้เป็นการส่วนตัวเมื่อคุณล้มเหลวหรือประสบความสำเร็จในทางที่ผิด: นั่นคือวิธีที่ฉันได้มาไกลขนาดนี้ และทำไมฉันถึงนำข้อความนี้มาให้คุณและช่วยให้คุณประสบความสำเร็จได้โดยไม่ต้องเบี่ยงเบนไปบนเส้นทางแห่งความบ้าคลั่งที่ทิ้งฉันถูกทำลายฉีกขาดและหลุดพ้นในขณะที่ฉันพบปัญหาปกติที่ทุกคนทำในระดับโลกด้วยระดับโลกของเครือข่ายที่เราจะทำงานอินเทอร์เน็ต คุณอาจไม่คุ้นเคยกับสิ่งที่ฉันเป็นเพียงไม่กี่คำ แต่ฉันขอแนะนำให้คุณอ่านต่อไปคุณจะรู้จักฉันในขณะที่คุณอ่านและเข้าใจฉันต่อไปในขณะที่สร้างโครงการของคุณเองเพื่อทำงานให้เสร็จ จะไม่มีการบ้านกับหนังสือเล่มนี้ตราบใดที่อาจารย์หรืออาจารย์ของคุณไม่ได้มอบหมายให้คุณ แต่ฉันขอแนะนำให้คุณสร้างผลงานโครงการด้วยตัวคุณเองเมื่อคุณอ่านไปพร้อมกับโครงการ Capstone ที่แสดงให้เห็นว่าคุณสามารถทำได้อย่างไร ใช้สิ่งที่คุณได้เรียนรู้ โครงการ Capstone ของฉันเป็นพื้นฐานสำหรับสิ่งที่คุณจะอ่านในหนังสือเล่มนี้เนื่องจากมันรวมรหัสจากโครงการก่อนหน้านี้รหัสที่ฉันได้สร้างและเรียนรู้ที่จะเขียนด้วยมืออย่างเป็นระบบและความคิดและเคล็ดลับที่หลากหลายที่ช่วยฉันได้ ประสบความสำเร็จในจุดที่ฉันสามารถหมุนแอพง่าย ๆ นั่นคือให้ความสำคัญกับรูปลักษณ์และประพฤติตนเหมือนแอพยอดนิยมที่คุณอาจเห็นเพื่อนหรือครอบครัวของคุณใช้บนอินเทอร์เน็ตโฆษณาให้คุณหรือในข่าว หนังสือเล่มนี้คืออะไร: หนังสือเล่มนี้เป็นแบบฝึกหัดโดยตัวอย่าง คุณสามารถค้นหารหัสได้ที่นี่คำแนะนำสำหรับวิธีการเรียนรู้รหัสข้อมูลเกี่ยวกับรหัสการดีบักและการแก้ไขข้อผิดพลาดขั้นตอนการแก้ไขปัญหาคำแนะนำเกี่ยวกับวิธีการสำรองข้อมูลและบันทึกรหัสของคุณ-ปรับใช้ใหม่หากใครทำลายรหัสของคุณ รหัสของคุณสร้างเว็บไซต์เชิงโต้ตอบที่ให้ความบันเทิงมีส่วนร่วมและเสพติดและคุณจะได้รับความรู้สึกว่าฉันเป็นใครทำไมสิ่งนี้ถึงสำคัญและวิธีการวาดภาพตัวเองแอพและภาพลักษณ์ของ บริษัท รวมถึงซอฟต์แวร์ที่คุณสร้าง ในแง่ที่ดีที่สุดที่จะเป็นสิ่งที่น่าสนใจที่สุดเท่าที่จะเป็นไปได้สำหรับผู้ใช้ปลายทางผู้เข้าชมเว็บไซต์ของคุณ ในหนังสือเล่มนี้ฉันจะแสดงตัวอย่างจำนวนมากของการออกแบบซอฟต์แวร์โดยมุ่งเน้นที่เว็บเป็นแพลตฟอร์มและความปลอดภัย เราจะเริ่มต้นประสบการณ์การเรียนรู้ด้วยการสร้างพื้นฐานECT ใช้เชลล์ UNIX พร้อมคุณสมบัติการสำรองข้อมูลและสคริปต์ จากนั้นเราจะตรวจสอบเว็บไซต์บล็อกพื้นฐานอัพเกรดบล็อกของเราด้วยคุณสมบัติภาพถ่ายและวิดีโอรวมถึงใช้คุณสมบัติเหล่านี้เพื่อใช้โซลูชันความปลอดภัยโดยใช้ซอฟต์แวร์ฟรีและรักษาความปลอดภัยเซิร์ฟเวอร์ของเราโดยใช้โมดูลการตรวจสอบความถูกต้องที่สามารถทำได้ (PAM) จากนั้นเราจะตรวจสอบการจัดการและประมวลผลการสำรวจการแก้ไขวิดีโอการบริจาคเสียงการสแกนบาร์โค้ดและการจดจำอักขระแบบออพติคอลท่ามกลางแนวคิดอื่น ๆ ระหว่างวิธีที่เราจะตรวจสอบ API ซึ่งจะช่วยให้เราทำให้ซอฟต์แวร์ของเรามีประโยชน์และปลอดภัยยิ่งขึ้นด้วยตัวเลือกฟรีและชำระเงิน ระหว่างทางเราจะสำรวจความปลอดภัยทางกายภาพและเครื่องมือการต่อสู้เช่นอาวุธปืนและการออกแบบอาวุธและการผลิตรวมถึงการออกแบบบาร์เรลและ Repeater, ป้อมปืนและการออกแบบเสียงพึมพำและหลักการอื่น ๆ ที่เราจะรวมเข้ากับซอฟต์แวร์ของเราในเครือข่ายที่มีอยู่เพื่อปกป้องซอฟต์แวร์ของเรา และแสดงให้เห็นถึงการป้องกันตนเองและการฟื้นฟู เราจะหยุดพักระหว่างทางเพื่อสร้างเกม 2D และ 3Dเครื่องยนต์ ndering และทำงานกับฮาร์ดแวร์ฝังตัวในกรณีศึกษาตัวอย่างของซอฟต์แวร์การเรนเดอร์มิติพื้นฐานและเครื่องนวดอิเล็กทรอนิกส์สั่นสะเทือนในยางซิลิโคนตามลำดับ ระหว่างทางเราจะใช้โซลูชั่นการเรียนรู้ของเครื่องจักรที่มีอยู่แล้วเพื่อให้ซอฟต์แวร์ของเราปลอดภัยขึ้น นอกจากนี้เรายังจะใช้เครื่องมือสต็อกสำหรับเว็บเพื่อปรับปรุงและรักษาความปลอดภัยกระบวนการ หนังสือเล่มนี้เป็นแนวทางสู่ความสำเร็จของคุณในการสร้างเว็บแอปพลิเคชันและรวมเข้ากับเครือ...
การเรียนรู้เชิงลึกและการรักษาความปลอดภัยบนเว็บเชิงปฏิบัติตามตัวอย่าง

การเรียนรู้อย่างลึกซึ้งบนเว็บที่ใช้งานได้จริงโดยตัวอย่าง ฉบับที่สาม Charlotte Harper 3 กรกฎาคม 2567 คำนำ: ข้อควรพิจารณาด้านความปลอดภัยในการสร้างซอฟต์แวร์สำหรับเว็บเป็นส่วนสำคัญของแผนและการดำเนินการของนักพัฒนาเว็บใด ๆ ในขณะที่วิศวกรรมต้นแบบที่เชื่อถือได้มั่นคงและมีประโยชน์สำหรับวัตถุประสงค์ในทางปฏิบัติ มาร์กอัป DOM (เอกสารมาร์กอัป) โดยมีการใช้งานของ HTML, JavaScript และ CSS รวมถึงซอฟต์แวร์แบ็กเอนด์ที่ใช้ Python, C/C ++, Java และ Bash ทำให้นักพัฒนาเว็บมีอิสระและพลังในการสร้างโครงการที่หลากหลาย ความคิดสร้างสรรค์ให้ความสะดวกในการใช้งานและฟังก์ชั่นการพรรณนาถึงความอ่อนน้อมถ่อมตนและตัวละครและให้ความสะดวกในการใช้งานรวมถึงความสะดวกสบายและบริการที่สำคัญที่น่าสนใจสำหรับ Joe โดยเฉลี่ยผู้ใช้ปลายทางที่ต้องการฆ่าเวลาหรือทำอะไรบางอย่างบนอินเทอร์เน็ต มักจะอยู่บนอุปกรณ์สมาร์ทโฟนหน้าจอสัมผัส คนส่วนใหญ่ไม่รู้ด้วยซ้ำว่าจะเริ่มต้นตรงไหนเมื่อพวกเขาต้องการสร้างเว็บไซต์จากเกาพวกเขามักจะเริ่มต้นในเว็บไซต์ของบุคคลอื่นและสร้างสิ่งที่ จำกัด ในการใช้งานฟังก์ชั่นความน่าเชื่อถือการใช้งานง่ายและความคิดสร้างสรรค์โดยเฉพาะอย่างยิ่งเมื่อพวกเขามีเครื่องมือที่ทรงพลังล่าสุดทั้งหมดในการกำจัดเพื่อสร้างสิ่งที่มีประโยชน์โดยไม่ต้องเสียเวลากดปุ่ม และโดยเฉพาะอย่างยิ่งการเสียเงินจ่ายเงินสำหรับการสมัครสมาชิกราคาแพงให้กับซอฟต์แวร์ไม่กี่คนที่ต้องการใช้ต่อไปเนื่องจากข้อ จำกัด ในการใช้งานและความยืดหยุ่น หากคุณมีเวลาไม่กี่นาทีในการอ่านหนังสือเล่มนี้และเรียนรู้สิ่งที่ฉันต้องการสอนคุณหรือพูดคุยกับฉันเกี่ยวกับเป้าหมายของคุณและได้รับคำแนะนำในทิศทางที่ถูกต้องและมีแรงจูงใจในการเรียนรู้ที่จะเขียนโค้ดและเขียนซอฟต์แวร์ของคุณเอง นำหนังสือเล่มนี้กลับบ้านและจัดสรรเวลาสักครู่เพื่อเรียนรู้ที่จะสร้างเว็บแอปพลิเคชันที่มีอิทธิพลมีประสิทธิภาพมีความคล่องตัวและสำคัญต่อไปเว็บไซต์ที่มีอยู่ในตัวคุณและทำสิ่งที่คุณต้องการและตอบสนองความต้องการของผู้ชมของคุณ เกี่ยวกับฉัน: ฉันเป็นนักพัฒนาซอฟต์แวร์ด้วยช่วงของประสบการณ์ใน C/C ++, Java, Python, HTML, CSS และ JavaScript ฉันสร้างเว็บไซต์ที่ผู้คนต้องการใช้ต้องการเยี่ยมชมและแม้กระทั่งติดอยู่กับการใช้เพียงเพื่อเรียนรู้สร้างและฆ่าเวลาและที่สำคัญที่สุดคือฉันขายซอฟต์แวร์ หากคุณมีความคิดว่าคุณต้องการให้เว็บไซต์ดูและฟังก์ชั่นอย่างไรคุณยินดีที่จะสนับสนุนฉันเพื่อที่ฉันจะได้ตอบสนองความต้องการของตัวเองในขณะที่ฉันพบคุณและคุณยินดีที่จะครอบคลุมค่าใช้จ่ายในการเรียกใช้เว็บไซต์ด้วยตัวเอง ฉันจะสร้าง YouTube, Tiktok, Twitter, Google หรือแม้แต่แอพรักษาความปลอดภัยไฮเทคต่อไปเท่านั้นที่คุณสามารถเข้าถึงได้ แทนที่จะพยายามขายเวลาให้คุณฉันพยายามซื้อของคุณ: ฉันต้องการพูดคุยกับคุณในการสร้างแอพ (เว็บไซต์) ด้วยตัวคุณเองด้วยข้อมูลที่มีอยู่แล้วและสอนสิ่งที่คุณต้องเป็นนักพัฒนาซอฟต์แวร์อิสระ ผู้ประกอบการเป็นผู้นำอาชีพที่ประสบความสำเร็จในสาขาใดก็ตามที่คุณต้องการ และให้ฉันชัดเจนการศึกษาที่ฉันให้คุณจะไม่เป็นทางการ คุณสามารถไปโรงเรียนและเรียนรู้ทั้งหมดนี้ด้วยไฟล์การศึกษาอย่างเป็นทางการหรือแม้กระทั่งอ่านหนังสือเล่มนี้ในโรงเรียนให้เสร็จสิ้นการมอบหมายของคุณและนำการศึกษาของคุณออกไปอย่างมาก แต่ฉันจะไม่ทำให้คุณอยู่ในที่นั่งร้อนแรงและขอให้คุณทำงานที่ได้รับมอบหมายให้เสร็จสมบูรณ์ ฉันไม่ใช่อาจารย์ของคุณคุณสามารถนึกถึงฉันเหมือนเพื่อนที่ต้องการนำทางคุณไปสู่อาชีพที่ขับเคลื่อนด้วยความสำเร็จส่วนตัวของคุณเอง และฉันก็ไม่ได้ขายให้คุณประสบความสำเร็จเช่นกันคุณจะต้องซื้อด้วยเวลาของคุณ การเรียนรู้ที่จะเขียนรหัสมีช่วงการเรียนรู้ที่สูงชันและไม่ง่ายหรือแม้แต่ควรจะเป็น คุณต้องทำงานหนักที่สุดเท่าที่จะทำได้และพยายามต่อไปและล้มเหลวและลองอีกครั้งแม้ว่าคุณจะรู้สึกหงุดหงิดเพื่อเรียนรู้และสร้างแอพด้วยตัวเอง นั่นคือลักษณะของรหัส รหัสดำเนินการโดยคอมไพเลอร์ที่ออกแบบมาเพื่อให้ข้อความแสดงข้อผิดพลาดโปรแกรมเมอร์และสิ่งเหล่านี้จะสอนวิธีการเขียนโค้ดแม้ว่าคุณจะเพียงแค่คัดลอกข้อผิดพลาดลงในเครื่องมือค้นหาของคุณและอ่านตัวอย่างของคนอื่น และฉันต้องบอกว่าคุณไม่จำเป็นต้องรวยมากฉลาดEssful หรือรายละเอียดที่มุ่งเน้นหรือจัดระเบียบเพื่อสร้างแอพ คอมพิวเตอร์ดูแลองค์กรนั้นให้คุณ คุณเพียงแค่ต้องอดทนผ่านการทดลองและข้อผิดพลาดรักษาโฟกัสและทำงานอย่างหนักในสิ่งที่คุณทำและคุณจะมีอาชีพที่ประสบความสำเร็จอย่างมากในสิ่งที่คุณทำ ฉันเป็นใคร: ฉันรู้ว่าส่วนสุดท้ายเกี่ยวกับการเรียนรู้มากขึ้นและคุณใช้วิธีจากหนังสือเล่มนี้ ฉันเป็นใครกันแน่? นั่นเป็นคำถามที่ซับซ้อน ฉันไม่ชัดเจนว่าตัวเองเพราะฉันต้องทนทุกข์ทรมานจากเงื่อนไขทางการแพทย์ที่อาจทำให้มันยากสำหรับฉันที่จะเขียนโค้ดหรือเขียนหนังสือเล่มนี้ในบางครั้งในขณะที่นำเสนอความท้าทายเกี่ยวกับปัญหาการขัดเกลาทางสังคมและตัวตนที่ทำให้ชีวิตของฉันยากขึ้นเมื่อพูดถึงการแนะนำตัวเอง . ในระยะสั้นถ้าคุณกำลังอ่านหนังสือเล่มนี้คุณนำมันกลับบ้านเพราะคุณพลิกมันและคิดว่ามันมีประโยชน์หรือแม้ว่าคุณจะอ่านมาไกลขนาดนี้กับคุณ ทุกสิ่งที่คุณทำ ฉันเป็นวิศวกรด้วยตัวเองนักพัฒนาและนักเรียนและฉันกำลังเขียนหนังสือเล่มนี้สำหรับนักเรียนคนอื่น ๆ ที่ต้องการทำให้ชีวิตของพวกเขาง่ายขึ้นโดยมีคู่มือของซอฟต์แวร์ที่พวกเขาต้องการทำให้ชีวิตของพวกเขาง่ายขึ้นโดยให้ตัวอย่างเพื่อคัดลอกเข้าด้วยกันเหมือนปริศนาขนาดใหญ่ในการทำงาน , มีประโยชน์, มีขนาดใหญ่, ใช้งานได้, ใช้งานได้และมีส่วนร่วมที่สามารถขับเคลื่อนความสำเร็จไม่ว่าจะเป็นธุรกิจ ส่วนใหญ่นี่คือสิ่งที่ฉันทำ: ฉันสร้างแอพเพื่อช่วยตัวเองและคนอื่น ๆ ให้ประสบความสำเร็จ ฉันเป็นนักเขียนเช่นกันถึงแม้ว่านี่จะเป็นสิ่งพิมพ์ครั้งแรกของฉันที่ฉันตั้งใจจะทำให้เสร็จเพื่อนำผลงานของฉันเข้าด้วยกันในเอกสารที่มีประโยชน์และฉันก็เป็นศิลปินเช่นกัน ฉันจะยอมรับสิ่งนี้กับคุณฉันเป็นคนแปลก ฉันไม่สมบูรณ์แบบฉันได้ดำเนินการตามกฎหมายแม้จะนำฉันออกจากวิทยาลัยและมหาวิทยาลัยและออกจากรัฐเพื่อพยายามสร้างชื่อให้ตัวเองด้วยความสำเร็จมากขึ้น ฉันเป็นผู้หญิงตั้งแต่แรกเกิดฉันสวมแต่งหน้าถ่ายรูปตัวเองสวมชุดและเสื้อผ้าสตรีอื่น ๆ และฉันก็ยังคงตระหนักถึงตัวเองในฐานะหญิงโดยธรรมชาติ ฉันเคยมีปัญหากับคนอื่น ๆ ในอดีตที่นำไปสู่การต่อสู้กับการเขียนและการสร้างเว็บแอปและฉันขอโทษที่ฉันไม่สามารถรับหนังสือเล่มนี้ในมือของคุณได้เร็วขึ้น: คุณต้องการสิ่งนี้ คุณจะต้องอ่านและเขียนโค้ดที่ดูเหมือนของฉันและทำงานเหมือนของฉันและทำสิ่งเดียวกัน แต่ดียิ่งขึ้นเพราะถ้าคุณสามารถซื้อหนังสือเล่มนี้ได้แทนที่จะบดแป้นแป้นพิมพ์ของคุณเหมือนที่ฉันทำเพื่อสร้างหนังสือด้วยตัวเอง สำหรับมันคุณมีทรัพยากรที่คุณต้องประสบความสำเร็จในชีวิตของคุณ ฉันมีปัญหาทุกเรื่องเกี่ยวกับครอบครัวที่เติบโตขึ้นสภาพสุขภาพแพทย์สื่อและกฎหมายและรหัสของฉันสะท้อนให้เห็นถึงการต่อสู้ที่เป็นสตรีและธรรมชาติของผู้หญิงในโลกที่ถูกแบ่งแยกและผิดหวัง อย่างไรก็ตามหนังสือเล่มนี้เป็นสิ่งที่ฉันใส่ใจอย่างลึกซึ้งลูกน้อยพอร์ตโฟลิโอและวิถีชีวิตของฉันดังนั้นฉันขอขอบคุณการพิจารณาของคุณเมื่อคุณนำข้อความกลับบ้านและรูขุมขนอย่างระมัดระวังเพื่อเรียนรู้จากฉัน โปรดจำไว้ว่าฉันไม่ได้ect หนังสือเล่มนี้จะมีข้อผิดพลาดการแก้ไขและฉบับใหม่และคุณจะต้องคิดกับสมองเชิงตรรกะของคุณให้ดีที่สุดเท่าที่จะทำได้เพื่อที่จะได้รับประสบการณ์ที่ประสบความสำเร็จกับการเขียนของฉัน นอกจากนี้ยังเข้าใจว่าฉันหมายถึงดีสำหรับคุณแม้ว่าคุณจะเผชิญกับความท้าทายเมื่อเขียน คิดเกี่ยวกับสิ่งนี้: เมื่อคุณสามารถเช่าระบบคอมพิวเตอร์เพื่อทำทุกอย่างที่คุณสามารถจินตนาการได้ในพื้นที่ดิจิตอลเก็บข้อมูลทั้งหมดที่คุณพบ #$%! yze และจัดระเบียบและเข้าใจมัน พบปัญหากับข้อมูลที่คุณบริโภคและแม้แต่การเผยแพร่อย่างหลีกเลี่ยงไม่ได้ ฉันบอกคุณเรื่องนี้เพราะฉันพบปัญหาเดียวกัน ใช้หนังสือเล่มนี้ด้วยความเสี่ยงของคุณเองทำงานร่วมกับชุมชนและชุมชนของคุณที่มีให้คุณสร้างซอฟต์แวร์ภายในสภาพแวดล้อมที่ปลอดภัยและอย่านำสิ่งต่าง ๆ ไปใช้เป็นการส่วนตัวเมื่อคุณล้มเหลวหรือประสบความสำเร็จในทางที่ผิด: นั่นคือวิธีที่ฉันได้มาไกลขนาดนี้ และทำไมฉันถึงนำข้อความนี้มาให้คุณและช่วยให้คุณประสบความสำเร็จได้โดยไม่ต้องเบี่ยงเบนไปบนเส้นทางแห่งความบ้าคลั่งAves Me Ruined, ฉีกขาดและหลุดพ้นในขณะที่ฉันพบปัญหาปกติที่ทุกคนทำในระดับโลกด้วยระดับโลกของเครือข่ายที่เราจะทำงานอินเทอร์เน็ต คุณอาจไม่คุ้นเคยกับสิ่งที่ฉันเป็นเพียงไม่กี่คำ แต่ฉันขอแนะนำให้คุณอ่านต่อไปคุณจะรู้จักฉันในขณะที่คุณอ่านและเข้าใจฉันต่อไปในขณะที่สร้างโครงการของคุณเองเพื่อทำงานให้เสร็จ จะไม่มีการบ้านกับหนังสือเล่มนี้ตราบใดที่อาจารย์หรืออาจารย์ของคุณไม่ได้มอบหมายให้คุณ แต่ฉันขอแนะนำให้คุณสร้างผลงานโครงการด้วยตัวคุณเองเมื่อคุณอ่านไปพร้อมกับโครงการ Capstone ที่แสดงให้เห็นว่าคุณสามารถทำได้อย่างไร ใช้สิ่งที่คุณได้เรียนรู้ โครงการ Capstone ของฉันเป็นพื้นฐานสำหรับสิ่งที่คุณจะอ่านในหนังสือเล่มนี้เนื่องจากมันรวมรหัสจากโครงการก่อนหน้านี้รหัสที่ฉันได้สร้างและเรียนรู้ที่จะเขียนด้วยมืออย่างเป็นระบบและความคิดและเคล็ดลับที่หลากหลายที่ช่วยฉันได้ ประสบความสำเร็จในจุดที่ฉันสามารถหมุนแอพง่ายๆได้โดดเด่นอย่างเต็มที่และรูปลักษณ์และประพฤติตนเหมือนแอพยอดนิยมที่คุณอาจเห็นเพื่อนหรือครอบครัวของคุณใช้บนอินเทอร์เน็ตโฆษณาให้คุณหรือในข่าว หนังสือเล่มนี้คืออะไร: หนังสือเล่มนี้เป็นแบบฝึกหัดโดยตัวอย่าง คุณสามารถค้นหารหัสได้ที่นี่คำแนะนำสำหรับวิธีการเรียนรู้รหัสข้อมูลเกี่ยวกับรหัสการดีบักและการแก้ไขข้อผิดพลาดขั้นตอนการแก้ไขปัญหาคำแนะนำเกี่ยวกับวิธีการสำรองข้อมูลและบันทึกรหัสของคุณ-ปรับใช้ใหม่หากใครทำลายรหัสของคุณ รหัสของคุณสร้างเว็บไซต์เชิงโต้ตอบที่ให้ความบันเทิงมีส่วนร่วมและเสพติดและคุณจะได้รับความรู้สึกว่าฉันเป็นใครทำไมสิ่งนี้ถึงสำคัญและวิธีการวาดภาพตัวเองแอพและภาพลักษณ์ของ บริษัท รวมถึงซอฟต์แวร์ที่คุณสร้าง ในแง่ที่ดีที่สุดที่จะเป็นสิ่งที่น่าสนใจที่สุดเท่าที่จะเป็นไปได้สำหรับผู้ใช้ปลายทางผู้เข้าชมเว็บไซต์ของคุณ ในหนังสือเล่มนี้ฉันจะแสดงตัวอย่างจำนวนมากของการออกแบบซอฟต์แวร์โดยมุ่งเน้นที่เว็บเป็นแพลตฟอร์มและความปลอดภัย เราจะเริ่มต้นประสบการณ์การเรียนรู้ด้วยการสร้างพื้นฐานOject ใช้เชลล์ UNIX พร้อมคุณสมบัติการสำรองข้อมูลและสคริปต์ จากนั้นเราจะตรวจสอบเว็บไซต์บล็อกพื้นฐานอัพเกรดบล็อกของเราด้วยคุณสมบัติภาพถ่ายและวิดีโอรวมถึงใช้คุณสมบัติเหล่านี้เพื่อใช้โซลูชันความปลอดภัยโดยใช้ซอฟต์แวร์ฟรีและรักษาความปลอดภัยเซิร์ฟเวอร์ของเราโดยใช้โมดูลการตรวจสอบความถูกต้องที่สามารถทำได้ (PAM) จากนั้นเราจะตรวจสอบการจัดการและประมวลผลการสำรวจการแก้ไขวิดีโอการบริจาคเสียงการสแกนบาร์โค้ดและการจดจำอักขระแบบออพติคอลท่ามกลางแนวคิดอื่น ๆ ระหว่างวิธีที่เราจะตรวจสอบ API ซึ่งจะช่วยให้เราทำให้ซอฟต์แวร์ของเรามีประโยชน์และปลอดภัยยิ่งขึ้นด้วยตัวเลือกฟรีและชำระเงิน ระหว่างทางเราจะสำรวจความปลอดภัยทางกายภาพและเครื่องมือการต่อสู้เช่นอาวุธปืนและการออกแบบอาวุธและการผลิตรวมถึงการออกแบบบาร์เรลและ Repeater, ป้อมปืนและการออกแบบเสียงพึมพำและหลักการอื่น ๆ ที่เราจะรวมเข้ากับซอฟต์แวร์ของเราในเครือข่ายที่มีอยู่เพื่อปกป้องซอฟต์แวร์ของเรา และแสดงให้เห็นถึงการป้องกันตนเองและการฟื้นฟู เราจะหยุดพักระหว่างทางเพื่อสร้างเกม 2D และ 3DEndering Engines และทำงานกับฮาร์ดแวร์แบบฝังตัวในกรณีศึกษาตัวอย่างของซอฟต์แวร์การเรนเดอร์มิติพื้นฐานและเครื่องนวดอิเล็กทรอนิกส์ที่สั่นสะเทือนในยางซิลิโคนตามลำดับ ระหว่างทางเราจะใช้โซลูชั่นการเรียนรู้ของเครื่องจักรที่มีอยู่แล้วเพื่อให้ซอฟต์แวร์ของเราปลอดภัยขึ้น นอกจากนี้เรายังจะใช้เครื่องมือสต็อกสำหรับเว็บเพื่อปรับปรุงและรักษาความปลอดภัยกระบวนการ หนังสือเล่มนี้เป็นแนวทางสู่ความสำเร็จของคุณในการสร้างเว็บแอปพลิเคชันและรวมเข้ากับเครือข่ายมืออาชีพของคอมพิวเตอร์และระบบกลไกการฝังตัวและคำแนะนำในการสร้างซอฟต์แวร์และฮาร์ดแวร์ที่ฝังโดยไม่มีความรู้พื้นฐานหรือประสบการณ์ก่อนหน้านี้ หนังสือเล่มนี้ไม่ใช่อะไร: หากคุณต้องการมีเว็บไซต์จริงๆคุณสามารถตั้งค่าร้านค้าง่ายๆและขายสิ่งที่คุณต้องการโพสต์บล็อกโพสต์รูปภาพหรือวิดีโอหรืออย่างอื่นโดยไม่ต้องเขียนรหัสบรรทัดเดียว หนังสือเล่มนี้ไม่ใช่อย่างนั้น หนังสือเล่มนี้จะสอนวิธีสร้างซอฟต์แวร์ที่มีประโยชน์มากขึ้นอย่างเต็มที่โดดเด่นใช้งานได้และปลอดภัยกว่าซอฟต์แวร์ใด ๆ ที่คุณสามารถหาได้เพราะมันปรับใช้ซอฟต์แวร์ล่าสุดที่ยังคงเป็นต้นแบบอาจมีราคาแพงในการทำงานในระดับ บริษัท เก่าที่ดำเนินงานอยู่ ทำเงินให้กับคนที่ไม่ได้ทำอะไรเลย หากคุณติดตามหนังสือเล่มนี้อย่างใกล้ชิดคุณจะต้องเขียนโค้ดรหัสวิจัยสร้างแอพของคุณเองและคุณจะทำเงินจากสิ่งที่คุณทำ ฉันจะทำเงินจากหนังสือเล่มนี้แม้ในระยะแรกเพราะมันมีข้อมูลที่ผู้คนต้องการและต้องการอ่านและกำลังซื้ออยู่แล้วเมื่อพวกเขาซื้อหรือใช้แอพของฉัน หนังสือเล่มนี้จะไม่สร้างแอพสำหรับคุณ แต่มันจะชี้ให้คุณไปในทิศทางที่ถูกต้องและแขนคุณด้วยเครื่องมือที่คุณต้องการและทักษะและเคล็ดลับที่จะช่วยให้คุณประสบความสำเร็จในการสร้างซอฟต์แวร์สำหรับเว็บทุกสาย รหัสคุณจะต้องเขียนเป็นตัวอย่างพร้อมที่จะรวมเข้าด้วยกันเป็นซอฟต์แวร์ที่คุณและผู้สนับสนุนแขกผู้เข้าพักลูกค้าRiends, ครอบครัว, ผู้เยี่ยมชม, ผู้รับเหมาและผู้คนในอินเทอร์เน็ตต้องการใช้และสนับสนุน สิ่งที่คุณจะเรียนรู้: หนังสือเล่มนี้จะสอนวิธีการสร้างและขายซอฟต์แวร์การใช้งานจริงซอฟต์แวร์ที่มีประโยชน์การบันทึกสื่อคุณสมบัติด้านความปลอดภัยเช่นการจดจำใบหน้าการสแกนบาร์โค้ดโซนที่อ่านได้ของเครื่องจักร API เว็บเพื่อตรวจสอบสิทธิ์บันทึกและแสดงวิดีโอและภาพถ่ายและแลกเปลี่ยนข้อความเช่นบลูทู ธ และการสื่อสารใกล้สนาม (NFC) หนังสือเล่มนี้จะสอนวิธีการใช้คอมพิวเตอร์เครือข่ายโดยเน้นไปที่ Debian Linux วิธีการสร้างรหัส Bash เพื่อทำการติดตั้งและสำรองซอฟต์แวร์ของคุณด้วยสายลมอัตโนมัติที่ไร้รอยต่อวิธีการสร้างรหัส Python เป็นแบ็กเอนด์เพื่อเสิร์ฟข้อความแบบไดนามิกสไตล์สไตล์ สิ่งต่าง ๆ ใช้สไตล์ CSS กับ Bootstrap เปิดใช้งานการเข้าสู่ระบบของผู้ใช้และการโต้ตอบผ่านอุปกรณ์เครือข่ายสร้างสื่อแบบโต้ตอบและเครือข่ายด้วยเว็บไซต์อื่น ๆRansactions เพื่อให้ซอฟต์แวร์ของคุณปลอดภัยการประมวลผลการชำระเงินการซื้อขาย cryptocurrency งานอะซิงโครนัสและอื่น ๆ คุณจะได้เรียนรู้วิธีการสร้างอุปกรณ์บลูทู ธ ของคุณเองด้วยแบตเตอรี่เครื่องชาร์จไมโครคอนโทรลเลอร์วงจรมอเตอร์และเซ็นเซอร์โดยใช้บัดกรีลวดและ 3D ที่พิมพ์และวัสดุหล่อ ฉันจะแสดงให้เห็นถึงหลักการออกแบบ 3 มิติที่นำไปใช้กับการผลิตและเครื่องมือเสริมและการทำตายดังนั้นคุณสามารถผลิตอุปกรณ์ฝังตัวของคุณเองด้วยแบตเตอรี่ในตัวเครื่องชาร์จวงจรอิเล็กทรอนิกส์และเอาต์พุตการทำงาน และสร้างเครือข่ายด้วยบลูทู ธ และเว็บ โดยเฉพาะเราจะตรวจสอบกรณีศึกษาสองกรณีการนวดที่สั่นสะเทือนและอาวุธปืนโฮมเมดทั้งสองโปรแกรมใน OpenSCAD ซึ่งมีให้เป็นอินเตอร์เฟสกราฟิกหรือยูทิลิตี้บรรทัดคำสั่งและสามารถรวมเข้ากับเว็บเพื่อผลลัพธ์ที่รวดเร็วยิ่งขึ้น คุณจะได้เรียนรู้วิธีการสร้างและปรับใช้เว็บไซต์จากพื้นดินโดยไม่มีประสบการณ์มาก่อนทำให้สามารถใช้งานได้ปลอดภัยสวยงามมีประโยชน์และมากที่สุดใช้งานได้จริง คุณจะได้เรียนรู้วิธีการใช้การเรียนรู้ของเครื่องและวิสัยทัศน์คอมพิวเตอร์เพื่อให้ไซต์ปลอดภัยและใช้งานได้จริงบันทึกวิดีโอและเสียงจากเว็บไซต์ของคุณบริจาคเสียงของคุณทำเพลงและปรับเสียงเพื่อสร้างตัวอย่างที่มีประโยชน์และวิธีการทำลายเสียงรบกวนโดย การใช้ประโยชน์จากเว็บไซต์อื่น ๆ เพื่อสร้างเครือข่ายที่ดีที่สุดของเว็บไซต์ที่คุณสามารถเชื่อมโยงโดยตรงกับคุณเพื่อแบ่งปันข้อมูลที่เป็นประโยชน์ทั้งหมดที่คุณมีให้และที่สำคัญยิ่งกว่านำผู้คนไปยังซอฟต์แวร์และธุรกิจของคุณ หนังสือเล่มนี้จะเน้นไปที่สื่อการรักษาความปลอดภัยและการเรียนรู้ของเครื่องซึ่งเป็นองค์ประกอบสำคัญสามประการที่จะช่วยให้คุณสร้างซอฟต์แวร์ที่มีประโยชน์สำหรับเว็บโดยการมีส่วนร่วมของผู้ใช้ที่เหมาะสม จับมือและมีส่วนร่วมในขณะที่ยังอัตโนมัติและแข็งแรง หนังสือเล่มนี้สอน UNIX, Debian (Ubuntu) โดยเฉพาะ, Bash Shell, Python, HTML, CSS, JavaScript และแพ็คเกจซอฟต์แวร์ที่มีประโยชน์จำนวนหนึ่งสำหรับn ชอบคำขอรวมถึงซอฟต์แวร์ Bash ที่มีประโยชน์เช่น Git และ FFMPEG ฉันจะสอนวิธีการแลกเปลี่ยน cryptocurrency โดยอัตโนมัติและรับการชำระเงินใน cryptocurrency หรือจากบัตรเดบิตปกติในขณะที่แม้กระทั่งจ่ายส่วนแบ่งรายได้ของผู้เยี่ยมชมของคุณหากคุณเลือกที่จะทำเช่นนั้น ฉันจะสอนวิธีสร้างรายได้จากเว็บไซต์ของคุณผ่านการโฆษณาเช่นกันวิธีการเตรียมแอพสำหรับเครื่องมือค้นหาและทำให้เร็วจัดอันดับในการจัดอันดับแรกสำหรับสิ่งที่ลูกค้าของคุณจะค้นหาเพื่อค้นหาคุณ ค้นหาได้มากที่สุด ฉันจะสอนวิธีการขายซอฟต์แวร์โฆษณาดึงดูดลูกค้าที่มองหาบริการของคุณและสร้างชื่อให้ตัวเองบนอินเทอร์เน็ตผ่านทางลู่ทางที่มีอยู่แล้วมีราคาไม่แพงและทำงานได้ดี ฉันจะสอนวิธีบันทึกข้อมูลของคุณในคอมพิวเตอร์คลาวด์ที่ทำงานให้คุณและบันทึกข้อมูลของคุณอย่างถูกต้องวิธีการวางแผนและสร้างเว็บไซต์ที่ทำในสิ่งที่ผู้ใช้ต้องการและสิ่งที่คุณต้องการและวิธีการให้ผู้ใช้ของคุณมีส่วนร่วมโดยไซต์ของคุณแตะบนโทรศัพท์ด้วยการแจ้งเตือนอีเมลข้อความข้อความโทรศัพท์และช่องทางอื่น ๆ ที่จะนำผู้ใช้ของคุณกลับไปที่เว็บไซต์ของคุณตามการคลิกปุ่มที่ปลอดภัยสำหรับคุณเท่านั้น หนังสือเล่มนี้จะมุ่งเน้นไปที่การปฏิบัติจริงของการเผยแพร่และแจกจ่ายสื่อในจำนวนมากตั้งแต่ข้อความไปจนถึงภาพถ่ายไปจนถึงวิดีโอไปจนถึงเสียงสร้างความประทับใจที่ดีต่อผู้ใช้ปลายทาง (ลูกค้าของคุณ) และขายตัวเองในแบบที่คุณทำเพื่อสร้าง เว็บไซต์แอพที่เป็นตัวแทนของคุณและคุณเท่านั้นและทำให้คุณซอฟต์แวร์และ บริษัท ของคุณดูดีในวิธีที่ดีที่สุดเท่าที่จะเป็นไปได้ นอกจากนี้คุณยังจะได้เรียนรู้เคล็ดลับและกลเม็ดเล็กน้อยจากฉันจากเคล็ดลับการเข้ารหัสโต๊ะเครื่องแป้งที่ใช้งานได้จริงเช่นการแต่งหน้าและการถ่ายภาพการสร้างแบบจำลองและการแสดงและอื่น ๆ ซึ่งจะเป็นสิ่งสำคัญสำหรับการวาดภาพตัวเองและ บริษัท ของคุณ สำหรับคุณในขณะที่แจกจ่ายเนื้อหาให้มากที่สุดเท่าที่คุณต้องการข้ามความสมดุลของแพลตฟอร์มเพื่อนำมาซึ่งE เพื่อบรรลุผลโดยไม่ต้องใช้ความพยายามงานหรือเงินมากกว่าที่จำเป็น หนังสือเล่มนี้เรียกว่า วัตถุประสงค์ในทางปฏิบัติที่ระบุไว้ในข้อความ ส่วนประกอบการเรียนรู้ของข้อความนี้ยังครอบคลุมการเรียนรู้ของเครื่องรหัสที่ฉันจะแสดงวิธีการเรียกใช้สำหรับเว็บที่จะจัดการกับการมองเห็นคอมพิวเตอร์การจดจำใบหน้าภาพและการปรับวิดีโอการปรับปรุงภาพการปรับปรุงความละเอียดคำบรรยายภาพและงานอื่น ๆ เช่น ตัวชี้วัดการทำนายที่มาจากภาพเช่นลักษณะของภาพเป็นภาพที่ถูกถ่ายทอดคอมพิวเตอร์จริงหรือสำเนาออปติคัล (ภาพถ่ายของภาพหรือภาพถ่ายที่พิมพ์) การเรียนรู้ของเครื่องมีความสำคัญมากเมื่อพูดถึงความปลอดภัยของเว็บและความปลอดภัยของซอฟต์แวร์เพราะสามารถเตรียมงานที่เป็นไปไม่ได้ คอมพิวเตอร์ของคุณเข้าสู่ระบบด้วยรหัสผ่าน แต่อาจปลอดภัยกว่าที่จะใช้ถ้ามันเข้าสู่ระบบด้วยใบหน้าของคุณ คุณสามารถทำให้คอมพิวเตอร์เซิร์ฟเวอร์ปลอดภัยนี้คอมพิวเตอร์ที่ปกติจะขอชื่อผู้ใช้และรหัสผ่านและเข้าสู่ระบบคุณอาจมีโทเค็นยืนยันสำหรับการเข้าสู่ระบบใหม่หรือที่อยู่ IP ใหม่ แต่ถ้าคุณสร้างขนาดใหญ่ ใช้ซอฟต์แวร์ที่มีความปลอดภัยพื้นฐานและมีประสิทธิภาพซึ่งอาจเพียงพอ การผูกซอฟต์แวร์ของคุณอย่างใกล้ชิดกับซอฟต์แวร์ของคนอื่นเช่นบริการอีเมลหรือบริการข้อความไม่เพียงพอที่จะทำให้ซอฟต์แวร์ของคุณปลอดภัยหรือทุกคน (ไซต์ใด ๆ ที่คุณใช้) ทุกคนที่สร้างซอฟต์แวร์ที่มีความปลอดภัยอย่างไร้ที่ติจะมีความรู้สึกว่าสิ่งนี้มีความหมายอย่างไร ซอฟต์แวร์ไม่ปลอดภัยโดยเนื้อแท้เนื่องจากอุปกรณ์และบัญชีที่เราใช้ในการเข้าถึงมันไม่ได้อยู่ในการกำจัดของเราเสมอไปพวกเขาอาจอยู่ในมือของใครก็ตามที่มีเจตนาร้ายสำหรับซอฟต์แวร์และอาจเสี่ยงต่อซอฟต์แวร์ นี่คือสิ่งที่สำคัญของหนังสือเล่มนี้ คอมพิวเตอร์เครือข่ายเป็นค่าเริ่มต้นปลอดภัยด้วยโทเค็นคีย์ยาวที่เรียกว่าและ SSH หรือ Secure Shell Key และมีความปลอดภัยที่ดีที่สุดด้วยเว็บเซิร์ฟเวอร์เนื่องจากเว็บเซิร์ฟเวอร์ให้การเข้าถึงแบบเปิดรวมถึงเครื่องมือรักษาความปลอดภัยสถานะของศิลปะที่ทำงานบนเซิร์ฟเวอร์เอง เว็บเซิร์ฟเวอร์สามารถเข้าถึงเว็บเบราว์เซอร์ของผู้ใช้ซึ่งเป็นส่วนที่ทรงพลังที่สุดของอุปกรณ์ของผู้ใช้เนื่องจากเป็นสถานที่ที่ผู้ใช้สามารถเข้าถึงซอฟต์แวร์เครือข่าย ชุดเครื่องมือนี้สามารถแสดงข้อความหน้าเว็บที่คุณเห็นและยังสามารถบันทึกภาพเสียงและวิดีโอ (เช่นภาพถ่ายใบหน้าหรือรหัสสถานะ) สามารถอ่านและเขียนไปยังอุปกรณ์วิทยุบลูทู ธ และสามารถอ่านและเขียนไปยังสนามใกล้ แท็ก transponder, คีย์การ์ดราคาไม่แพง, fobs, สติกเกอร์, แหวนและแม้แต่การปลูกถ่ายชิปที่มีหมายเลขซีเรียลที่ไม่ซ้ำกันซึ่งสามารถอ่านและเขียนด้วยข้อมูลที่สร้างและตรวจสอบโดยเว็บเซิร์ฟเวอร์ที่เชื่อมโยงกับเว็บไซต์ การใช้เครื่องมือทั้งหมดตามที่คุณต้องการด้วยหนังสือเล่มนี้คุณจะได้รับความรู้ในการสร้างเว็บไซต์ที่ปลอดภัยและโดยรวมระบบคอมพิวเตอร์เครือข่าย URE ที่เหมาะกับคุณการเสนอราคาของคุณและดูและรู้สึกถูกต้อง จุดเริ่มต้น: คุณยินดีที่จะข้ามผ่านส่วนที่ฉันเริ่มต้นหนังสือเล่มนี้ด้วยหรือส่วนใด ๆ ไปยังรหัสที่แน่นอนที่คุณต้องการโดยเฉพาะอย่างยิ่งถ้าคุณมีประสบการณ์เกี่ยวกับการเขียนโค้ดก่อนหรือเครื่องมือใด ๆ ที่กล่าวมาข้างต้นฉันจะอธิบายรายละเอียดในหนังสือเล่มนี้เป็น เช่นเดียวกับการบันทึกกรณีการใช้งานและตัวอย่างที่เป็นประโยชน์ หากคุณไม่มีประสบการณ์ในการเขียนโค้ดฉันขอแนะนำให้คุณอ่านหนังสือเล่มนี้ทั้งหมดและโดยเฉพาะอย่างยิ่งขอแนะนำให้คุณอ่านส่วนก่อนหน้านี้เพื่อให้แน่ใจว่าหนังสือเล่มนี้เหมาะกับคุณ หากหนังสือเล่มนี้ไม่ถูกต้องสำหรับคุณให้พิจารณาให้ของขวัญกับเพื่อนหรือญาติที่อาจสนใจเรียนรู้เกี่ยวกับการพัฒนาเว็บด้วยตนเองและแม้แต่พิจารณายืมมันกลับมาและเรียนรู้จากพวกเขาเพื่อเติมเต็มช่องว่างที่ฉันล้มเหลวในฐานะ ครูหรือครูคนอื่น ๆ ทำหน้าฉัน เริ่มต้นที่คุณจะทุกส่วนของหนังสือเล่มนี้จะมีประโยชน์หากคุณตั้งใจจะสร้างประโยชน์PP และพิจารณาว่าแอพที่ดีที่สุดถูกสร้างขึ้นโดยคำนึงถึงผู้ใช้ปลายทาง: รู้จักลูกค้าของคุณ ตอนนี้คุณรู้จักฉันคุณรู้หนังสือเล่มนี้และคุณพร้อมที่จะเริ่มต้น ในการเริ่มต้นคว้าคอมพิวเตอร์ (แม้แต่แล็ปท็อปที่ถูกที่สุดจากร้านค้ากล่องอเมซอนหรือเดสก์ท็อปเก่าและตั้งค่าในแบบที่เหมาะกับคุณ วิธีอ่านหนังสือเล่มนี้: ข้อความที่ไฮไลต์แสดงว่าข้อความอยู่ในพรอมต์คำสั่งซึ่งคุณจะเขียนรหัสที่คุณเรียกใช้ พรอมต์คำสั่งนั้นเน้นคีย์บอร์ดอย่างมากและต้องใช้เพียงเล็กน้อยถึงไม่มีเลยเร่งความเร็วในการทำงานและทำให้คุณง่ายขึ้น เริ่มต้นใช้งาน: มาดำน้ำกันเถอะเราจะเริ่มต้นด้วยการสร้างรหัสบนเครื่องท้องถิ่นและเริ่มต้นโดยไม่ต้องสร้างเว็บไซต์ที่เชื่อมต่อกับอินเทอร์เน็ต สิ่งนี้ปลอดภัยกว่าที่จะเริ่มต้นด้วยค่าใช้จ่ายใด ๆ และเป็นเรื่องง่ายสำหรับคุณ ขึ้นอยู่กับระบบปฏิบัติการของคุณการเข้าสู่เปลือกทุบตีจะแตกต่างกันเล็กน้อย สำหรับ Mac OS ฉันขอแนะนำให้ติดตั้งเครื่องเสมือนจริง ณ จุดนี้เนื่องจากคุณจะได้รับความเข้ากันได้มากที่สุดด้วยเครื่องเสมือน ผู้ให้บริการต่างๆเช่น VirtualBox และ Paralells สามารถเรียกใช้เครื่องเสมือนสำหรับคุณแม้ว่าจะเป็นไปได้ที่จะติดตั้ง Ubuntu โดยตรงบนเครื่องหากคุณต้องการใช้สภาพแวดล้อมดั้งเดิมซึ่งแนะนำเพื่อสร้างประสบการณ์ที่รวดเร็วและคล่องตัว หากคุณใช้ Linux หรือ Windows ซึ่งฉันแนะนำมันน่าจะค่อนข้างง่ายในการสร้างโครงการ เปิดเทอร์มินัลของคุณปรับขนาดตามที่คุณเห็นและเริ่มทำตามขั้นตอนที่ 2 หากคุณใช้ Windows โปรดทำตามขั้นตอนที่ 1 ขั้นตอนที่ 1: - ผู้ใช้ Windows เท่านั้น ใน Windows ให้เปิดพรอมต์คำสั่งเป็นผู้ดูแลระบบและพิมพ์ WSL –install ขั้นตอนที่ 2: - ดำเนินการต่อที่นี่หรือข้ามขั้นตอนที่ 1 ไปที่นี่หากคุณไม่ได้ใช้ Windows ในเทอร์มินัลเปิด (ขึ้นอยู่กับระบบปฏิบัติการของคุณที่เรียกว่า Ubuntu ใน Windows, Terminal ใน Mac หรือ Linux หรือชื่อที่คล้ายกัน) เริ่มต้นด้วยการสร้างโครงการ เราทำสิ่งนี้กับคำสั่ง mkdir ซึ่งสร้างไดเรกทอรี หากคุณต้องการสร้างไดเรกทอรีเพื่อจัดเก็บโครงการของคุณซึ่งแนะนำให้ใช้ไฟล์คำสั่ง CD เพื่อเปลี่ยนเป็นไดเรกทอรีและและ CD/PATH/TO/DIRECTORY - เส้นทางคือโฟลเดอร์ (ไฟล์) ที่นำหน้าไดเรกทอรีปลายทางของคุณเส้นทางเริ่มต้นของคุณคือ ~ หรือ/บ้าน/ชื่อผู้ใช้ (ที่ชื่อผู้ใช้คือชื่อผู้ใช้ของคุณ) หากต้องการเปลี่ยนเป็นไดเรกทอรีเริ่มต้นให้พิมพ์ CD หรือ CD ~ ตัวอย่าง mkdir - แทนที่“ ตัวอย่าง” ด้วยชื่อของไดเรกทอรี ตอนนี้คุณมีไดเรกทอรีการทำงานสำหรับโครงการของคุณ เป็นสิ่งสำคัญมากที่จะต้องบันทึกไดเรกทอรีนี้ในกรณีที่คุณต้องการเปลี่ยนไปใช้เครื่องอื่นหรือปรับใช้รหัสที่คุณเขียนเพื่อให้พร้อมสำหรับเว็บเราจะสร้างสคริปต์เพื่อสำรองไดเรกทอรีของคุณในอีกไม่กี่ขั้นตอนถัดไป แต่การสร้างสคริปต์ใช้รหัสเล็กน้อยและรหัสจะต้องเป็นไปโดยอัตโนมัติเพื่อให้มีประโยชน์มากที่สุด ดังนั้นเรามาสร้างสคริปต์เพื่อสร้างสคริปต์ก่อน เริ่มต้นด้วยการสร้างสคริปต์และทำให้สามารถใช้งานได้ เราจะใช้ sudo, chmod และสัมผัสกับสิ่งนี้และเรียกสคริปต์


sudo touch /usr/bin/ascript
sudo chmod a+x /usr/bin/ascript
sudo nano /usr/bin/ascript
ตอนนี้เราได้สร้างสคริปต์ทำให้สามารถดำเนินการได้และพร้อมที่จะแก้ไข Nano เป็นตัวแก้ไขข้อความที่จะให้คุณแก้ไขข้อความโดยไม่คลิกซึ่งง่ายกว่าการใช้ส่วนต่อประสานผู้ใช้กราฟิก ในการแก้ไขไฟล์ด้วยนาโนให้ใช้นาโนและจากนั้นพา ธ ไปยังไฟล์ ในการสร้างสคริปต์ที่สร้างสคริปต์มันค่อนข้างคล้ายกับการทำให้สคริปต์ของเราตั้งแต่แรก เราจะใช้รหัสเดียวกันกับด้านบนแทนที่ชื่อของสคริปต์“ Ascript” ด้วยพารามิเตอร์อาร์กิวเมนต์ $ 1 สิ่งนี้ช่วยให้เราเรียกสคริปต์โดยการพิมพ์ Sudo Ascript Newscript ณ จุดนี้เราสามารถสร้างสคริปต์ใหม่ได้โดยแทนที่ "newscript" ด้วยชื่อสคริปต์ของคุณ รหัสในนาโนควรมีลักษณะ:

sudo touch /usr/bin/$1
sudo chmod a+x /usr/bin/$1
sudo nano /usr/bin/$1
และเพื่อปิดนาโนเราสามารถกดปุ่มควบคุมและกด X จากนั้น y เพื่อแสดงว่าเรากำลังบันทึกไฟล์และกดกลับ ตอนนี้แทนที่จะพิมพ์คำสั่งทั้งสามนี้เพื่อแก้ไขสคริปต์เราจะสามารถพิมพ์ sudo ascript ascript เพื่อแก้ไขสคริปต์อีกครั้ง ผลงานนี้! และสคริปต์ใหม่ใด ๆ สามารถทำงานได้อย่างง่ายดายโดยเรียกมันในเชลล์ มาบันทึกงานของเรากันเลย: เราเขียนสคริปต์สำรองเพื่อบันทึกสคริปต์ใหม่ของเราแล้วสำรองไว้ในไดเรกทอรีโครงการของเราในขณะเดียวกันก็สำรองสคริปต์สำรอง

sudo ascript backup
ตอนนี้ในนาโน:

sudo cp /usr/bin/backup /path/to/directory/
sudo cp /usr/bin/ascript /path/to/directory/
โดยที่/path/to/directory เป็นเส้นทางไปยังโครงการที่คุณสร้างด้วย mkdir ต่อมาเราจะได้เรียนรู้วิธีคัดลอกเส้นทางซ้ำเช่นนี้ด้วยลูปและรายการซึ่งเป็นรหัสน้อยกว่า แต่ตอนนี้ขอให้มันง่ายและมีไม่กี่บรรทัด ในการเรียกใช้สคริปต์นี้และสำรองรหัสของคุณให้บันทึกไฟล์ในนาโนด้วยตัวควบคุม+x, y และส่งคืนและพิมพ์ด้านล่างลงในเชลล์ของคุณ

backup
หากคุณได้รับแจ้งสำหรับรหัสผ่านในขณะที่อ่านหนังสือเล่มนี้และติดตามในเชลล์โปรดป้อนรหัสผ่านผู้ใช้ของคุณอย่างถูกต้องคุณจะต้องพยายามสามครั้งก่อนที่คุณจะต้องเรียกใช้คำสั่งอีกครั้ง คุณสามารถใช้ลูกศรขึ้นและลงเพื่อเรียกใช้คำสั่ง REUN และแก้ไขได้หากคุณต้องการเรียกใช้อะไรสองครั้ง กดง่ายขึ้นและลงเป็นระยะ ๆ เพื่อเลือกคำสั่งก่อนแก้ไขคำสั่งด้วยลูกศรขวาซ้ายและลบคีย์รวมถึงแป้นพิมพ์และเรียกใช้ด้วยการส่งคืน ยินดีด้วย! คุณจัดการเพื่อสร้างสคริปต์สำรองที่ยอดเยี่ยมที่สำรองสคริปต์เชลล์สำคัญสองสคริปต์ในไดเรกทอรีการทำงานของคุณ เราอาจย้ายสิ่งต่าง ๆ ในภายหลังเมื่อโครงการใหญ่ขึ้น แต่ตอนนี้ใช้งานได้ดี ลองไปสำรองในคลาวด์เราจะใช้ GitHub สำหรับสิ่งนี้ (แม้ว่าจะมีโซลูชัน GIT อื่น ๆ อีกมากมายสำหรับการสำรอง ซอฟต์แวร์ในขณะที่คุณส่งไปยังเซิร์ฟเวอร์ในขณะที่ยังช่วยให้คุณสามารถดาวน์โหลดสำเนาซอฟต์แวร์ทั้งหมดของคุณที่อยู่ด้านหลังรหัสผ่านหรือคีย์ มันมีประโยชน์ในการบันทึกซอฟต์แวร์ของคุณโดยเฉพาะอย่างยิ่งเมื่อเราย้ายไปยังอินสแตนซ์ของ Linux ที่ปลอดภัยซึ่งบางครั้งก็แตกเมื่อรหัสบรรทัดเดียวล้มเหลวทำให้คุณถูกล็อคในขณะที่รหัสของคุณอาจไม่ได้รับการสำรองหากคุณไม่ได้รับโอกาสในการสำรองข้อมูล ขึ้นโดยอัตโนมัติซึ่งเราจะครอบคลุม หากคุณยังไม่ได้ใช้เครื่องเสมือนของ Ubuntu ณ จุดนี้ฉันขอแนะนำให้ใช้เครื่องเสมือนของ Ubuntu ณ จุดนี้เพราะมันจะทำให้ชีวิตของคุณง่ายขึ้นเมื่อติดตั้งแพ็คเกจทั้งหมดที่จำเป็นเพื่อสร้างเว็บไซต์ที่ใช้งานได้ การดำเนินการในคอมพิวเตอร์ของคุณ เราจะย้ายรหัสไปยังเว็บเซิร์ฟเวอร์ในอนาคตอันใกล้ แต่เราต้องการให้แน่ใจว่ามีความปลอดภัยอย่างน้อยสองสามเลเยอร์ที่อยู่เบื้องหลังเว็บเซิร์ฟเวอร์ของเราที่ทนต่อฟิชชิ่งและใช้แพ็คเกจ Linux จำนวนหนึ่งเพื่อที่จะทำ นี้. หากคุณยังต้องการใช้ Mac OS คุณสามารถค้นหาและติดตั้งได้แพคเกจที่จำเป็นทางออนไลน์ แต่อาจไม่มีทางเลือกสำหรับทุกแพ็คเกจหนังสือหรือซีรีส์นี้จะครอบคลุม มาเพิ่มคำสั่งสองสามคำเพื่อส่งผลงานของเราด้วยสคริปต์สำรองโดยเรียกใช้คำสั่ง sudo ascript

# -
git add –all
git commit -m “backup”
git push -u origin master
อีกครั้งควบคุม X เพื่อบันทึก ตอนนี้เราต้องทำการกำหนดค่าครั้งเดียวสำหรับโครงการนี้ เนื่องจากในไม่ช้ามันจะเป็นโครงการ GIT เราไม่จำเป็นต้องพิมพ์ทุกคำสั่งทุกครั้งที่เราปรับใช้จากที่เก็บ GIT แต่เราจะได้รับสิ่งนี้เมื่อเราเขียนสคริปต์การปรับใช้ของเรา ในการเริ่มต้นให้ตรวจสอบให้แน่ใจว่าเราอยู่ในไดเรกทอรีที่เหมาะสมและเริ่มต้นที่เก็บ GIT และสร้างคีย์ SSH

cd /path/to/directory
git init
git branch -m master
ssh-keygen
หลังจากที่เราพิมพ์ ssh-keygen คีย์ใหม่ควรบันทึกไว้ในโฟลเดอร์โฮมภายใต้โฟลเดอร์ที่เรียกว่า. ssh มันถูกเรียกว่า id_rsa.pub ลองค้นหาคีย์นี้และคัดลอก เพื่อดูมัน

cd ~
cat .ssh/id_rsa.pub
คัดลอกข้อความที่ส่งคืนโดยคำสั่งสุดท้ายและสร้างบัญชีกับผู้ให้บริการ GIT ของคุณ (GitHub อย่างเหมาะสม) ก่อนที่จะเพิ่มคีย์ SSH ลงในบัญชีของคุณ เมื่อคุณมีบัญชีแล้วให้คลิกเมนูด้านบนขวาและป้อนการตั้งค่าก่อนที่จะเพิ่มคีย์ SSH ของคุณในคีย์ SSH และ GPG ภายใต้การเข้าถึงในเมนู เลือกเพิ่มคีย์ SSH และเพิ่มของคุณโดยวางไว้ในและให้ชื่อก่อนที่จะบันทึกและกลับไปที่ GitHub เพื่อสร้างที่เก็บใหม่ สิ่งนี้คล้ายกันสำหรับผู้ให้บริการ GIT รายอื่นคุณจะต้องอ่านเอกสารของพวกเขา ในการกำหนดค่าที่เก็บใหม่ให้ชื่อที่เก็บของคุณมีชื่อเชิงพรรณนาและตัดสินใจว่าคุณต้องการเผยแพร่หรือไม่และตรวจสอบให้แน่ใจว่าไม่มีการกำหนดค่าไฟล์สำหรับการรวม เมื่อสร้างที่เก็บแล้วให้คัดลอกโคลนด้วย URL SSH และวางลงในคำสั่งต่อไปนี้

git remote add git://… (your remote URL)
ตอนนี้คุณสามารถย้ายกลับไปที่ที่เก็บด้วยซีดีคุณจะคุ้นเคยกับสิ่งนี้ ลองใช้สคริปต์สำรองของคุณตอนนี้ด้วยการสำรองข้อมูล ยอดเยี่ยม! ตอนนี้เราสามารถรับการเข้ารหัสได้จริงๆ มาติดตั้ง Django กันเถอะว่าเรามีความเข้าใจที่ดีเกี่ยวกับ Bash and Git Django จะให้เราสำรองซอฟต์แวร์ของเราโดยอัตโนมัติ Bash สามารถทำสิ่งนี้ได้เช่นกัน แต่ Django ควรมีการใช้งานที่ปลอดภัยกว่าที่ง่ายกว่า (สามารถปิดใช้งานและกำหนดค่าได้ง่ายขึ้น) ในการติดตั้งซอฟต์แวร์ใน Ubuntu เราจะใช้คำสั่ง sudo apt-get ก่อนอื่นมาอัปเดตและอัพเกรดซอฟต์แวร์ที่เรามีอยู่แล้ว สามารถทำได้ด้วยการอัปเดต Sudo Apt-Get และการอัพเกรด Sudo Apt-Get -y ต่อไปให้ติดตั้ง Python และสภาพแวดล้อมเสมือนจริงของเราบ้านของรหัสของเราด้วยคำสั่งต่อไปนี้: sudo apt-get ติดตั้ง python-is-python3 python3-venv นี่คือทั้งหมดที่คุณต้องใช้กับ Django ในแง่ของการติดตั้งซอฟต์แวร์ในอินสแตนซ์ Ubuntu สำหรับ Windows และ Linux สิ่งนี้ควรตรงไปตรงมา แต่สำหรับ Mac คุณอาจต้องการติดตั้งเครื่องเสมือนและLinux โดยใช้สภาพแวดล้อมเสมือนจริงฟรีหรือชำระเงินเช่น VirtualBox หรือ Paralells Desktop และสร้างขั้นตอนข้างต้นใหม่เพื่อตั้งค่าสภาพแวดล้อม Ubuntu Ubuntu มีความสำคัญในกรณีนี้เนื่องจากเป็นซอฟต์แวร์ที่เว็บไซต์ทำงานและช่วยให้พวกเขาสามารถโฮสต์เว็บไซต์ด้วยซอฟต์แวร์ทั้งหมดดังกล่าว มาขุดลงไปใน Django ในไดเรกทอรีของเราอีกครั้งด้วย

python -m venv venv # สร้างสภาพแวดล้อมเสมือนจริงที่จัดเก็บรหัส
source venv/bin/activate # เปิดใช้งานสภาพแวดล้อมเสมือนจริง
pip install Django
django-admin startproject mysite . # ที่ MySite เป็นโครงการที่ฉันเริ่มต้นในไดเรกทอรีปัจจุบันของฉัน
Django เพิ่งเริ่มต้นเราเพราะ Django กำลังโฮสต์เว็บเซิร์ฟเวอร์และกำลังทำทุกอย่างที่เราต้องการเพื่อให้เว็บไซต์ท้องถิ่นพื้นฐานทำงาน ตอนนี้เราได้ติดตั้ง Django แล้วเรามาแก้ไขการตั้งค่าเล็กน้อยเพื่อให้มันทำงานตามที่เราต้องการ ก่อนอื่นมาสร้างแอพใหม่

python manage.py startapp feed
คุณจะสังเกตเห็นว่าแอพแรกเรียกว่าฟีด แอพควรเรียกสิ่งที่คุณต้องการและเราจะสร้างแอพใหม่ แต่ชื่อของแต่ละแอพจะต้องสอดคล้องกันทุกครั้งที่แอปอ้างอิงในรหัส ในการเพิ่มแอพใหม่เราจะแก้ไขการตั้งค่าเสมอ py ในไดเรกทอรีอื่น ๆ แอปที่สร้างขึ้นชื่อใน startProject แอปต่อจากนี้ ใช้นาโน

nano app/settings.py
ในการตั้งค่าให้ค้นหา _apps ที่ติดตั้งและแยก [] ออกเป็น 3 บรรทัด การใช้ช่องว่างสี่ช่องบนเส้นกลางที่ว่างเปล่าเพิ่ม 'ฟีด' หรือชื่อแอปของคุณ ส่วนนี้ของการตั้งค่า py ควรมีลักษณะ:

INSTALLED_APPS = [
    'feed',
]
ก่อนที่เราจะลืมลองทดสอบว่า Django กำลังทำงานอยู่ การใช้คำสั่ง python manage.py runserver 0.0.0.0:8000 เราสามารถเรียกใช้เซิร์ฟเวอร์แล้วนำทางในเว็บเบราว์เซอร์บนคอมพิวเตอร์ที่ใช้รหัสไปยัง http: // localhost: 8000 และดูตัวอย่างเว็บเพจ (ใช้งานได้!) ออกจากเซิร์ฟเวอร์ด้วยตัวควบคุม C เหมือนกับคำสั่งอื่น ๆ ตอนนี้เรามาเขียนโค้ด Python กันบ้าง Django มีสามองค์ประกอบหลักทั้งหมดดำเนินการด้วยรหัสทั้งหมด ส่วนประกอบนี้เรียกว่าโมเดลมุมมองและเทมเพลตและแต่ละส่วนจะอยู่ในระดับที่สูงขึ้นและต่ำกว่าตามลำดับก่อนที่หน้าเว็บจะถูกส่งไปยังผู้ใช้ โมเดลคือรหัสที่เก็บข้อมูลในฐานข้อมูลสำหรับการดึงการเรียงลำดับและการแสดงผล มุมมองตัดสินใจว่าโมเดลนั้นได้รับการจัดการและแก้ไขอย่างไรเกือบทุกมุมมองจะใช้แบบจำลองโดยตรง เทมเพลตคือรหัส HTML ที่มีระฆังพิเศษและนกหวีดที่เรียกว่าภาษาแม่แบบ เทมเพลตจะแสดงผลโดยมุมมองที่เต็มไปด้วยรหัส Python และบริบทเช่นแบบจำลองและข้อมูล (usuall strings และจำนวนเต็ม) จากมุมมอง Django มีส่วนประกอบอื่น ๆ เช่นกันรวมถึง แต่ไม่ จำกัด เพียง: การตั้งค่าซึ่งกำหนดค่าแอปตามที่เราพูดถึง URL ซึ่งเป็นรูปแบบที่ผู้ใช้ติดตามเพื่อเข้าถึงส่วนเฉพาะของเว็บแอปพลิเคชัน แบบฟอร์มซึ่งกำหนดวิธีการส่งข้อมูลที่ส่งไปยังเซิร์ฟเวอร์และแสดงผลไปยังฐานข้อมูลเช่นเดียวกับผู้ใช้ เหล่านี้เป็นรากฐานของข้อมูลการประมวลผลทางฝั่งเซิร์ฟเวอร์และสามารถรับข้อมูลประเภทใดก็ได้ที่ร้านคอมพิวเตอร์สตริงข้อความที่โดดเด่นที่สุดตัวเลขและบูลีนจริง/เท็จ (โดยปกติจะเป็นช่องทำเครื่องหมาย) เทมเพลตซึ่งเป็นรหัส HTML และภาษาแม่แบบและเชื่อมช่องว่างระหว่าง Python และ HTML หมายถึงข้อมูล Python สามารถใช้เป็นรหัส HTML ที่ทุกคนสามารถเข้าถึงและสามารถรักษาความปลอดภัยเว็บไซต์ด้วยการเข้าถึงที่ จำกัด สำหรับวัตถุประสงค์ที่หลากหลายบนอุปกรณ์ระยะไกลที่ไม่ได้eed จะอยู่ใกล้เซิร์ฟเวอร์ ไฟล์คงที่ซึ่งมักจะเป็น JavaScript และเป็นไลบรารีที่เซิร์ฟเวอร์ให้บริการและเชื่อมโยงกับเทมเพลต ไฟล์สื่อซึ่งเซิร์ฟเวอร์ให้บริการหรือโฮสต์จากภายนอกหรือเพิ่งเขียนลงในเซิร์ฟเวอร์ก่อนที่จะถูกประมวลผลและโพสต์ไปยังเซิร์ฟเวอร์อื่น (ที่เก็บข้อมูล) สำหรับโฮสต์ มิดเดิลแวร์ซึ่งเป็นชิ้นส่วนของรหัสที่ทำงานในเวลาเดียวกันกับทุกมุมมองและได้รับการพิจารณาว่า "รวมอยู่ในมุมมอง ประมวลผลบริบทซึ่งประมวลผลบริบทของแต่ละมุมมองและใช้เพื่อเพิ่มบริบทพิเศษ การทดสอบซึ่งตรวจสอบว่าผู้ใช้หรือคำขอผ่านข้อกำหนดบางประการก่อนที่จะแสดงมุมมอง ผู้บริโภคซึ่งกำหนดวิธีที่ WebSockets จัดการและตอบสนองต่อการสื่อสาร ผู้ดูแลระบบซึ่งใช้ในการลงทะเบียนโมเดลเพื่อให้สามารถจัดการรายละเอียดภายในหน้า Django Admin ซึ่งฐานข้อมูลสามารถจัดการผ่านอินเตอร์เฟสกราฟิก คื่นฉ่ายซึ่งกำหนดงานอะซิงโครนัสบางส่วนของรหัส Django สามารถเริ่มต้นได้ก่อนที่จะดำเนินการต่อไปยังงานหรือบรรทัดของรหัสต่อไปทันที Django สามารถมีส่วนประกอบอื่น ๆ อีกมากมายซึ่งเราจะพูดถึงรายละเอียดที่นี่ มีหลายวิธีในการทำให้ django ทำงานได้มากขึ้นเพิ่ม websockets ซึ่งเป็นช่องทางการสื่อสารที่รวดเร็วมีความคล่องตัว, คื่นฉ่ายซึ่งดำเนินงานแบบอะซิงโครนัสและซอฟต์แวร์ชิ้นอื่น ๆ มากมายสำหรับการขยาย Django โดยเฉพาะอย่างยิ่งในฟังก์ชั่นมุมมอง รหัสถูกดำเนินการ ฟังก์ชั่นดูเป็นกุญแจสำคัญเพราะพวกเขามักจะประกาศรหัสทุกชิ้นที่เฉพาะเจาะจงกับรูปแบบ URL เฉพาะหรือส่วนของเซิร์ฟเวอร์ ก่อนอื่นมาสำรวจฟังก์ชั่นมุมมอง ฟังก์ชั่นดูเริ่มต้นด้วยการนำเข้าที่แสดงถึงรหัสที่จะใช้ในมุมมองและถูกกำหนดโดยใช้คำจำกัดความฟังก์ชันปกติหรือคลาส มุมมองที่ง่ายที่สุดถูกกำหนดโดยนิยามฟังก์ชัน def และส่งคืน httpresponse ด้วยเทมเพลตพื้นฐาน เริ่มต้นด้วยการกำหนดมุมมองพื้นฐานเพื่อส่งคืนข้อความ“ Hello World” จำไว้ว่าทุกครั้งที่คุณเพิ่มแสดงคำสั่งเช่น def ถ้าในขณะที่สำหรับ ฯลฯ คุณจะต้องเพิ่ม 4 ช่องว่างสำหรับคำจำกัดความก่อนหน้าแต่ละคำที่คุณต้องการนำไปใช้กับฟังก์ชั่นของคุณ เราจะเข้าสู่ความหมายของแต่ละสิ่งเหล่านี้ในไม่ช้า จากไดเรกทอรีของไซต์ของเราแก้ไขไฟล์ feed/views.py โดยใช้ Nano และเพิ่มบรรทัดต่อไปนี้ในตอนท้ายของไฟล์

from django.http import HttpResponse

def hello(request):
    return HttpResponse('hello world')
httpresponse ของ Django ตอบกลับด้วยสตริงข้อความแสดงด้วยการเปิดและปิด ' ทุกครั้งที่คุณส่งข้อมูลไปยังฟังก์ชั่นหรือคลาสเช่นคำขอหรือสตริงคุณจะต้องใช้วงเล็บ (, การเปิดและปิด) นี่ไม่ใช่ทั้งหมดที่เราต้องเห็นมุมมองของเรา แน่นอนว่าเรายังไม่ได้บอกเซิร์ฟเวอร์ว่ามุมมองอยู่ตรงไหนเรายังต้องกำหนดเส้นทางที่มุมมองควรแสดงผล เริ่มต้นด้วยการกำหนดเส้นทางพื้นฐานในแอพ/urls.py และเราจะเข้าสู่กลุ่มพา ธ ในภายหลัง ในแอพ/urls.py เพิ่มบรรทัดหลังจากคำสั่งนำเข้าหลังจากเริ่มต้นนำเข้ามุมมองที่เราเพิ่งสร้างขึ้น

from feed import views as feed_views
ตอนนี้เรามากำหนดรูปแบบการดู รูปแบบการดูมีสามองค์ประกอบส่วนประกอบพา ธ ซึ่งจะบอกเซิร์ฟเวอร์ว่ามีมุมมองที่มีอยู่ภายในเซิร์ฟเวอร์ (พา ธ URL ที่ผู้ใช้พิมพ์ลงในแถบการนำทางเพื่อเข้าสู่หน้าเว็บ) ส่วนประกอบมุมมองที่ระบุมุมมองและ A ชื่อที่เป็นมิตรสำหรับมุมมองดังนั้นจึงเป็นเรื่องง่ายที่จะดึงรูปแบบของมันเมื่อทำงานกับเทมเพลตโดยเฉพาะอย่างยิ่งดังนั้นชื่อจึงสามารถเปลี่ยนแปลงและอัปเดตได้หากจำเป็นเพื่อให้มีพื้นที่สำหรับมุมมองอื่นหรือใช้ชื่อที่มีเหตุผลมากขึ้น มันสมเหตุสมผลที่จะทำสิ่งต่าง ๆ ด้วยวิธีนี้และมีความยืดหยุ่นเพราะ codebase ของคุณจะเป็นสภาพแวดล้อมที่เปลี่ยนแปลงตลอดเวลาที่ต้องการความยืดหยุ่นและการปรับตัวเพื่อให้มีคุณค่าและง่ายต่อการทำงาน นี่คือสิ่งที่มุมมองของคุณจะเป็นเช่นนั้นคุณสามารถเพิ่มสิ่งนี้ลงใน urlpatterns = [ส่วนของแอพ/urls.py รูปแบบมุมมองถูกกำหนดด้วยสามองค์ประกอบที่อธิบายไว้ข้างต้นและฟังก์ชั่นที่เรียกว่าเส้นทาง รูปแบบ URL ของคุณเป็นรายการดังนั้นอย่าลืมจบแต่ละรายการไว้เสมอด้วยเครื่องหมายจุลภาคเพราะสิ่งนี้จะแยกแต่ละอันออก แต่ละรายการควรไปบนบรรทัดใหม่อีกครั้งด้วยสี่ช่องว่างก่อนหน้านี้เช่นเดียวกับแอพในการตั้งค่า py เราจะกำหนดส่วนประกอบแรกของมุมมองด้วยฟังก์ชั่นสตริงว่างเพื่อสร้างมุมมองที่ทำงานบนไดเรกทอรีรูทของเว็บเซิร์ฟเวอร์ urls.py ของคุณตอนนี้ควรมีลักษณะ

from feed import views as feed_views

urlpatterns = [
    path('', feed_views.hello, name='hello'),
]
นี่คือพื้นฐานสำหรับการสร้างเว็บไซต์ที่มี django ที่คงที่อย่างสมบูรณ์ เพื่อสร้างเว็บไซต์แบบไดนามิกมากขึ้นซึ่งเราสามารถเริ่มการแคชข้อมูลเช่นรูปภาพวิดีโอเสียงและอื่น ๆ เราจะต้องใช้โมเดลซึ่งเราจะสำรวจต่อไป สำหรับตอนนี้ลองตรวจสอบรหัสของเราและเรียกใช้เซิร์ฟเวอร์ หากต้องการตรวจสอบรหัสข้อผิดพลาดให้เรียกใช้:

python manage.py check
หากมีข้อความแสดงข้อผิดพลาดใด ๆ คุณควรตรวจสอบการเปลี่ยนแปลงที่คุณทำกับแอปของคุณอย่างรอบคอบและดูว่ามีสิ่งใดที่จำเป็นต้องได้รับการแก้ไขหรือไม่หรือขาดพื้นที่ ตัวละครที่ถูกลบหรือสิ่งอื่นใด การอ่านข้อความแสดงข้อผิดพลาด (ถ้าคุณมี) คุณควรจะเห็นเส้นทางไปยังไฟล์ที่คุณสร้างหรือแก้ไขพร้อมหมายเลขบรรทัดดังนั้นดูไฟล์และบรรทัดนั้นและดูว่าคุณสามารถแก้ไขอะไรก็ได้ที่มีอยู่ . หากคุณได้แก้ไขปัญหาให้เรียกใช้คำสั่งด้านบนอีกครั้ง เมื่อซอฟต์แวร์ของคุณพร้อมที่จะทำงานและใช้งานได้คุณจะเห็นผลลัพธ์“ การตรวจสอบระบบที่ระบุว่าไม่มีปัญหา” ตอนนี้คุณพร้อมที่จะไป เรียกใช้เซิร์ฟเวอร์ด้วย:

python manage.py runserver 0.0.0.0:8000
ตอนนี้เปิดเว็บเบราว์เซอร์และนำทางไปที่ http: // localhost: 8000 คุณควรเห็นข้อความที่ส่งคืนในวงเล็บและคำพูดของฟังก์ชั่น HTTPRESSPONSE ในมุมมองของคุณ นี่เป็นเพียงตัวอย่างพื้นฐาน แต่ถ้าคุณทำมันไกลขนาดนี้คุณเข้าใจพื้นฐานของการทำงานของ Linux, Bash, Python และ Django ลองขุดลึกลงไปในการสร้างแบบจำลองฐานข้อมูลและสำรวจพลังของคลาส Python ในการจัดเก็บข้อมูล จากนั้นเราจะเริ่มจับ HTML และ CSS ก่อนที่เราจะทำให้ไซต์ของเราโดดเด่นมีความยืดหยุ่นและปลอดภัยโดยใช้ JavaScript และการเรียนรู้ของเครื่อง คลาสจะถูกเก็บไว้ในโมเดลแอพของคุณ การใช้ Nano, แก้ไขแอพ/models.py และเพิ่มคลาสใหม่ คลาสถูกกำหนดด้วยคำจำกัดความของคลาสและผ่าน superclass ที่ได้รับมาจากในกรณีนี้โมเดลโมเดล ชื่อของคลาสมาหลังจากคำจำกัดความของคลาสและหลังจากคำจำกัดความของคลาส A: (ลำไส้ใหญ่) ถูกนำมาใช้ก่อนที่จะมีแอตทริบิวต์และคำจำกัดความฟังก์ชันที่เชื่อมโยงกับคลาสแสดงไว้ด้านล่าง ชั้นเรียนของเราต้องการ ID ที่เราสามารถใช้เพื่อเรียกคืนและทำให้เป็นเอกลักษณ์และยังต้องการฟิลด์ข้อความเพื่อจัดเก็บข้อมูลบางอย่าง ในภายหลังเราสามารถเพิ่มการประทับเวลาไฟล์บูลีน (คำจำกัดความจริงหรือเท็จที่สามารถช่วยโค้ดของเราตัดสินใจเกี่ยวกับสิ่งที่ต้องทำกับโมเดลและสามารถใช้ในการเรียงลำดับ) อินสแตนซ์เพื่อผูกโมเดลกับผู้ใช้ที่บันทึกไว้ เข้าสู่เซิร์ฟเวอร์และอื่น ๆ มาแกะรหัสกันเถอะ

from django.db import models # การนำเข้าที่ใช้เพื่อกำหนดคลาสของเราและเป็นคุณลักษณะ

class Post(models.Model): # คำจำกัดความของชั้นเรียนของเราเอง
    id = models.AutoField(primary_key=True) # ID ของโมเดลของเราซึ่งเป็นคีย์ที่สร้างขึ้นโดยอัตโนมัติซึ่งจะช่วยให้เราสอบถามโมเดลรักษาความเป็นเอกลักษณ์และมีประโยชน์เมื่อเราต้องการโต้ตอบกับโมเดลเมื่อสร้างขึ้น
    text = models.TextField(default='') # แอตทริบิวต์คลาสของเราจัดเก็บในกรณีนี้ข้อความบางส่วนเริ่มต้นเป็นสตริงว่าง
ปิดและบันทึกไฟล์ตามที่เราทำก่อนหน้านี้ มีฟิลด์และตัวเลือกอื่น ๆ อีกมากมายที่เราจะสำรวจเมื่อเราอัปเดตคลาสนี้เมื่อแอปของเราวิวัฒนาการ แต่นี่เป็นสิ่งจำเป็นพื้นฐานในการสร้างแอพเพื่อโพสต์ข้อความ อย่างไรก็ตามรุ่นนี้จะไม่ทำงานคนเดียว ตามที่อธิบายไว้ก่อนหน้านี้เราจะต้องมีมุมมองที่กำหนดเองและรูปแบบ URL ที่กำหนดเองเพื่อให้โมเดลนี้ทำงานได้และเราจะต้องมีแบบฟอร์มพร้อมกับเทมเพลต มาสำรวจแบบฟอร์มก่อน ในการกำหนดแบบฟอร์มให้แก้ไขแอพ/ฟอร์มด้วยนาโนและเพิ่มบรรทัดต่อไปนี้ เราจะต้องมีการนำเข้าสองรายการคลาสแบบฟอร์มของเรารวมถึงโมเดลที่เราสร้างขึ้น (feed.models.post), คำจำกัดความของคลาสที่คล้ายกับโมเดลและฟิลด์พร้อมกับคลาสย่อยที่เรียกว่า meta ที่จะกำหนดรูปแบบแบบโต้ตอบ กับ. แบบฟอร์มยังสามารถมีฟังก์ชั่นการเริ่มต้นซึ่งตั้งค่าตามข้อมูลในคำขอโมเดลหรืออื่น ๆ เราจะสำรวจสิ่งนี้ในภายหลัง รูปแบบแบบจำลองมีประโยชน์มากเพราะสามารถสร้างโมเดลหรือแก้ไขโมเดลได้ดังนั้นเราจะใช้พวกเขาทั้งคู่ มากำหนดหนึ่งในรูปแบบ py

from django import forms
from feed.models import Post

class PostForm(forms.ModelForm):
    text = forms.CharField(widget=forms.Textarea)
    class Meta:
        model = Post
        fields = ('text',)
นี่คือพื้นฐานของรูปแบบและรูปแบบที่มีลักษณะอย่างไร แบบฟอร์มโมเดลนี้สามารถใช้ในการสร้างอินสแตนซ์หรือแก้ไขโพสต์เปลี่ยนข้อความที่มีอยู่ เราจะดูการรวมฟอร์มนี้เข้ากับมุมมองต่อไป ก่อนอื่นมาทำการอพยพและโยกย้ายฐานข้อมูลเพื่อให้รหัสของเราสามารถโต้ตอบกับโมเดลเมื่อทำงานได้ ในการทำเช่นนี้ให้เรียกใช้คำสั่งต่อไปนี้:

python manage.py makemigrations
python manage.py migrate
วิธีนี้จะใช้เวลาสักครู่ในการดำเนินการ แต่เมื่อทำเช่นนั้นมันจะช่วยให้คุณสามารถเข้าถึงโมเดลในมุมมองมิดเดิลแวร์หรือที่อื่น ๆ ในซอฟต์แวร์ มาดูต่อไปโดยการดูที่เราสามารถเห็นโมเดลของเรา แก้ไข FEED/Views.py และเพิ่มรหัสต่อไปนี้ตามที่ระบุไว้ คุณไม่จำเป็นต้องเพิ่มอะไรหลังจากป้าย # รหัสนั้นเป็นความคิดเห็นที่ใช้เพื่อแสดงข้อมูลเกี่ยวกับรหัส เราจะเริ่มต้นด้วยการนำเข้าโมเดลของเราในมุมมองและเพิ่มลงในบริบทที่เราสามารถแสดงในเทมเพลตเป็นรายการสำหรับการแสดงผล ต่อไปเราจะเพิ่มเทมเพลตที่เราสามารถแสดงผลและรุ่นด้วยปุ่มเพื่อสร้างวัตถุใหม่ตามรุ่นและโพสต์ลงในเซิร์ฟเวอร์ ฟังดูซับซ้อนดังนั้นลองมาทีละขั้นตอน ก่อนที่เราจะจบมุมมองลองสร้างเทมเพลตที่เพิ่งแสดงผลโมเดลและตรวจสอบให้แน่ใจว่าเราสามารถดูได้โดยการสร้างโพสต์ใหม่ในเชลล์ นี่คือวิธีที่มุมมองนั้นควรดู:

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

def feed(request):
    posts = Post.objects.all() # สอบถามโพสต์ทั้งหมดในฐานข้อมูลจนถึงตอนนี้
    return render(request, 'feed/feed.html', {
        'posts': posts,
    })
ทั้งหมดนี้ดูเรียบง่ายจนกระทั่งเราไปถึงด้านล่าง เรนเดอร์ค่าที่ส่งคืนโดยฟังก์ชั่นแทนที่จะเป็นในการตอบกลับ HTTP เช่นตัวอย่างก่อนหน้านี้มักจะใช้การร้องขอเป็นอินพุตแรกยอมรับบริบท (ในกรณีนี้โพสต์ในฐานข้อมูล) ซึ่งสามารถแสดงผลได้ในเทมเพลต และส่งคืนเทมเพลตที่กำหนดไว้ในฟังก์ชั่น เทมเพลตกำลังจะเป็นเอกสาร HTML ที่มีภาษาเล็กน้อยที่เรียกว่า Jinja2 ซึ่งแสดงข้อมูล Python ลงใน HTML ในการเริ่มต้นสร้างเทมเพลตให้ทำสองไดเรกทอรีในฟีด

mkdir feed/templates
mkdir feed/templates/feed
ถัดไปแก้ไขเทมเพลตในไดเรกทอรีด้านบนฟีด/เทมเพลต/ฟีดและเพิ่มรหัสสำหรับตัวอย่างนี้ ลองดูที่แม่แบบสำหรับตัวอย่างนี้
 
<!doctype HTML>
<html>
<body>
<legend>Feed</legend>
<hr>
{% for post in posts %}
<p>{{ post.text }}</p>
{% endfor %}
</body>
</html>
 
นี่คือเทมเพลตที่ง่ายมาก มันกำหนดแท็กการเปิดและปิด HTML, แท็กประเภทเอกสาร, แท็กตัวถังที่มีชื่อตำนาน, แท็กเบรคซึ่งเพิ่มบรรทัดเล็ก ๆ ข้ามหน้าจอและสำหรับลูปที่แสดงผลแต่ละโพสต์ในรายการโพสต์เป็นย่อหน้าใน เทมเพลต นี่คือทั้งหมดที่ใช้ในการโพสต์ แต่ยังไม่มีในฐานข้อมูล มาสร้างบางอย่างด้วยเชลล์ เราสามารถเรียกใช้เชลล์ด้วย managem.py

python manage.py shell
ตอนนี้เรามานำเข้าโมเดลโพสต์ของเรากันเถอะ

from feed.models import Post
ต่อไปเราจะสร้างโพสต์อย่างง่ายด้วยสตริงและออกจากเชลล์ สตริงสามารถเป็นอะไรก็ได้ตราบใดที่มันเป็นข้อความที่ถูกต้อง

Post.objects.create(text='hello world')
exit()
สุดท้ายเราจะต้องเพิ่มรูปแบบ URL ลงในฟีดของเรา เนื่องจากแอพฟีดของเราจะใช้ URL หลายตัวและเราต้องการเก็บขนาดไฟล์ไว้ให้เล็กลองสร้าง urls ท้องถิ่นในแอพฟีดของเราที่มีลักษณะเช่นนี้:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.feed, name='feed'),
]
เราจะต้องแก้ไข urls.py ในแอพพื้นฐานไม่ว่าเราจะตัดสินใจเรียกมันว่านี่เป็นไดเรกทอรีแรกที่เราสร้างขึ้น แก้ไขแอพ/app.py และเพิ่มสิ่งต่อไปนี้ในรูปแบบ URL

from django.urls import include # ที่ด้านบน

urlpatterns = [
    # ... รหัสก่อนหน้านี้ที่นี่
    path('feed/', include(('feed.urls'), namespace='feed')),
]
ตอนนี้เมื่อเราเรียกใช้เซิร์ฟเวอร์ด้วย Python Manage.py Runserver เราจะเห็นหน้าเว็บที่เราสร้างขึ้นเพราะเรามีโมเดลมุมมองและเทมเพลตรวมถึงรูปแบบ URL พร้อมกับรายการในฐานข้อมูล ต่อไปเรามาใช้แบบฟอร์มที่เราสร้างและเริ่มสร้างโพสต์ของเราเอง แต่ก่อนที่เราจะเขียนโค้ดมากเกินไปให้ทำการสำรองข้อมูลโดยใช้สคริปต์ที่เราเขียนไว้ก่อนหน้านี้สำรองข้อมูล เรียกใช้สคริปต์นี้ในเชลล์รอสักครู่และรหัสทั้งหมดจะได้รับการสำรองไว้ในที่เก็บ Git ของเรา

backup
การใช้แบบฟอร์มนั้นค่อนข้างง่าย เราจะนำเข้าแบบฟอร์มของเราเพิ่มตัวจัดการคำขอโพสต์ลงในมุมมองและบันทึกโพสต์ในฐานข้อมูลก่อนที่จะเปลี่ยนเส้นทางไปยังมุมมองเดียวกัน เราสามารถใช้ฟังก์ชั่นการเปลี่ยนเส้นทางที่เรานำเข้าแล้วและฟังก์ชั่นอื่นที่เรียกว่า Reverse เพื่อรับ URL สำหรับรูปแบบการดู เราจะสอบถามสิ่งนี้ด้วยสตริง 'ฟีด: ฟีด' เพราะเนมสเปซของรูปแบบที่รวมอยู่คือฟีดและมุมมองที่เรียกว่าฟีด

from feed.forms import PostForm

def feed(request):
    posts = Post.objects.all() # สอบถามโพสต์ทั้งหมดในฐานข้อมูลจนถึงตอนนี้
    if request.method == 'POST': # จัดการคำขอโพสต์
        form = PostForm(request.POST) # สร้างอินสแตนซ์ของแบบฟอร์มและบันทึกข้อมูลลงไป
        if form.is_valid(): # ตรวจสอบความถูกต้องของแบบฟอร์ม
            form.save() # บันทึกวัตถุใหม่
        return redirect(reverse('feed:feed')) # เปลี่ยนเส้นทางไปยัง URL เดียวกันด้วยคำขอรับ
    return render(request, 'feed/feed.html', {
        'form': PostForm(), # ตรวจสอบให้แน่ใจว่าได้ส่งผ่านแบบฟอร์มเข้าไปในบริบทเพื่อให้เราสามารถแสดงผลได้
        'posts': posts,
    })
ตอนนี้เราจะต้องอัปเดตเทมเพลตเพื่อบัญชีสำหรับแบบฟอร์มใหม่ เราสามารถทำได้โดยใช้ไฟล์
แท็กใน HTML และแสดงผลแบบฟอร์มในเทมเพลต HTML ด้วยปุ่มส่ง นอกจากนี้เรายังต้องการโทเค็น CSRF ซึ่งเป็นโทเค็นที่ป้องกันไม่ให้ไซต์ภายนอกโพสต์ลงในแบบฟอร์มโดยไม่ต้องโหลดหน้าแรก
 
<!doctype HTML>
<html>
<body>
<legend>Feed</legend>
<form method=”POST”>
{% csrf_token %}
{{ form }}
<button type=”submit”>New Post</button>
</form>
<hr>
{% for post in posts %}
<p>{{ post.text }}</p>
{% endfor %}
</body>
</html>
 
มาทำลายสิ่งนี้กันเถอะ มีคลาสแบบฟอร์มใหม่โทเค็นแบบฟอร์มและปุ่มส่ง ค่อนข้างง่าย แต่เมื่อเราดูมันเราอาจต้องการทำให้มันดูดีขึ้น มันใช้งานได้เราสามารถโพสต์โพสต์ใหม่ด้วยแบบฟอร์มและตอนนี้พวกเขาจะถูกบันทึกไว้ในฐานข้อมูล มีบางสิ่งเกิดขึ้นที่นี่ เราใช้แท็ก HTML เพื่อประกาศว่าเอกสารเป็นเอกสาร HTML เราใช้แท็กเทมเพลต ({ % … %}) เพื่อแสดงโทเค็นสำหรับแบบฟอร์มและอีกอันหนึ่ง {{…}} เพื่อแสดงผลแบบฟอร์ม นอกจากนี้เรายังมีลูปเพื่อแสดงข้อความโดยใช้แท็กบล็อกและแท็กเทมเพลต แท็กบล็อกมีความสำคัญมากเพราะเราสามารถกำหนดวิธีการแสดงผลส่วนของเทมเพลตและแท็กเทมเพลตเป็นพื้นฐานของวิธีที่เราใส่ตัวแปรลงในรหัสของเรา ตอนนี้เราต้องทำให้แอปของเราดูดีขึ้นเพราะตอนนี้มันดูธรรมดาจริงๆ เราสามารถทำได้โดยใช้ CSS ไม่ว่าจะเป็นแบบอินไลน์หรือในชั้นเรียนที่เชื่อมโยงกับแต่ละวัตถุในเอกสาร CSS ดีมากเพราะมันบอกทุกอย่างบนหน้าเว็บว่าควรมีลักษณะอย่างไรและสามารถทำให้มันดูดีจริงๆ มีห้องสมุดสองสามห้องที่สามารถทำได้ แต่ส่วนตัวของฉันไปที่ bootstrap Bootstrap สามารถดาวน์โหลดได้จากเว็บไซต์ของพวกเขาgetBootstrap.com/- เมื่อถึงที่นั่นให้กดปุ่มเพื่ออ่านเอกสารการติดตั้งและคัดลอกรหัสจากส่วนรวมผ่านส่วน CDN คุณจะต้องใช้รหัสนี้ที่ด้านบนของเอกสาร HTML ของคุณในแท็กที่เรียกว่า Head นอกจากนี้เราไปข้างหน้าและสร้างเทมเพลตพื้นฐานเพื่อให้เราไม่จำเป็นต้องสร้างลิงค์เหล่านี้ใหม่ในแต่ละเทมเพลต สร้างไดเรกทอรีใหม่ที่เรียกว่าเทมเพลตด้วยเทมเพลต mkdir จากนั้นแก้ไขเทมเพลต/base.html ควรมีลักษณะเช่นนี้:
 
<!doctype HTML>
<html>
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
</head>
<body>
{% block body %}
{% endblock %}
</body>
</html>
 
ตรวจสอบให้แน่ใจว่าได้คัดลอกไฟล์ CSS และ JavaScript ไฟล์. CSS และ. JS เพราะเราจะต้องใช้ JavaScript เพื่อให้ไซต์ของเราทำงานได้มากขึ้นในอนาคต ตอนนี้เรามากลับไปที่ Shell Bash และเรียกใช้คำสั่งอย่างรวดเร็ว โปรดจำไว้ว่าหากคุณต้องการเข้าถึงสภาพแวดล้อมเสมือนจริงให้พิมพ์แหล่งที่มาของ Venv/bin/เปิดใช้งาน สิ่งนี้จะช่วยให้คุณติดตั้งแพ็คเกจ Python ในเครื่องในแบบที่ช่วยให้ Django เข้าถึงได้ เพื่อให้แบบฟอร์มของเราสร้างขึ้นโดยคลาส Bootstrap Django เราจะใช้แพ็คเกจ Python ที่เรียกว่า Crispy Forms เราสามารถดาวน์โหลดสิ่งนี้ด้วยคำสั่งต่อไปนี้

pip install django-crispy-forms
เมื่อติดตั้งแล้วให้เพิ่มลงในการตั้งค่า PY

INSTALLED_APPS = [
    # …รหัสก่อนหน้านี้ที่นี่
    'crispy_forms',
]
ตอนนี้ย้อนกลับไปในเทมเพลตฟีดของเราเราสามารถลบบางสิ่งได้ ลองลบจุดเริ่มต้นและจุดสิ้นสุดของเอกสารและแทนที่ด้วยการสืบทอดจากเทมเพลตฐานของเราโดยใช้การขยายและคำจำกัดความของบล็อก นอกจากนี้เราจะเพิ่มการนำเข้าตัวกรองเทมเพลตด้วยโหลดและตัวกรองเทมเพลตลงในแบบฟอร์ม สุดท้ายเรามาเพิ่มคลาส bootstrap ลงในปุ่มบนแบบฟอร์มเพื่อให้ดูเหมือนปุ่มมากขึ้น ที่ควรมีลักษณะเช่นนี้:
 
{% extends 'base.html' %}
{% block body %}
{% load crispy_forms_tags %}
<form method=”POST”>
{% csrf_token %}
{{ form|crispy }}
<button type=”submit” class=”btn btn-outline-primary”>New Post</button>
</form>
<hr>
{% for post in posts %}
<p>{{ post.text }}</p>
{% endfor %}
{% endblock %}
 
สวย! นั่นเป็นรหัสที่ค่อนข้างน้อยแล้ว ต่อไปเราควรทดสอบมันและตรวจสอบให้แน่ใจว่าเราเห็นว่าทุกอย่างดูดีและตรวจสอบให้แน่ใจว่าทุกอย่างทำงานได้อย่างถูกต้อง เรียกใช้เซิร์ฟเวอร์ตามคำแนะนำก่อนหน้านี้และตรวจสอบให้แน่ใจว่าเว็บไซต์มีลักษณะและทำงานได้ดี เยี่ยมมาก! คุณพร้อมที่จะไปยังขั้นตอนต่อไปซึ่งเราจะเพิ่มฟังก์ชั่นการเข้าสู่ระบบของผู้ใช้โดยใช้ URL รูปแบบมุมมองและเทมเพลตที่คล้ายกัน เทมเพลตพื้นฐานมีความสำคัญและเราจะดำเนินการแก้ไขและทำการเปลี่ยนแปลงตามความจำเป็น แต่ตอนนี้เรามามุ่งเน้นไปที่การทำให้ไซต์ของเราปลอดภัยยิ่งขึ้นโดยช่วยให้ผู้ใช้สามารถเข้าสู่ระบบด้วยชื่อผู้ใช้และรหัสผ่านและในที่สุดข้อมูลที่สำคัญยิ่งกว่านั้น จะช่วยให้แอปของคุณปลอดภัยและบัญชีของคุณเองสามารถเข้าถึงได้โดยคุณเท่านั้น ในการทำเช่นนี้เราจะต้องใช้โมเดลผู้ใช้ที่สร้างขึ้นใน Django โมเดลผู้ใช้เป็นรูปแบบฐานข้อมูลเช่นโพสต์ของเราที่สามารถแสดงผลเพื่อบันทึกผู้ใช้ในเว็บไซต์ ในอนาคตก่อนที่เราจะปรับใช้เว็บไซต์ไปยังอินเทอร์เน็ตเราจะขยายโมเดลนี้ด้วยรุ่นอื่น ๆ ที่มาจากมันและสร้างมาตรการรักษาความปลอดภัยเพิ่มเติมสำหรับการเข้าสู่ระบบที่ทนต่อฟิชชิ่ง เราจะเริ่มต้นด้วยการใช้แบบฟอร์มการเข้าสู่ระบบในตัวที่ Django จัดเตรียมไว้ ก่อนอื่นมาสร้างแอพใหม่ที่เราจะใช้ในการแสดงเทมเพลตและมุมมองสำหรับหน้าเข้าสู่ระบบพื้นฐาน นอกจากนี้เรายังจะสร้างแอพอื่น ๆ เพื่อแสดงถึงความท้าทายในการเข้าสู่ระบบอย่างต่อเนื่องเพื่อรักษาความปลอดภัยแอพรวมถึงพินโหนดการจดจำใบหน้าใกล้การสื่อสารภาคสนามอุปกรณ์ภายนอกการตรวจสอบความถูกต้องหลายปัจจัยและการจดจำลายนิ้วมือ เราได้พูดคุยเกี่ยวกับการเริ่มต้นแอปแล้ว จากไดเรกทอรีของเราภายในสภาพแวดล้อมเสมือนจริงผ่านการจัดการ py เหล่านี้

python manage.py startapp users
ตอนนี้เราควรมีไดเรกทอรีสำหรับแอพใหม่ เริ่มต้นด้วยการสร้างมุมมองในไดเรกทอรีที่สอดคล้องกับการเข้าสู่ระบบของผู้ใช้ Django ได้สร้างมุมมองสำหรับการเข้าสู่ระบบของผู้ใช้ แต่สิ่งเหล่านี้จะไม่เหมาะสำหรับเราเพราะเราต้องการมุมมองที่กำหนดเองซึ่งทำได้โดยเฉพาะกับคำจำกัดความ ในมุมมองนี้เราจะเริ่มต้นด้วยการตรวจสอบคำขอโพสต์ส่งคำขอผ่านไปยังรูปแบบการเข้าสู่ระบบที่นำเข้าจาก Django ตรวจสอบบัญชีผู้ใช้และเข้าสู่ระบบผู้ใช้ก่อนที่จะเปลี่ยนเส้นทางไปยังแอพฟีดของเรา ในผู้ใช้/views.py เพิ่มรหัสต่อไปนี้

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

def login(request):
    if request.method == “POST”:
        username = request.POST['username'] # รับชื่อผู้ใช้และรหัสผ่านจากคำขอโพสต์
        password = request.POST['password'] # รับรองความถูกต้องของผู้ใช้
        user = authenticate(username=username, password=password)
        if user:
            auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
            messages.success(request, 'Your password was accepted. Please continue')
            return redirect(reverse('feed:feed'))
        else: messages.warning(request, 'Username or password incorrect. Please try again')
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
นี่คือทั้งหมดที่คุณต้องการสำหรับมุมมองการเข้าสู่ระบบพื้นฐาน ตอนนี้เรามาสร้างแบบฟอร์มสำหรับมุมมองโดยขยายเทมเพลตฐาน เราจะเริ่มต้นด้วยการสร้างไดเรกทอรีใหม่สำหรับเทมเพลตในโฟลเดอร์ผู้ใช้

mkdir users/templates
mkdir users/templates/users
ตอนนี้เราควรจะสามารถแก้ไขผู้ใช้/เทมเพลต/ผู้ใช้/เข้าสู่ระบบ html ได้ ในขณะที่เราอยู่ที่นี่เราจะสร้างเทมเพลตเพื่อให้ผู้ใช้สมัครใช้งานด้วย

nano users/templates/users/login.html
ตอนนี้ในเทมเพลต
 
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<form method="POST">
    {% csrf_token %}
    <fieldset class="form-group">
        <legend class="border-bottom mb-4 break">Log In</legend>
        {{ form|crispy }}
    </fieldset>
    <div class="form-group">
        <button class="btn btn-outline-info" type="submit">Login</button>
    </div>
</form>
{% endblock %}
 
นี่คือพื้นฐานของเทมเพลตการเข้าสู่ระบบ มันเหมือนกับเทมเพลตอื่น ๆ ในโครงสร้าง แต่มันดูแตกต่างกันเล็กน้อยเมื่อมันแสดงผล เราสามารถคัดลอกรหัสนี้เพื่อสร้างเทมเพลตที่คล้ายกันอื่น ๆ ที่เรียกว่า register.html ซึ่งเราจะเปลี่ยนถ้อยคำและใช้แบบฟอร์มใหม่ที่เราสร้าง มาสร้างเทมเพลตก่อน แก้ไขผู้ใช้/เทมเพลต/ผู้ใช้/register.html และเพิ่มรหัสต่อไปนี้:
 
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<form method="POST">
    {% csrf_token %}
    <fieldset class="form-group">
        <legend class="border-bottom mb-4 break">Create an account</legend>
        {{ form|crispy }}
    </fieldset>
    <div class="form-group">
        <button class="btn btn-outline-info" type="submit">Register</button>
    </div>
</form>
{% endblock %}
 
ตอนนี้เรามาสร้างแบบฟอร์มสำหรับการลงทะเบียนผู้ใช้ของเราและวงกลมกลับไปที่มุมมองก่อนที่เราจะอัปเกรดเข้าสู่ระบบผู้ใช้ของเราด้วยโมเดล เราจะทำให้แบบฟอร์มนี้เริ่มต้นด้วย แต่รวมรายละเอียดเพิ่มเติมและคุณสมบัติด้านความปลอดภัยเช่นข้อตกลงและ Captcha ในอนาคต แก้ไขแบบฟอร์มด้วยผู้ใช้ Nano/Forms.py และเพิ่มรหัสต่อไปนี้

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

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

    class Meta:
        model = User
        fields = ['username', 'email', 'password1', 'password2']
ดังนั้นเราจึงมีรูปแบบอื่นที่นี่ซึ่งใช้งานได้ง่าย เป็นแบบฟอร์มการลงทะเบียนผู้ใช้ที่มีชื่อผู้ใช้อีเมลและรหัสผ่านรวมถึงฟิลด์ยืนยันรหัสผ่าน โปรดทราบว่าแบบฟอร์มนี้ไม่ขยายรูปแบบปกติคลาสฟอร์มมันเป็นรูปแบบของแบบจำลองซึ่งหมายความว่ามันมีเมตา ฟิลด์หนึ่งถูกกำหนดให้เหมือนกันและเมตาคลาสจะกำหนดโมเดลแบบฟอร์มสอดคล้องกับส่วนที่เหลือของข้อมูลที่จะเขียนลงในแบบฟอร์ม ส่วนใหญ่มีอยู่แล้วใน UserCreationForm ที่สร้างขึ้นใน Django ดังนั้นเราจะใช้สิ่งนั้นเป็นพื้นฐานสำหรับชั้นเรียน (ผ่านในวงเล็บ) ต่อไปเราจะตรวจสอบมุมมองเพื่อลงทะเบียนผู้ใช้ตอนนี้เรามีแบบฟอร์มและเทมเพลต นี่คือ Modelform เช่นเดียวกับรูปแบบในมุมมองโพสต์ใหม่ แก้ไขผู้ใช้/views.py และเพิ่มรหัสต่อไปนี้:

# …จำนวนเงิน
from .forms import UserRegisterForm

def register(request):
    if request.method == “POST”:
        form = UserRegisterForm(request.POST)
        if form.is_valid():
            user = form.save()
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
นี่คือทั้งหมดที่เราต้องได้รับการลงทะเบียนผู้ใช้ แต่เราควรมีข้อมูลเพิ่มเติม เราต้องการทราบเวลาที่ผู้ใช้ลงทะเบียนเวลาที่พวกเขาอยู่ในเว็บไซต์ข้อมูลบางอย่างเกี่ยวกับพวกเขาเช่นชีวประวัติเขตเวลาและอื่น ๆ เราจะต้องอัปเดตโมเดลฟีดโพสต์เพื่อบัญชีสำหรับผู้ใช้ โมเดลและโพสต์แอตทริบิวต์ไปยังผู้ใช้แต่ละคน เพื่อที่จะทำเช่นนั้นเราจะอัปเดตโมเดล py ในทั้งสองแอพ เริ่มต้นด้วยการแก้ไขรูปแบบฟีด ตอนนี้ควรมีลักษณะเช่นนี้:

from django.db import models # …จำนวนเงิน
from django.contrib.auth.models import User

class Post(models.Model):
    id = models.AutoField(primary_key=True)
    author = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name='posts') # เพิ่มในบรรทัดนี้
    text = models.TextField(default='')
ให้ความสนใจกับบรรทัดที่สองที่เพิ่มเข้าไปในไฟล์ นี่คือคีย์ต่างประเทศซึ่งจะให้คุณสมบัติแต่ละโพสต์ไปยังผู้ใช้รายเดียวต่อโพสต์ดังนั้นเราจึงสามารถตรวจสอบให้แน่ใจว่าเราบันทึกโพสต์บนพื้นฐานของผู้ใช้ต่อผู้ใช้และไม่สามารถโพสต์ได้โดยไม่ต้องนำมาประกอบกับผู้ใช้ เรากำหนดคีย์ต่างประเทศนี้ด้วยคลาสที่แสดงถึงอาร์กิวเมนต์ลบเพื่อให้แน่ใจว่าโพสต์จะถูกลบด้วยผู้ใช้อาร์กิวเมนต์ว่างและว่างเปล่าเพื่อให้แน่ใจว่าเราสามารถลบผู้ใช้ได้หากจำเป็นและเพื่อรองรับการขาดผู้ใช้ในโพสต์ที่เราอยู่แล้ว สร้างขึ้นและชื่อที่เกี่ยวข้องซึ่งเราสามารถใช้เพื่ออ้างถึงวัตถุโพสต์ที่ผู้ใช้สร้างขึ้น ชื่อที่เกี่ยวข้องนี้ซึ่งแตกต่างจาก Post.Author ผู้แต่งโพสต์ให้ผู้ใช้ที่โพสต์โพสต์ ตอนนี้เราสามารถรับโพสต์ที่ผู้ใช้ทำโดยการเรียกใช้ user.posts.All () หรือผู้แต่ง. posts.All () ตอนนี้มาทำให้การเข้าสู่ระบบของเรามีความยืดหยุ่นมากขึ้น เราสามารถทำให้ไซต์ของเรามีความเสี่ยงน้อยกว่าฟิชชิ่งโดยเพียงแค่ให้คะแนน จำกัด จำนวนครั้งที่เราจะอนุญาตให้เข้าสู่ระบบไซต์นี้ค่อนข้างง่าย มาเริ่มเก็บข้อมูลบางอย่างเกี่ยวกับผู้ใช้แต่ละคนก่อนที่เราจะพัฒนาแอพของเราต่อไป การแก้ไขผู้ใช้/models.py เพิ่มสิ่งต่อไปนี้

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

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True, related_name='profile')
    account_created = models.DateTimeField(default=timezone.now)
    last_seen = models.DateTimeField(default=timezone.now)
    can_login = models.DateTimeField(default=timezone.now)
    preferred_name = models.CharField(max_length=20,default='', null=True, blank=True)
    bio = models.TextField(blank=True, default='')
โปรดทราบว่ารุ่นนี้ค่อนข้างคล้ายกับโมเดลโพสต์ เรามีการนำเข้าเขตเวลาเพิ่มเติมซึ่งจะช่วยให้เราตั้งค่าเริ่มต้นในฟิลด์ DateTime และเรายังมีตัวละครและฟิลด์ข้อความเช่นโพสต์ การใช้การประทับเวลาทั้งหมดเหล่านี้ช่วยให้เรารักษาความปลอดภัยเว็บไซต์และเข้าใจการใช้งานและฟิลด์ข้อความให้เราแสดงข้อมูลเกี่ยวกับผู้ใช้แต่ละคนหรือผู้แต่งบนเว็บไซต์ Onetoonefield ควรเป็นเพียงการพิจารณาเพียงเล็กน้อยเท่านั้นมันจะทำงานได้เหมือนกันกับ Foreeginkey แต่มีเพียงหนึ่งเดียวต่อรุ่นที่ตามมา ด้วยวิธีนี้ผู้ใช้มีโปรไฟล์เดียวเท่านั้นในขณะที่พวกเขาอาจมีโพสต์มากมาย ตอนนี้เรามาปรับปรุงการเข้าสู่ระบบของเราและลงทะเบียนมุมมองเพื่อบัญชีสำหรับโปรไฟล์ ขั้นแรกให้แก้ไขผู้ใช้/views.py และมุ่งเน้นไปที่มุมมองการลงทะเบียน:

# …จำนวนเงิน
from .forms import UserRegisterForm

def register(request):
    if request.method == “POST”:
        form = UserRegisterForm(request.POST)
        if form.is_valid():
            user = form.save()
            Profile.objects.create(user=user) # ตรวจสอบให้แน่ใจว่าได้เพิ่มบรรทัดนี้เพื่อสร้างโปรไฟล์สำหรับผู้ใช้
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
สิ่งนี้เพียงสร้างโปรไฟล์สำหรับผู้ใช้โดยไม่ต้องกรอกข้อมูลใด ๆ ตอนนี้เราต้องการให้แน่ใจว่าบัญชีผู้ใช้ไม่สามารถลงชื่อเข้าใช้บ่อยเกินไปหรืออย่างน้อยก็ไม่สามารถลองใช้รหัสผ่านได้บ่อยเกินไปดังนั้นเรามาอัปเดตมุมมองการเข้าสู่ระบบ

# …จำนวนเงิน
from .models import Profile
from django.utils import timezone
import datetime

def login(request):
    if request.method == “POST”:
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(username=username, password=password)
        if user and user.profile.can_login < timezone.now(): # โปรดทราบว่าตอนนี้เราตรวจสอบว่าผู้ใช้สามารถเข้าสู่ระบบได้หรือไม่
            auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
            messages.success(request, 'Your password was accepted. Please continue.')
            return redirect(reverse('feed:feed'))
        else: # หากการเข้าสู่ระบบไม่ประสบความสำเร็จ
            messages.warning(request, 'Username or password incorrect. Please try again.')
            user = User.objects.filter(username=username).first() # นี่คือส่วนที่เราอัปเดตโปรไฟล์ผู้ใช้
            if user: 
                profile = user.profile
                profile.can_login = timezone.now() + datetime.timedelta(seconds=15) # ดังนั้นพวกเขาจึงไม่สามารถเข้าสู่ระบบได้อีกสองสามวินาที
                profile.save()
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
นี่คือพื้นฐานพื้นฐานของความปลอดภัย ตรวจสอบให้แน่ใจว่าไซต์นั้นไม่เสี่ยงต่อใครบางคนเพียงแค่ลองรวมรหัสผ่านที่เป็นไปได้ทุกครั้งหรือแม้แต่บางส่วนในเวลาเดียวกัน สิ่งนี้จะไม่น่าหงุดหงิดกับผู้ใช้ทั่วไปที่รู้รหัสผ่านของพวกเขาและเพียงแค่ลงชื่อเข้าใช้ในอุปกรณ์สองสามตัว แต่มันจะทำให้หุ่นยนต์ฟิชชิ่งจำนวนมากออกจากแอพ โปรดทราบว่าเราได้เพิ่มคำสั่ง IF ด้วยตัวแปร CAN_LOGIN ซึ่งควรเป็นเวลาในอดีตและอัปเดตด้วยการเข้าสู่ระบบที่ไม่ประสบความสำเร็จแต่ละครั้งโดยใช้ชื่อผู้ใช้เดียวกัน ด้วยวิธีนี้ผู้ใช้ที่เป็นอันตรายจะไม่สามารถเดารหัสผ่านได้ทุกที่ใกล้เร็ว จำนวนวินาทีใน datetime.timedelta () สามารถอัปเดตได้เช่นกันและเว็บไซต์จะมีความยืดหยุ่นมากขึ้น แต่ใช้งานได้น้อยกว่าเล็กน้อยในไม่กี่วินาที ฉันแนะนำ 15 เพื่อเริ่มต้นด้วย โปรดจำไว้ว่าเราสร้างสคริปต์สำรองเพื่อบันทึกงานของเราดังนั้นขอไปข้างหน้าและสำรองสิ่งที่เรามีจนถึงตอนนี้เพื่อให้แน่ใจว่าเราได้บันทึกทุกอย่าง เรียกใช้คำสั่ง:

sudo backup
อีกครั้งสิ่งนี้จะช่วยงานของคุณจนถึงตอนนี้ ฉันขอแนะนำให้ใช้การสำรองข้อมูลบ่อยครั้งเพื่อบันทึกงานของคุณและคุณอาจต้องการเรียกใช้งานสำรองโดยอัตโนมัติ คุณสามารถทำได้โดยใช้ยูทิลิตี้ Unix ที่เรียกว่า cron ในการเปิดใช้งานยูทิลิตี้นี้ให้เรียกใช้คำสั่งต่อไปนี้และป้อนรหัสผ่านของคุณ:

sudo crontab -e
หากคุณยังไม่ได้เลือกตัวเลือก 1 สำหรับนาโนตัวแก้ไขข้อความที่คุณควรคุ้นเคยและเลื่อนไปที่ด้านล่างของไฟล์โดยใช้ปุ่มลูกศร เพิ่มบรรทัดต่อไปนี้:

0 * * * * sudo backup
Cron ใช้รูปแบบนาทีชั่วโมงวันเดือนเดือนวันของสัปดาห์โดยที่ A * หรือตัวเลขแสดงถึงเวลาที่จะเรียกใช้คำสั่ง ใช้ 0 สำหรับนาทีและ * สำหรับตัวเลือกที่เหลือเราสามารถเรียกใช้คำสั่งในนาทีแรกของทุกชั่วโมงในช่วงเริ่มต้นของนาที สิ่งนี้ช่วยให้เราสำรองรหัสโดยอัตโนมัติ งานทั้งหมดของ Cron เมื่อดำเนินการกับ sudo run เป็นรูทดังนั้นเราไม่จำเป็นต้องพิมพ์รหัสผ่านทุกชั่วโมง เพื่อให้ง่ายต่อการสำรองข้อมูลรหัสของเราโดยไม่ต้องใช้รหัสผ่านให้ปิดการใช้งานรหัสผ่านสำหรับคำสั่งสำรองของเรา เราจะทำสิ่งนี้โดยดำเนินการคำสั่งต่อไปนี้และป้อนรหัสผ่าน:

sudo visudo
ทีนี้ลองเลื่อนไปที่ด้านล่างของไฟล์แล้วเพิ่มบรรทัดอื่น:

ALL ALL=NOPASSWD: /bin/backup
สิ่งนี้ช่วยให้เราเรียกใช้คำสั่ง“ สำรองข้อมูล” เป็นผู้ใช้ใด ๆ โดยไม่มีรหัสผ่าน รูปแบบสำหรับสิ่งนี้เป็นเรื่องง่ายเพียงแค่นำหน้าด้วย“ all all = nopasswd:/bin/” และจบด้วยคำสั่งตัวอย่างเช่น/bin/backup ซึ่งมีอยู่ใน/usr/bin/ ตอนนี้มาเริ่มทำงานกับอีเมล อีเมลมีความสำคัญอย่างยิ่งสำหรับเว็บไซต์เพราะเป็นวิธีที่จะทำให้เว็บไซต์ปลอดภัยยิ่งขึ้นตรวจสอบว่าผู้ใช้เป็นคนจริงและแม้กระทั่งผลิตภัณฑ์ตลาดหรือบริการให้กับลูกค้า หลายคนที่ใช้อินเทอร์เน็ตตรวจสอบอีเมลทุกวันและรับอีเมลการตลาดทุกประเภทเกี่ยวกับผลิตภัณฑ์และบริการที่พวกเขาสนใจมีตัวเลือกเล็กน้อยเมื่อมันมาถึงการเปิดใช้งานอีเมลบนเว็บไซต์ Django และคุณสามารถเลือกได้ ไม่ว่าจะเป็นแบบไหนที่ดีที่สุดสำหรับคุณ ก่อนอื่นคุณสามารถชำระเงินสำหรับบริการอีเมลที่จะช่วยให้คุณสามารถส่งอีเมลจากโดเมนของคุณและต้องใช้รหัสน้อยที่สุด มีบริการมากมายที่เสนอสิ่งนี้เช่น Google Workspace, SendinBlue, MailGun และอื่น ๆ มิฉะนั้นคุณจะออกจากอาคารได้ดีบริการอีเมลของคุณเองภายในเซิร์ฟเวอร์ของคุณตั้งแต่เริ่มต้น ฉันแนะนำตัวเลือกนี้แม้ว่าจะเป็นรหัสมากขึ้นและอาจต้องใช้โฮสติ้งพิเศษ คุณจะไม่สามารถเริ่มต้นเซิร์ฟเวอร์เมลจากคอมพิวเตอร์ที่บ้านของคุณได้มากที่สุดดังนั้นลองไปข้างหน้าและตรวจสอบการกำหนดค่าและรหัสเพื่อส่งอีเมลก่อนที่เราจะเริ่มเซิร์ฟเวอร์ในคลาวด์และสร้างเซิร์ฟเวอร์เมลของเราเองภายใน ก่อนอื่นแก้ไขการตั้งค่า py ด้วยสิ่งต่อไปนี้

nano app/settings.py
แอพคือชื่อของแอพที่คุณสร้างด้วย StartApp เพิ่มบรรทัดต่อไปนี้:

SITE_NAME = 'Django App'

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'localhost'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_ADDRESS = username@server.com'
EMAIL_HOST_USER = 'username'
EMAIL_HOST_PASSWORD = config['EMAIL_HOST_PASSWORD']
DEFAULT_FROM_EMAIL = '{} <{}>'.format(SITE_NAME, EMAIL_HOST_USER)
ตรวจสอบให้แน่ใจว่าได้เปลี่ยนสิ่งเหล่านี้เมื่อคุณพร้อมที่จะปรับใช้แอปของคุณเราจะกลับมาอีกครั้งในภายหลัง การตั้งค่า email_address ควรเป็นอีเมลที่คุณต้องการส่งจากและรหัสผ่าน (email_host_password) ควรตั้งค่าเป็นรหัสผ่านที่คุณสร้างขึ้นสำหรับเซิร์ฟเวอร์ ฉันโหลดรหัสผ่านจากไฟล์กำหนดค่าเพื่อป้องกันไม่

import os
import json
with open('/etc/config.json') as config_file:
    config = json.load(config_file)
จากนั้นฉันได้ตั้งค่าไฟล์ JSON ด้วย config in /etc/config.json โดยใช้ nano ดังนี้ ในการแก้ไขไฟล์:

sudo nano /etc/config.json
เพิ่มบรรทัดต่อไปนี้:

{
	“EMAIL_HOST_PASSWORD”: “<some password here>”
}
เราจะแก้ไขไฟล์กำหนดค่าต่อไปและเพิ่มรหัสผ่านและคีย์ทั้งหมดที่เราจะใช้ในแอพ สำหรับตอนนี้เรามาตรวจสอบวิธีส่งอีเมลอย่างรวดเร็วโดยใช้ Python ก่อนอื่นมาสร้างเทมเพลตสำหรับอีเมลยืนยันที่เราสามารถส่งไปยังผู้ใช้ของเราและใส่ไว้ในไดเรกทอรีเทมเพลตผู้ใช้ เทมเพลตนี้จะเขียนใน HTML

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

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

<p>The link will expire in 30 minutes.</p>
<p>If you have not requested a verification email you can simply ignore this email.</p>
<p>See you there,</p>
<p>Daisy</p>
 
อีเมลนี้ค่อนข้างง่าย ต้องใช้บริบทของผู้ใช้ URL พื้นฐานสำหรับเว็บไซต์และ ID ผู้ใช้และโทเค็นที่ใช้ในการตรวจสอบอีเมลของผู้ใช้ ตรวจสอบให้แน่ใจว่าได้กำหนด URL พื้นฐานในการตั้งค่า py ก่อนที่เราจะเขียนรหัส Python เพื่อแสดงเทมเพลต ไปข้างหน้าและเพิ่มบรรทัดต่อไปนี้ลงในแอพ/การตั้งค่า py ใกล้จุดเริ่มต้น

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

BASE_URL = PROTOCOL + '://' + DOMAIN
ในที่สุดเมื่อไซต์ของคุณพร้อมสำหรับอินเทอร์เน็ตและคุณปรับใช้คุณจะต้องกำหนดโดเมนของคุณเป็นชื่อโดเมนที่คุณซื้อเพื่อเป็นตัวแทนของเว็บไซต์ นี่คือชื่อที่คุณจะพิมพ์ใน Navbar เพื่อเข้าถึงเว็บไซต์ของคุณ สำหรับตอนนี้คุณสามารถปล่อยให้โดเมนว่างเปล่าหรือใช้ตัวยึดตำแหน่ง คุณจะต้องเปลี่ยน site_name เป็นชื่อที่คุณต้องการให้ไซต์ของคุณเลือก ก่อนที่เราจะส่งอีเมลลองสร้างเครื่องกำเนิดโทเค็นเพื่อให้เราสามารถมีโทเค็นการเปิดใช้งานบัญชีที่ไม่เคยหมดอายุ เราสามารถทำได้โดยการสร้างและนำเข้าโทเค็นการเปิดใช้งานบัญชีที่ดูเหมือนต่อไปนี้ แก้ไขไฟล์:

nano users/tokens.py
เพิ่มรหัสต่อไปนี้:

from django.contrib.auth.tokens import PasswordResetTokenGenerator
import six
class TokenGenerator(PasswordResetTokenGenerator):
    def _make_hash_value(self, user, timestamp):
        return (
            six.text_type(user.pk) + six.text_type(timestamp)
        )
account_activation_token = TokenGenerator()
unsubscribe_token = TokenGenerator()
เครื่องกำเนิดโทเค็นพื้นฐานนี้สร้างโทเค็นที่เราสามารถส่งผู้ใช้ใน URL และผู้ใช้สามารถใช้เพื่อยืนยันอีเมลและเปิดใช้งานบัญชีของพวกเขา ต่อไปเรามาดูวิธีส่งอีเมล การใช้ Nano, แก้ไขผู้ใช้/email.py

nano users/email.py
การส่งอีเมลการตรวจสอบ HTML จะเป็นแบบนี้:

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

def send_verification_email(user):
    User = get_user_model()
    mail_subject = '[{}] Activate your account.'.format(settings.SITE_NAME)
    html_message = render_to_string('users/verification_email.html', {
        'user': user,
        'domain': settings.DOMAIN,
        'protocol': 'https',
        'uid': urlsafe_base64_encode(force_bytes(user.pk)),
        'token': account_activation_token.make_token(user),
    })
    send_html_email(user, mail_subject, html_message)
นี่ค่อนข้างง่าย เรานำเข้าฟังก์ชั่นที่เราต้องส่งอีเมลแสดงอีเมลด้วยเทมเพลตและการตั้งค่าของเราจากนั้นเรากำหนดอีเมลด้วยชื่อเทมเพลตและส่งไปยังผู้ใช้โดยใช้ฟังก์ชั่น คุณจะสังเกตเห็นว่าเรายังไม่ได้กำหนดฟังก์ชั่นเพื่อส่งอีเมล send_html_email แต่ลองเขียนสิ่งนี้ด้านล่างรหัสที่เราเพิ่มไปยังผู้ใช้/email.py

def send_html_email(user, mail_subject, html_message):
    to_email = user.email
    username = user.username
    if to_email == '':
        return None
    unsub_link = settings.BASE_URL + user.profile.create_unsubscribe_link()
    html_message = html_message + "<p><a href=\"" + unsub_link +  "\" + title=\"Unsubscribe from " + settings.SITE_NAME + " emails\">Unsubscribe</a></p></body></html>"
    msg = EmailMultiAlternatives(mail_subject, strip_tags(html_message), settings.DEFAULT_FROM_EMAIL, [to_email], headers={'List-Unsubscribe' : '<' + unsub_link + '>'},)
    msg.attach_alternative(html_message, "text/html")
    profile = user.profile
    try:
        msg.send(fail_silently=False)
        if not profile.email_valid:
            profile.email_valid=True
            profile.save()
    except:
        profile.email_valid=False
        profile.save()
นี่ค่อนข้างซับซ้อนและเรายังไม่พร้อมที่จะเรียกใช้รหัสทั้งหมดนี้ ขอให้สังเกตว่าเรากำลังกำหนด UNSUB_LINK ลิงก์ที่ผู้ใช้สามารถใช้เพื่อยกเลิกการสมัครจากอีเมลของเรา นี่เป็นสิ่งสำคัญเนื่องจากผู้ใช้จะต้องไม่สามารถยกเลิกอีเมลของเราได้เว้นแต่ว่าพวกเขาต้องการเห็นพวกเขาได้ตลอดเวลา นอกจากนี้เรายังเพิ่มทางเลือกข้อความลงในข้อความของเราซึ่งเป็นข้อความ HTML ที่ถูกถอดออกจากแท็ก HTML สุดท้ายเราตรวจสอบว่าอีเมลที่ส่งหรือไม่และหากไม่เป็นเช่นนั้นเราจะทำเครื่องหมายในโปรไฟล์ของผู้ใช้ว่าอีเมลของพวกเขาไม่ถูกต้อง ลองย้ายกลับไปที่โมเดลผู้ใช้เพื่อให้เราสามารถทำให้ทั้งหมดนี้ทำงานได้ เราจำเป็นต้องกำหนดฟังก์ชั่นเพื่อสร้างลิงก์ไปยังการยกเลิกการสมัครและกำหนดฟิลด์บูลีนเพื่อทำเครื่องหมายว่าอีเมลของผู้ใช้ไม่ถูกต้อง ก่อนอื่นให้เพิ่มการนำเข้าต่อไปนี้ไปที่ด้านบนของผู้ใช้/models.py

nano users/models.py

# -
from django.core.signing import TimestampSigner, BadSignature, SignatureExpired
from django.urls import reverse
ถัดไปเรามาเพิ่มฟังก์ชั่นลงในโมเดลผู้ใช้เพื่อสร้างโทเค็นและตรวจสอบโทเค็นที่ใช้ในการเปิดใช้งานอีเมลรวมถึงฟิลด์เพื่อบันทึกว่าผู้ใช้จะได้รับจดหมายได้สำเร็จหรือไม่ ใน users/models.py อีกครั้งเพิ่มรหัสต่อไปนี้ในตอนท้ายของรุ่น (รหัสเยื้อง)

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

    def check_token(self, token):
        try:
            key = '%s:%s' % (self.user.username, token)
            TimestampSigner().unsign(key, max_age=60 * 60 * 24 * 30) # ใช้ได้กับ 30 วัน
        except (BadSignature, SignatureExpired):
            return False
        return True

    def create_unsubscribe_link(self):
        username, token = self.make_token().split(":", 1)
        return reverse('users:unsubscribe', kwargs={'username': username, 'token': token,})
นี่เป็นเรื่องง่ายพอสมควรเราใช้ TimestampSigner ซึ่งเป็นเครื่องมือการเข้ารหัสพื้นฐานเพื่อสร้างโทเค็นซึ่งจะหมดอายุหลังจากระยะเวลาหนึ่งและเรายังใช้ฟังก์ชั่นอื่นเพื่อตรวจสอบว่าถูกต้องหรือไม่ เราใช้โทเค็นเหล่านี้สองครั้งหนึ่งครั้งเพื่อตรวจสอบอีเมลและอีกครั้งสำหรับลิงก์ยกเลิกการสมัคร ตอนนี้เรามีสิ่งเหล่านี้งานสุดท้ายที่เราต้องทำคือในมุมมอง ภายในผู้ใช้/views.py มาเพิ่มมุมมองเพื่อตรวจสอบที่อยู่อีเมลและยกเลิกการสมัคร

nano users/views.py
ก่อนอื่นให้เพิ่มการนำเข้าต่อไปนี้ ฉันโยนเพิ่มอีกสองสามอย่างดังนั้นเราจะไม่ต้องนำเข้ารายการเพิ่มเติมอีกครั้งในภายหลัง

from django.contrib.auth import logout
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.models import User
from django.utils.encoding import force_str
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
import json
import requests
import datetime, traceback
from django.contrib import messages
from .models import Profile
from django.utils import timezone
from django.views.decorators.cache import never_cache
from .email import send_verification_email # ตรวจสอบให้แน่ใจว่าได้นำเข้าฟังก์ชั่นการส่งอีเมลยืนยัน
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.utils.decorators import method_decorator
from django.http import HttpResponseRedirect
from django.conf import settings
from django.utils import timezone
import datetime
import pytz
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
from django.contrib.auth.tokens import default_token_generator
from django.utils.http import urlsafe_base64_decode
from .tokens import account_activation_token
คุณอาจมีการนำเข้าเหล่านี้อยู่แล้ว แต่ก็ไม่เจ็บที่จะทำซ้ำ คุณจะต้องนำเข้าฟังก์ชั่นการส่งอีเมลยืนยันรวมถึง account_activation_token จากผู้ใช้ท็อคเก้นท่ามกลางการนำเข้าอื่น ๆ ตอนนี้ที่ด้านล่างของไฟล์เพิ่มรหัสต่อไปนี้:

def unsubscribe(request, username, token):
    user = get_object_or_404(User, username=username)
    if((request.user.is_authenticated and request.user == user) or user.profile.check_token(token)):
        # ยกเลิกการสมัครพวกเขา
        profile = user.profile
        profile.subscribed = False
        profile.save()
        return render(request, 'users/unsubscribe.html')
    # มิฉะนั้นเปลี่ยนเส้นทางไปยังหน้าเข้าสู่ระบบ
    messages.warning(request,f'Your unsubscribe link has expired. Please log in to unsubscribe.')
    next_url = reverse('users:unsubscribe', kwargs={'username': username, 'token': token,})
    return HttpResponseRedirect('%s?next=%s' % (reverse('login'), next_url))

def activate(request, uidb64, token):
    try:
        uid = force_str(urlsafe_base64_decode(uidb64))
        user = User.objects.get(pk=uid)
    except(TypeError, ValueError, OverflowError, User.DoesNotExist):
        user = None
    ip = get_client_ip(request)
    if user is not None and account_activation_token.check_token(user, token):
        user.profile.email_verified = True
        user.profile.save()
        user.save()
# SendWelcomeEmail (คำขอผู้ใช้)
        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})
นี่คือรหัสจำนวนมาก มาทำลายมันลง ฟังก์ชั่นแรกสะอาดและเรียบง่ายยกเลิกการสมัครผู้ใช้จากรายชื่อผู้รับจดหมาย ฟังก์ชั่นที่สองเปิดใช้งานอีเมลของพวกเขาและคุณจะสังเกตเห็นว่าฉันเพิ่มฟังก์ชั่นความคิดเห็น SendWelcomeEmail คุณสามารถใช้เทมเพลตอีเมลและนิยามฟังก์ชั่นเพื่อส่งอีเมลต้อนรับฉันยังไม่ได้ ฟังก์ชั่นสุดท้ายที่ฉันโยนเข้ามาเป็นสิ่งสำคัญเนื่องจากอีเมลเปิดใช้งานหมดอายุ ดังนั้นเราจะต้องส่งอีเมลเปิดใช้งานอีกครั้ง เราสามารถใช้แบบฟอร์มพื้นฐานสำหรับสิ่งนี้และเรียกใช้ฟังก์ชั่นเพื่อส่งอีเมลยืนยัน ก่อนที่เราจะทำเช่นนี้มาตรวจสอบให้แน่ใจว่าได้รับการส่งตั้งแต่แรกโดยเพิ่มการเรียกใช้ฟังก์ชันไปยังมุมมองการลงทะเบียน เพิ่มบรรทัดนี้ก่อนการเปลี่ยนเส้นทางในมุมมองการลงทะเบียน, DEF register, ในผู้ใช้/views.py

nano users/views.py

# … (หลังจาก) def register (คำขอ):
            send_verification_email(user)
# … (ก่อน) เปลี่ยนเส้นทาง (
คุณไม่จำเป็นต้องเพิ่มบรรทัดแรกและบรรทัดสุดท้ายในตัวอย่างรหัสนั้นเพียงตรวจสอบให้แน่ใจว่ามุมมองการลงทะเบียนส่งอีเมลยืนยันไปยังผู้ใช้ ควรมีลักษณะเช่นนี้:

# …จำนวนเงิน
from .forms import UserRegisterForm

def register(request):
    if request.method == “POST”:
        form = UserRegisterForm(request.POST)
        if form.is_valid():
            user = form.save()
            send_verification_email(user) # ตรวจสอบให้แน่ใจว่าได้เพิ่มบรรทัดนี้!
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
ตอนนี้เราจะต้องเพิ่มแบบฟอร์มเพื่อส่งอีเมลเปิดใช้งานอีกครั้ง ในผู้ใช้/แบบฟอร์มเพิ่มแบบฟอร์มต่อไปนี้:

# … (จำนวน)
class ResendActivationEmailForm(forms.Form):
    email = forms.EmailField(required=True)
นอกจากนี้เรายังต้องการเทมเพลตที่สอดคล้องกับแบบฟอร์มการเปิดใช้งานอีเมลที่ส่งกลับนี้ มาเพิ่มเทมเพลตนี้ในการแก้ไขไฟล์:

nano users/templates/users/resend_activation.html
ถัดไปเพิ่มรหัสต่อไปนี้ลงในไฟล์

{% extends 'base.html' %}
{% block content %}
{% load crispy_forms_tags %}
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Resend activation email</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-secondary" type="submit">Resend activation email</button>
            </div>
        </form>
{% endblock %}
ว้าวนั่นเยอะมาก! ตอนนี้เมื่อเราปรับใช้รหัสไปยังเซิร์ฟเวอร์ของเราเราจะสามารถส่งอีเมล HTML และเปิดใช้งานบัญชีผู้ใช้ด้วยการคลิกในอีเมล นอกจากนี้เรายังอาจต้องการส่งอีเมลต้อนรับอย่างง่าย ๆ ดังนั้นมาดูกันว่าจะทำอย่างไร ย้อนกลับไปใน users/email.py เพิ่มรหัสต่อไปนี้:

def sendwelcomeemail(user):
    User = get_user_model()
    html = open('{}/users/welcome_email.html'.format(settings.BASE_DIR)).read()
    subject = 'Welcome to ' + settings.SITE_NAME + ', {{ username }}!'
    template = Template(html)
    subjtemplate = Template(subject)
    context = Context({'username': user.username, 'base_url': settings.BASE_URL, 'model_name': 'Daisy Holton, 'site_name': settings.SITE_NAME})
    renderedtemplate = template.render(context)
    subjcontext = Context({'username': user.username})
    subjrenderedtemplate = subjtemplate.render(subjcontext)
    send_html_email(user, subjrenderedtemplate, renderedtemplate)
นอกจากนี้เราจะต้องมีแม่แบบเพื่อแสดงข้อมูลทั้งหมดนี้ บนเว็บไซต์ของฉันเทมเพลตดูเหมือนด้านล่าง แต่คุณสามารถจัดรูปแบบได้ตามที่คุณต้องการ
 
<html>
<body>
<h3>Welcome to {{ site_name }}</h3>
<p>Hello {{ username }},</p>
<p>We are happy to see you here! Thank you for joining {{ site_name }} and being a part of the fun. To get started, here are a few things you can do after you verify your identity.</p>
<ol>
    <li><a href="{{ base_url }}/" title="Use the app">Use the app</a>. This is the main page of {{ site_name }}</li>
    <li><a href="{{ base_url }}/feed/profile/Clementine/" title="See my profile">Visit my private {{ site_name }} profile</a>. This is a page for anyone wanting to get to know me.</li>
    <li><a href="{{ base_url }}/feed/profiles/" title="See all profiles currently on the site">More profiles</a>. You can find these people on the site, and see their content.</li>
    <li><a href="{{ base_url }}/feed/all/" title="See everything on {{ site_name }}">See all posts here</a>. This is the private front page of {{ site_name }}.</li>
</ol>
<p>There is even more on the site, so feel free to visit and see what you find. You can share the site with any of the social buttons on each page. I hope you enjoy your time with {{ site_name }}! Thanks for being here.</p>
<p>With much love,</p>
<p>{{ model_name }}</p>
<a href="{{ base_url }}" title="{{ site_name }}">{{ base_url }}</a>
 
โปรดทราบว่าเราไม่มีแท็กปิดร่างกายหรือแท็ก HTML เพราะเราเพิ่มสิ่งเหล่านี้เมื่อเราเพิ่มลิงค์ HTML ยกเลิกการสมัคร สิ่งเหล่านี้มีความสำคัญ แต่เราไม่ต้องการกำหนดสองครั้ง แล้วอะไรต่อไป? เรามาไกล จริงๆแล้วเราควรพร้อมที่จะปรับใช้ไซต์ไปยังเซิร์ฟเวอร์ เราสามารถเพิ่ม @Login_Required Decorator และทำให้มุมมองของเราปลอดภัยใช้การสมัครใช้งานผู้ใช้ส่งอีเมลที่สอดคล้องและข้อมูลแคชซึ่งเป็นพื้นฐานของสิ่งที่เว็บไซต์ต้องทำเพื่อให้มีความเกี่ยวข้อง เราจะเพิ่มคุณสมบัติที่มีประโยชน์อีกสองสามอย่างจากนั้นสร้างพื้นฐานสำหรับการปรับใช้รหัสของเราไปยังเซิร์ฟเวอร์ระยะไกลตั้งค่าเซิร์ฟเวอร์เมลการกำหนดค่าโดเมนและตัวกรองเพื่อให้ไซต์ของเราปลอดภัยและเหมาะสม นอกจากนี้เรายังต้องมีมุมมองรีเซ็ตรหัสผ่านดังนั้นเรามาเพิ่มอย่างรวดเร็วจริงๆ มุมมองการรีเซ็ตรหัสผ่านในตัวของ Django เสียในบางฟังก์ชั่น แต่เราจะดูวิธีการเขียนมุมมองของเราเองเทมเพลตอีเมลแบบฟอร์มและรูปแบบ URL นี่คือสิ่งที่มุมมองดูเหมือนว่าในผู้ใช้/views.py

# ... นำเข้า
from django.contrib.auth.tokens import default_token_generator
from django.contrib.auth.forms import SetPasswordForm
from django.utils.http import urlsafe_base64_decode

def password_reset(request, uidb64, token):
    user = get_object_or_404(User, id=urlsafe_base64_decode(uidb64))
    if request.method == 'POST':
        form = SetPasswordForm(user, request.POST)
        if form.is_valid() and default_token_generator.check_token(user, token):
            form.save()
            messages.success(request, 'Your password has been reset.')
        elif not form.is_valid():
            messages.warning(request, 'Your passwords do not match, or do not meet the requirements. Please try again.')
            return redirect(request.path)
        else:
            messages.warning(request, 'Your password reset link has expired. Please create a new one.')
        return redirect(reverse('users:login'))
    return render(request, 'users/password_reset_confirm.html', {
        'title': 'Reset your Password',
        'form': SetPasswordForm(user)
แบบฟอร์มนี้สร้างขึ้นใน Django แต่เราจะต้องมีเทมเพลตเพื่อยืนยันการรีเซ็ตรหัสผ่านผู้ใช้/แม่แบบ/ผู้ใช้/password_reset_confirm.html
 
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Reset Password</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-info" type="submit">Reset Password</button>
            </div>
        </form>
{% endblock content %}
 
นอกจากนี้เรายังมีเทมเพลตเพื่อส่งอีเมลรีเซ็ตรหัสผ่านด้วยรูปแบบง่าย ๆ ในผู้ใช้/แม่แบบ/ผู้ใช้/password_reset.html
 
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Reset Password</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-info" type="submit">Request Password Reset</button>
            </div>
        </form>
{% endblock content %}
 
เทมเพลตสำหรับอีเมลนั้นง่ายมันเป็นไฟล์ HTML พื้นฐานการแสดงผลลิงค์เพื่อรีเซ็ตรหัสผ่านในผู้ใช้/เทมเพลต/ผู้ใช้/password_reset_email.html Django จะตีความไฟล์นี้โดยอัตโนมัติ
 
<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>
 
เราจะต้องมีเทมเพลตอีกสองแบบ สิ่งแรกคือการยืนยันว่าอีเมลถูกส่งไปแล้ว มุมมองสำหรับสิ่งเหล่านี้อยู่ใน Django อยู่แล้วดังนั้นเราจึงจำเป็นต้องจัดการกับพวกเขาใน URLS.py เทมเพลตนี้อยู่ที่ผู้ใช้/แม่แบบ/ผู้ใช้/password_reset_done.html
 
{% extends 'base.html' %}
{% block content %}
  <div class="media-body">
    <div class="alert alert-info">
        An email has been sent with instructions to reset your password.
    </div>
  </div>
{% endblock content %}
 
และสุดท้ายเพื่อยืนยันว่าการรีเซ็ตรหัสผ่านเสร็จสมบูรณ์ผู้ใช้/เทมเพลต/ผู้ใช้/password_reset_complete.html
 
{% extends 'base.html' %}
{% block content %}
 <div class="media-body">
    <div class="alert alert-info">
        Your password has been set.
    </div>
    <a href="{% url 'users:login' %}">Sign In Here</a>
  </div>
{% endblock content %}
 
ตอนนี้เราต้องการรูปแบบ URL สำหรับมุมมองเหล่านี้ ในผู้ใช้/urls.py เพิ่มรูปแบบ URL ต่อไปนี้:

urlpatterns = [
    # ... URL ก่อนหน้านี้ที่นี่
    path('password-reset/',
         auth_views.PasswordResetView.as_view(
             template_name='users/password_reset.html',
             html_email_template_name='users/password_reset_html_email.html'
         ),
         name='password_reset'),
    path('password-reset/done/',
         auth_views.PasswordResetDoneView.as_view(
             template_name='users/password_reset_done.html'
         ),
         name='password_reset_done'),
    path('password-reset-confirm/<uidb64>/<token>/',
         auth_views.PasswordResetConfirmView.as_view(
             template_name='users/password_reset_confirm.html'
         ),
         name='password_reset_confirm'),
    path('password-reset-complete/',
         auth_views.PasswordResetCompleteView.as_view(
             template_name='users/password_reset_complete.html'
         ),
         name='password_reset_complete'),
]
เทมเพลตสี่แบบนั้นเยอะมาก! แต่ตอนนี้เรามั่นใจได้ว่าจะสามารถรีเซ็ตรหัสผ่านของผู้ใช้ได้ตลอดเวลาที่เราต้องการทั้งหมดจากเว็บเบราว์เซอร์ ฉันเข้าใจว่านี่เป็นรหัสจำนวนมาก หากดูเหมือนว่าเหนือหัวของคุณนิดหน่อยก็โอเค คุณจะปรับปรุงความเข้าใจของคุณจะดีขึ้นและคุณจะมีความสามารถมากขึ้นด้วยรหัสในไม่ช้า หากคุณหลงทางโดยสิ้นเชิงฉันขอแนะนำให้กลับมาที่ซอฟต์แวร์นี้ในภายหลังหลังจากทำงานเกี่ยวกับการเรียนรู้ด้วยตนเองเพื่อเขียนรหัสหลักสูตรออนไลน์ สิ่งเหล่านี้มักจะมีอิสระในการเริ่มต้นและจะแนะนำคุณผ่านทุกสิ่งที่คุณต้องการเพื่อให้ประสบความสำเร็จเมื่อคุณกลับมาที่โครงการนี้ หากคุณรู้สึกว่าคุณพร้อมที่จะดำเนินการต่ออ่านต่อไปเราจะครอบคลุมการปรับใช้รหัสของคุณกับเซิร์ฟเวอร์ระยะไกลและตั้งค่าเซิร์ฟเวอร์เมลรวมถึงการปรับใช้ของคุณโดยอัตโนมัติโดยใช้ BASH เพื่อให้คุณสามารถตั้งค่าโครงการใหม่ได้ตลอดเวลาด้วย คำสั่งง่ายๆสองสามคำ สิ่งสุดท้ายที่เราต้องทำก่อนที่จะปรับใช้กับเซิร์ฟเวอร์ระยะไกลคือทำให้ไซต์ของเราปลอดภัยขึ้นเล็กน้อย คุณโปรดสังเกตว่ามุมมองการเข้าสู่ระบบใช้ชื่อผู้ใช้และรหัสผ่านเท่านั้นและไม่มีการตรวจสอบความถูกต้องหลายปัจจัยหรือรหัสครั้งเดียว นี่คือการแก้ไขที่ง่ายและด้วยรหัสเดียวกันเราสามารถทำให้ไซต์ของเราส่งข้อความและแม้กระทั่งตอบสนองต่อข้อความที่ส่งไปยังเซิร์ฟเวอร์ ในการเริ่มต้นเราจะกลับเข้าไปในโมเดลผู้ใช้และเพิ่มผู้ลงนามการประทับเวลาที่จะเป็นตัวแทนของการเข้าสู่ระบบแต่ละครั้ง นอกจากนี้เรายังจะเพิ่มตัวระบุการหมุนที่ไม่ซ้ำกันให้กับโมเดลผู้ใช้ที่จะใช้เพื่อเพิ่มความปลอดภัยพิเศษให้กับการเข้าสู่ระบบของเรา การแก้ไขโมเดลผู้ใช้ผู้ใช้/รุ่น py เพิ่มสิ่งต่อไปนี้

from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
# ตรวจสอบให้แน่ใจว่าได้นำเข้า UUID, Timestamp Signer และ URL Generator (ย้อนกลับ)
import uuid
from django.core.signing import TimestampSigner, BadSignature, SignatureExpired
from django.urls import reverse

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True, related_name='profile')
    account_created = models.DateTimeField(default=timezone.now)
    last_seen = models.DateTimeField(default=timezone.now)
    can_login = models.DateTimeField(default=timezone.now)
    preferred_name = models.CharField(max_length=20,default='', null=True, blank=True)
    bio = models.TextField(blank=True, default='')
    # เพิ่มรหัสนี้ที่นี่
    uid = models.CharField(max_length=32, default=uuid.uuid4, null=True, blank=True)
    mfa_enabled = models.BooleanField(default=False)
    enable_mfa = models.BooleanField(default=False)
    phone_number = models.CharField(default='', null=True, blank=True, max_length=15)
    verification_code = models.CharField(default='', null=True, blank=True, max_length=15)
    verification_code_length = models.IntegerField(default=6)
    mfa_code_expires = models.DateTimeField(default=timezone.now)
    mfa_attempts = models.IntegerField(default=0)

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

    # และเพิ่มฟังก์ชั่นนี้
    def create_auth_url(self):
        username, token = self.make_auth_token().split(":", 1)
        return reverse('users:mfa', kwargs={'username': username, 'token': token,})

    def check_auth_token(self, token):
        try:
            key = '%s:%s' % (self.uid, token)
            TimestampSigner().unsign(key, max_age=60 * settings.AUTH_VALID_MINUTES) # ใช้ได้ 3 นาที
        except (BadSignature, SignatureExpired):
            return False
        return True
ตรวจสอบให้แน่ใจว่าผู้ใช้/โมเดลของคุณมีลักษณะเช่นนี้นอกเหนือจากความคิดเห็น (รหัสในบรรทัดที่มี #) การทำลายสิ่งนี้มันง่าย เรามีการนำเข้าไม่กี่ตัวผู้กำหนดเวลาซึ่งเป็นยูทิลิตี้เข้ารหัสที่สามารถสร้างรหัสที่ปลอดภัยและตรวจสอบเพื่อให้แน่ใจว่าถูกต้องใช้เพียงครั้งเดียวและไม่เก่ากว่าจำนวนวินาทีที่แน่นอน นอกจากนี้เรายังใช้ UUID ซึ่งเป็นตัวระบุที่ไม่ซ้ำกันซึ่งระบุผู้ใช้ของเราในการลงนามในโทเค็นและใน URL ที่โทเค็นถูกส่งไปยังผู้ใช้ เราจะใช้การเข้ารหัสพื้นฐานนี้เพื่อสร้างมุมมองการรับรองความถูกต้องสองปัจจัย ก่อนที่เราจะทำอย่างอื่นให้เรียกใช้การย้ายถิ่นเพื่อให้โมเดลผู้ใช้ของเราได้รับการอัปเดต ในไดเรกทอรีด้วย manage.py ให้เรียกใช้คำสั่งต่อไปนี้เพื่อสร้างและดำเนินการอพยพให้เสร็จสมบูรณ์

source venv/bin/activate
python manage.py makemigrations && python manage.py migrate
สิ่งนี้มีความสำคัญเนื่องจากทุกครั้งที่เราทำการเปลี่ยนแปลงโมเดลเราจะต้องสร้างตารางและอัปเดตฐานข้อมูลด้วยค่าเริ่มต้นก่อนที่เราจะสามารถใช้แบบจำลองได้จริง ต่อไปเรามาปรับปรุงมุมมองการเข้าสู่ระบบของเราเพื่อเปลี่ยนเส้นทางไปยังมุมมองการรับรองความถูกต้องรอง ในผู้ใช้/views.py ลบฟังก์ชั่นการเข้าสู่ระบบและเปลี่ยนเส้นทางไปยัง URL ที่เราเพิ่งสร้างในรุ่นผู้ใช้

# …นำเข้า

def login(request):
    if request.method == “POST”:
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(username=username, password=password)
        if user and user.profile.can_login < timezone.now(): # โปรดทราบว่าตอนนี้เราตรวจสอบว่าผู้ใช้สามารถเข้าสู่ระบบได้หรือไม่
            # ลบฟังก์ชั่น auth_login ที่อยู่ที่นี่
            messages.success(request, 'Your password was accepted. Please continue.')
            if user.profile.mfa_enabled:
                return redirect(user.profile.create_auth_url()) # หมายเหตุเราเปลี่ยนเส้นทางไปยัง URL ใหม่ที่นี่
            else: # หากผู้ใช้ไม่ได้ใช้การรับรองความถูกต้องแบบหลายปัจจัยเพียงเข้าสู่ระบบ
                auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
                return redirect('feed:feed')
        else: # หากการเข้าสู่ระบบไม่ประสบความสำเร็จ
            messages.warning(request, 'Username or password incorrect. Please try again.')
            user = User.objects.filter(username=username).first() # นี่คือส่วนที่เราอัปเดตโปรไฟล์ผู้ใช้
            if user: 
                profile = user.profile
                profile.can_login = timezone.now() + datetime.timedelta(seconds=15) # ดังนั้นพวกเขาจึงไม่สามารถเข้าสู่ระบบได้อีกสองสามวินาที
                profile.save()
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
ดังนั้นนี่จึงค่อนข้างง่ายตอนนี้เรามีวิธีเปลี่ยนเส้นทางไปยังมุมมองการรับรองความถูกต้องสองปัจจัยเมื่อเราสร้างมันขึ้นมา นอกจากนี้เรายังมีทางเลือกในกรณีที่ผู้ใช้ยังไม่ได้เพิ่มหมายเลขโทรศัพท์ เราจะเพิ่มมุมมองพื้นฐานเพื่อเพิ่มหมายเลขโทรศัพท์เร็ว ๆ นี้และเข้าสู่ระบบด้วยข้อความเร็ว ๆ นี้ ก่อนอื่นเราต้องการวิธีง่ายๆในการส่งข้อความจากรหัสของเรา ในการทำเช่นนี้เราสามารถเลือก API จำนวนหนึ่งได้ แต่สิ่งที่ง่ายที่สุดในความคิดของฉันคือ Twilio พวกเขายังเสนอราคาที่ดีสำหรับโครงการขนาดเล็กรวมถึงส่วนลดจำนวนมาก สร้างบัญชีบน twilio.com กรอกรายละเอียดบางอย่างเกี่ยวกับโครงการของคุณซื้อหมายเลขโทรศัพท์และคัดลอกปุ่ม API ของคุณไปยังการตั้งค่าของคุณ จากนั้นเพิ่มรหัสนี้ภายใต้ไฟล์ใหม่ผู้ใช้/sms.py

nano users/sms.py

# นำเข้าแพ็คเกจที่จำเป็นทั้งหมด
from django.utils import timezone
import random
import datetime
from django.conf import settings
from feed.middleware import get_current_request
from django.contrib import messages
import traceback

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

# รหัสนี้ส่งข้อความด้วย twilio
def send_text(target_phone, text):
    from twilio.rest import Client
    try:
        client = Client(account_sid, auth_token)
        if len(target_phone) >= 11:
            message = client.messages.create(
                to=target_phone,
                from_=source_phone,
                body=text)
    except:
        print(traceback.format_exc())

# ฟังก์ชั่นผู้ช่วยที่จะได้รับตัวเลขที่มีตัวเลขมากมาย
def get_num_length(num, length):
    n = ''
    for x in range(length):
        n = n + str(num)
    return int(n)

# ส่งข้อความเพื่อยืนยันผู้ใช้
def send_verification_text(user):
    length = user.profile.verification_code_length
    code = random.randint(get_num_length(1, length), get_num_length(9, length));
    user.profile.verification_code = code
    user.profile.mfa_code_expires = timezone.now() + datetime.timedelta(minutes=3)
    user.profile.save()
    send_user_text(user, "Your verification code for {} is {}".format(settings.SITE_NAME, str(code)))

# ส่งข้อความใด ๆ กับผู้ใช้ด้วยฟังก์ชั่นนี้
def send_user_text(user, text):
    send_text(user.profile.phone_number, text)

# ตรวจสอบรหัสด้วยฟังก์ชันนี้
def check_verification_code(user, code):
    user.profile.mfa_attempts += 1
    result = user.profile.verification_code != None and code != '' and user.profile.verification_code == code and user.profile.mfa_code_expires > timezone.now() and user.profile.mfa_attempts <= 3
    if user.profile.mfa_attempts < 3 and result:
        user.profile.verification_code_length = 6
    elif user.profile.mfa_attempts > 2 and not result:
        user.profile.verification_code_length = 8
    user.profile.save()
    return result

# ตรวจสอบเวลา
def check_verification_time(user):
    result = user.profile.mfa_code_expires > timezone.now()
    return result
ตรวจสอบให้แน่ใจว่าได้เปลี่ยนการตั้งค่าของคุณอย่างเหมาะสมเพิ่มบรรทัดเหล่านี้ด้วยปุ่มของคุณ:

# ตรวจสอบให้แน่ใจว่าได้คัดลอกสิ่งเหล่านี้จากแดชบอร์ด Twilio ของคุณ
TWILIO_ACCOUNT_SID = “<your sid>”
TWILIO_AUTH_TOKEN = “<your token>”
PHONE_NUMBER = “<your twilio phone number>”
SITE_NAME = “<Your site name>”
AUTH_VALID_MINUTES = 3 # จำนวนนาทีที่หน้า TFA ทำงานเมื่อมีการสร้างอินสแตนซ์
ก่อนอื่นเราจะต้องมีแบบฟอร์มสำหรับมุมมองการตรวจสอบความถูกต้องสองปัจจัยของเรา การแก้ไขผู้ใช้/แบบฟอร์มเพิ่มรหัสต่อไปนี้

# …จำนวนเงิน
from django import forms

# แบบฟอร์มสำหรับป้อนหมายเลขโทรศัพท์ของเรา
class PhoneNumberForm(forms.Form):
    phone_number = forms.RegexField(regex=r'^\+?1?\d{9,15}$', error_messages = {'invalid': "Phone number must be entered in the format: '+999999999'. Up to 15 digits is allowed."})
    def __init__(self, *args, **kwargs):
        super(PhoneNumberForm, self).__init__(*args, **kwargs)
        self.fields['phone_number'].label = phone_number_label

# แบบฟอร์มสำหรับการรับรองความถูกต้อง
class TfaForm(forms.Form):
    code = forms.IntegerField(required=False)
    def __init__(self, *args, **kwargs):
        super(TfaForm, self).__init__(*args, **kwargs)
        self.fields['code'].widget.attrs.update({'autocomplete': 'off'})
    help_texts = {
        'code': 'Please enter the six digit code after sending it to your phone with the button above.'
    }
ถัดไปเรามาสร้างมุมมองในผู้ใช้/views.py

# …จำนวนเงิน
from django.http import HttpResponseRedirect
from .forms import PhoneNumberForm, TfaForm

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

@login_required
def mfa_onboarding(request):
    if request.method == 'POST':
        form = PhoneNumberForm(request.POST)
        request.user.profile.phone_number = form.data['phone_number'].replace('-', '').replace('(','').replace(')','')
        request.user.profile.mfa_enabled = True
        request.user.profile.enable_two_factor_authentication = True
        request.user.profile.save()
        messages.success(request, 'You have added a phone number to your account.')
        user = request.user
        return redirect(user.profile.create_auth_url())
    form = PhoneNumberForm(initial={'phone_number': request.user.profile.phone_number if request.user.profile.phone_number else '+1'})
    return render(request, 'users/mfa_onboarding.html', {'title': 'Enter your phone number', 'form': form, 'small': True})
เราจะต้องมีเทมเพลตสำหรับทั้งสองมุมมองนี้ มาเพิ่มเทมเพลต MFA ก่อน

nano users/templates/users/mfa.html
เพิ่มรหัส HTML นี้ลงในเทมเพลต
 
{% extends 'base.html' %}
{% block content %}
{% load app_filters %}
{% load crispy_forms_tags %}
        <form action="{{ request.path }}{% if request.GET.next %}?next={{ request.GET.next }}{% endif %}" method="POST">
            {% csrf_token %}
            <legend class="border-bottom mb-4">Enter Verification Code</legend>
            <p>Step 1: Send the code</p>
	    <i>Never share your code with anyone, as it can be used to access your account temporarily.</i>
	    <div class="form-group">
                <button class="btn btn-outline-primary" type="submit">Send code</button>
            </div>
	    <hr>
	    <p>Step 2: Enter the code</p>
            <fieldset class="form-group">
                {{ form|crispy }}
		<p>Press the enter button to send yourself the code at {{ user.profile.phone_number|securephone }}. Then, enter the code and press enter.</p>
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-secondary" type="submit">Enter code</button>
            </div>
        </form>
{% endblock %}
 
นี่เป็นคำอธิบายตัวเอง แบบฟอร์มส่งรหัสหรือรหัสว่างและคุณจะสังเกตเห็นในมุมมองที่เราส่งรหัสหากเราได้รับรหัสที่ว่างเปล่า จากนั้นเราก็มีปุ่มส่งสองปุ่มและวิธีนี้เราสามารถส่งรหัสด้วยปุ่มใดก็ได้ ต่อไปเราจะเพิ่มแบบฟอร์มง่ายๆเพื่อเพิ่มหมายเลขโทรศัพท์

nano users/templates/users/mfa_onboarding.html
เพิ่ม html ต่อไปนี้:
 
{% extends 'base.html' %}
{% block content %}
{% load crispy_forms_tags %}
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Set Up Two Factor Authentication</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-secondary" type="submit">Add phone number</button>
            </div>
        </form>
{% endblock %}
 
แบบฟอร์มนี้ง่ายกว่ามากเพียงแค่แสดงผลหมายเลขโทรศัพท์ที่เราสร้างขึ้นและให้ผู้ใช้เพิ่มหมายเลขโทรศัพท์ มันดูดีจริงๆ! ตราบใดที่ทุกอย่างถูกตั้งค่าอย่างเหมาะสมเราควรจะสามารถส่งข้อความและบันทึกผู้ใช้ด้วยหมายเลขโทรศัพท์ของพวกเขาทันทีที่เราเพิ่มรูปแบบ URL สิ่งสุดท้ายที่เราต้องตั้งค่าคือมุมมองโปรไฟล์เพื่อให้เราสามารถตรวจสอบให้แน่ใจว่าผู้ใช้สามารถเปลี่ยนหมายเลขโทรศัพท์ของพวกเขาโดยไม่ต้องเข้าสู่ระบบนอกจากนี้ในที่สุดเราจะต้องเพิ่มตัวเลือก“ หยุดเพื่อเลิก” เพื่อให้ผู้ใช้สามารถส่งข้อความ “ หยุด” เพื่อยกเลิกข้อความในอนาคต มาเพิ่มมุมมองโปรไฟล์ให้กับผู้ใช้/views.py มุมมองนี้จะอัปเดตประวัติผู้ใช้อีเมลชื่อผู้ใช้และหมายเลขโทรศัพท์ของผู้ใช้รวมถึงอนุญาตให้เราเปิดใช้งานการรับรองความถูกต้องหลายปัจจัย ก่อนอื่นเราจะต้องมีอีกสองรูปแบบในผู้ใช้/แบบฟอร์ม

# ... จำนวนเงิน
class UserUpdateForm(forms.ModelForm):
    email = forms.EmailField()
    class Meta:
        model = User
        fields = ['username', 'email']

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

class ProfileUpdateForm(forms.ModelForm):
    subscribed = forms.BooleanField(required=False)
    phone_number = forms.CharField(required=False)
    def __init__(self, *args, **kwargs):
        super(ProfileUpdateForm, self).__init__(*args, **kwargs)
    class Meta:
        model = Profile
        fields = ['bio', 'phone_number', 'enable_mfa', 'subscribed']
ต่อไปเราสามารถสร้างมุมมองเพื่อใช้ทั้งสองรูปแบบนี้ แก้ไขผู้ใช้/views.py และเพิ่มในมุมมอง

# เพิ่มการนำเข้าเหล่านี้
from .forms import UserUpdateForm, ProfileUpdateForm
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_exempt
from .models import Profile
from .mfa import send_user_text

@csrf_exempt
@never_cache
@login_required
def profile(request):
    if request.method == 'POST':
        u_form = UserUpdateForm(request.POST, instance=request.user)
        p_form = ProfileUpdateForm(request.POST,
                                       request.FILES,
                                       instance=request.user.profile)
        if u_form.is_valid() and p_form.is_valid():
            new_phone_number = p_form.data['phone_number']
            u_form.save()
            profile = p_form.save(commit=False)
            profile.phone_number = profile.phone_number.replace('-', '').replace('(','').replace(')','')
            profile.save()
            if new_phone_number != oldprofile.phone_number and oldprofile.phone_number and len(oldprofile.phone_number) >= 11:
                profile.mfa_enabled = True
                profile.save()
                send_text(oldprofile.phone_number, 'Your phone number has been updated to ' + new_phone_number + '. Please refer to texts on that phone to log in. If you didnt make this change, please call us. - {}'.format(settings.SITE_NAME))
            if profile.enable_two_factor_authentication and profile.phone_number and len(profile.phone_number) < 11:
                profile.enable_two_factor_authentication = False
                messages.success(request, f'Two factor authentication can\'t be activated without entering a phone number. Please enter a phone number to enable two factor authentication.')
            profile.save()
            if new_phone_number != oldprofile.phone_number and new_phone_number and len(new_phone_number) >= 11:
                send_user_text(request.user, 'You have added this number to {} for two factor authentication. You can now use your number for two factor authentication. If you didnt make this change, please call us. - {}'.format(settings.SITE_NAME, settings.DOMAIN))
                profile.mfa_enabled = True
                profile.mfa_code_expires = timezone.now() + datetime.timedelta(minutes=3)
                profile.save()
                return redirect(profile.create_auth_url())
            messages.success(request, f'Your profile has been updated!')
            print('Profile updated')
            return redirect('users:profile')
    else:
        u_form = UserUpdateForm(instance=request.user)
        p_form = ProfileUpdateForm(instance=request.user.profile, initial={'phone_number': request.user.profile.phone_number if request.user.profile.phone_number else '+1'})
    context = {
        'u_form': u_form,
        'p_form': p_form,
        'title':'Update Your Profile',
    }
    return render(request, 'users/profile.html', context)
เราจะต้องมีแม่แบบสำหรับมุมมองนี้

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

{% endblock content %}
{% block javascript %}
var form = document.getElementById('profile-form');
$('input').change(function(){
	var formdata = new FormData(form);
	$.ajax({
		url: window.location.href,
		type: "POST",
		data: formdata,
		processData: false,
		contentType: false,
		timeout: 1000 * 60,
                success: function(data) {
                  $(posted).removeClass("hide");
		  setTimeout(function() {
			$(posted).addClass("fade-hidden");
			setTimeout(function() {
				$(posted).addClass("hide");
				$(posted).removeClass("fade-hidden");
			}, 2000);
		  }, 2000);
                }
	});
});
{% endblock %}
 
คุณจะสังเกตเห็นว่านี่เป็นรูปแบบที่ค่อนข้างง่าย แต่มีจาวาสคริปต์อยู่บ้างที่โพสต์เนื้อหาของแบบฟอร์มโดยอัตโนมัติตามที่ได้รับการปรับปรุง สิ่งนี้มีประโยชน์ที่จะมีดังนั้นคุณสามารถแก้ไขได้โดยไม่ต้องกดส่งทุกครั้ง ต่อไปเราต้องการ URL ที่แสดงถึงมุมมองทั้งหมดเหล่านี้ใน URL ของผู้ใช้ patters แก้ไขผู้ใช้/urls.py และเพิ่มรหัสนี้:

# …รหัสก่อนหน้านำเข้า
from django.urls import path
from . import views

app_name='users'

urlpatterns = [
# …รูปแบบ URL ที่เราป้อนก่อนหน้านี้เพิ่มสามบรรทัดถัดไป
    path('mfa/<str:username>/<str:token>/', views.mfa, name='mfa'),
    path('mfa/onboarding/', views.mfa_onboarding, name='mfa_onboarding'),
    path('profile/', views.profile, name='profile'),
]
ตอนนี้เป็นเวลาที่ดีในการทดสอบโครงการของเรา แต่ก่อนอื่นเรามาทำการสำรองข้อมูลอีกครั้ง

backup
และเรียกใช้เซิร์ฟเวอร์ ก่อนที่เราจะปรับใช้กับเซิร์ฟเวอร์ Linux เป็นความคิดที่ดีที่จะเปิดใช้งานการรับรองความถูกต้องสองปัจจัยในบัญชี เราจะทำสิ่งนี้ไปที่ URL โปรไฟล์ของเรา/ผู้ใช้/โปรไฟล์/และทำเครื่องหมายในช่องเพื่อเปิดใช้งานการรับรองความถูกต้องหลังจากป้อนหมายเลขโทรศัพท์ของเราแล้วส่งแบบฟอร์ม

python manage.py runserver localhost:8000
เยี่ยมชมหน้าเว็บโดยไปที่เว็บเบราว์เซอร์ของคุณฉันใช้ Google Chrome ในตัวอย่างนี้และป้อน URL https: // localhost: 8000/บัญชี/โปรไฟล์/ คุณจะสามารถเข้าสู่ระบบได้หากจำเป็นและเปิดใช้งานการตรวจสอบสองปัจจัย โครงการนี้ต้องการเซิร์ฟเวอร์เพื่อทำงานเพื่อให้สามารถส่งจดหมายได้ แต่ก่อนอื่นเราต้องมีวิธีดูข้อผิดพลาด คุณจะสังเกตเห็นว่าหากคุณเรียกใช้เซิร์ฟเวอร์ในโหมดดีบักด้วยการตั้งค่า debug เท่ากับจริงเซิร์ฟเวอร์จะแสดงข้อผิดพลาดโดยอัตโนมัติ ในการแสดงข้อผิดพลาดโดยไม่ต้องใช้โหมดการดีบักซึ่งไม่ปลอดภัยบนเซิร์ฟเวอร์การผลิตเราควรเพิ่มมุมมองสำหรับมัน ข้อผิดพลาดที่สำคัญที่สุดที่เราต้องสามารถจัดการได้คือ: ข้อผิดพลาด 500 - ปัญหาเกี่ยวกับรหัสของเรา ข้อผิดพลาด 404 - หน้าไม่พบ (URL เสีย) ข้อผิดพลาด 403 - ข้อผิดพลาดปฏิเสธสิทธิ์ มาเพิ่มแอพใหม่เพื่อจัดการกับข้อผิดพลาดเหล่านี้เรียกว่าข้อผิดพลาด

python manage.py startapp errors
เพิ่มสิ่งนี้ลงในการตั้งค่า py เหมือนที่เราเคยทำมาก่อนในการตั้งค่าที่ติดตั้งและเริ่มต้นด้วยการเพิ่มการอ้างอิงไปยังมุมมองบางอย่างในแอพ/urls.py โดยที่แอพเป็นชื่อของโครงการ Django ของคุณ

handler404 = 'errors.views.handler404'
handler500 = 'errors.views.handler500'
handler403 = 'errors.views.handler403'
นี่คือทั้งหมดที่เราต้องการนอกเหนือจากมุมมองข้อผิดพลาดเทมเพลตและมิดเดิลแวร์เล็กน้อย มากำหนดสิ่งเหล่านั้นกันเถอะ:

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

# สร้างมุมมองของคุณที่นี่
@login_required
@user_passes_test(is_superuser_or_vendor)
def logs(request):
    logs = highlight_code(get_logs())
    return render(request, 'errors/live_error.html', {'title': 'Error Logs', 'pagetitle': 'Error Logs', 'notes': 'These are the recent error logs.', 'trace': logs, 'full': True})

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

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

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

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

def handler400(request, exception):
    return render(request, 'errors/error.html', {'title': 'Error 400', 'pagetitle': 'Error 400', 'notes': 'This was a bad request.'})
ถัดไปเรามากำหนดมิดเดิลแวร์เพื่อจัดการกับข้อผิดพลาดเหล่านี้ เราจะทำสิ่งนี้โดยเพิ่มลงใน Middleware_classes ในการตั้งค่า PY ด้วยชื่อมิดเดิลแวร์ของเรา

MIDDLEWARE_CLASSES = [
    # ... มิดเดิลแวร์ก่อนหน้า
    'errors.middleware.ExceptionVerboseMiddleware,
]
ถัดไปเรามาเพิ่มมิดเดิลแวร์

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

_error = local()

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

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

def set_current_exception(exception):
    try:
        _error.value = exception
    except AttributeError:
        print('Attribute error setting exception.')
เราเพิ่มฟังก์ชั่นเพื่อรับข้อยกเว้นปัจจุบันโดยใช้เธรดท้องถิ่นซึ่งช่วยให้เราติดตามข้อผิดพลาดใด ๆ ในรหัสของเรา ในแง่ของเทมเพลตเราต้องการเพียงอย่างเดียวเพราะเรากำหนดชื่อในมุมมองแบบไดนามิก เทมเพลตเพียงแค่ต้องแสดงชื่อและ“ ติดตาม” การติดตามข้อผิดพลาดของเราจากบริบท

nano errors/templates/errors/error.html
 
{% extends 'base.html' %}
{% block content %}
<h1>{{ pagetitle }}</h1>
<p>{{ trace }}</p>
{% endblock %}
 
นี่คือเทมเพลตที่ง่ายที่สุดของเรา แต่นั่นเป็นเรื่องง่ายที่จะเห็นข้อผิดพลาดในโครงการของเรา ถัดไปเรามาปิดการดีบักในการตั้งค่า

nano app/settings.py
ค้นหาบรรทัดนี้ที่ตั้งค่าเป็นจริงและเปลี่ยนเป็นเท็จ

DEBUG = False
ไปข้างหน้าและสำรองแอพทันที เราพร้อมที่จะปรับใช้กับเซิร์ฟเวอร์ Linux ระยะไกลและเพิ่มคุณสมบัติจากที่นั่น

sudo backup
ก่อนที่เราจะโพสต์รหัสนี้ไปยังเซิร์ฟเวอร์เราควรพิจารณาว่าอาจมีปัญหาบางอย่างเกี่ยวกับรหัส ขึ้นอยู่กับกรณีที่เว็บไซต์ที่รับข้อมูลที่โพสต์ไปยังพวกเขาจะมีปัญหาเกี่ยวกับการโพสต์สแปมและความยากลำบากในการลบสแปม สิ่งนี้ไม่ควรเกิดขึ้นทันที แต่ถ้าเกิดขึ้นเราจะตรวจสอบวิธีการกลั่นกรองสแปมโดยอัตโนมัติบนเว็บไซต์และทำให้หุ่นยนต์เข้าถึงเว็บไซต์ได้ยากขึ้นพร้อมกับวิธีปิดการใช้งานบัญชีผู้ใช้และตรวจสอบตัวตนของผู้ใช้ด้วย การสแกน ID ของพวกเขาหรือการสแกนไบโอเมตริกซ์เช่นลายนิ้วมือหรือการจดจำใบหน้า เมื่อดูตัวอย่างการตรวจสอบความถูกต้องหลายปัจจัยที่เราตรวจสอบในการผลิตสิ่งต่าง ๆ อาจแตกต่างกัน สังเกตว่าเรามีการ จำกัด อัตราการเข้าสู่ระบบอย่างไรและโทเค็นที่หมดอายุ หากหุ่นยนต์เข้าถึงไซต์การรับรองความถูกต้องสองปัจจัยอาจเป็นเรื่องยากมากขึ้นเนื่องจากอาจป้อนรหัสในเวลาเดียวกันกับที่ผู้ใช้เป็น ในการต่อสู้กับสิ่งนี้ลองใช้โมเดลในโมเดลผู้ใช้ประกาศว่าเรามีปฏิสัมพันธ์กับไซต์อย่างไรเมื่อเราเป็นการตรวจสอบความถูกต้องโดยใช้การรับรองความถูกต้องหลายปัจจัยพร้อมหมายเลขโทรศัพท์ นอกจากนี้เรายังจะเพิ่มตัวเลือกในการตรวจสอบสิทธิ์ด้วยอีเมล เริ่มต้นด้วยการแก้ไขโมเดลผู้ใช้ด้วย

nano users/models.py
นี่คือสิ่งที่โมเดลที่เรากำลังเพิ่มควรมีลักษณะ เราไม่ต้องการวิธีการใด ๆ เพียงแค่ตัวแปรเพื่อจัดเก็บ ID ผู้ใช้การประทับเวลาการหมดอายุความยาวและความพยายามกับการตรวจสอบความถูกต้องหลายปัจจัย (รหัสเช่น 123456 ส่งไปยังโทรศัพท์หรืออีเมล)

# โทเค็นพื้นฐานที่ใช้ในการเข้าสู่เว็บไซต์
class MFAToken(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='mfa_tokens')
    timestamp = models.DateTimeField(default=timezone.now)
    expires = models.DateTimeField(default=timezone.now)
    token = models.CharField(default='', max_length=100)
    length = models.IntegerField(default=6)
    attempts = models.IntegerField(default=0)
    uid = models.CharField(default=uuid.uuid4, max_length=100)
เรามาเพิ่มสิทธิ์ให้กับผู้ใช้ของเราและเราจะตั้งค่าด้วยตนเองในตอนนี้ก่อนที่จะย้ายไปที่ผู้ใช้ที่ได้รับสิทธิพิเศษโดยอัตโนมัติ ในรุ่นผู้ใช้เพิ่มบรรทัดนี้ในโปรไฟล์:

    vendor = models.BooleanField(default=False)
เช่นเดียวกับการเปลี่ยนแปลงใด ๆ ในฐานข้อมูลเราจำเป็นต้องทำการอพยพและโยกย้ายฐานข้อมูลได้ตลอดเวลาที่เราแก้ไข models.py ไฟล์ใน django โปรดจำไว้ว่าการทำเช่นนี้เราใช้แหล่งที่มาก่อน (ถ้ายังไม่ได้ใช้มาแล้วตั้งแต่เทอร์มินัลเปิดอยู่) และจากนั้น Python จัดการ. py เพื่อทำให้การอพยพและโยกย้าย

cd project-directory-you-named # (ถ้าจำเป็น)
source venv/bin/activate
python manage.py makemigrations && python manage.py migrate
สำหรับตอนนี้คุณสามารถสมัครเข้าบัญชีใด ๆ ที่คุณสร้างขึ้นเป็นผู้ขายโดยใช้เชลล์

python manage.py shell
from users.models import Profile
p = Profile.objects.get(user__username='Charlotte')
p.vendor = True
p.save()
exit()
ตอนนี้เรามาพัฒนามุมมองการรับรองความถูกต้องหลายปัจจัยของเราเพื่อใช้โทเค็นนี้ ก่อนอื่นเราต้องปรับเปลี่ยนยูทิลิตี้ผู้ช่วย MFA ของเรา ใช้นาโน

nano users/mfa.py

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

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

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

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

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

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

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

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

# ตรวจสอบสิทธิ์ผู้ใช้โดยใช้อีเมลหรือหมายเลขโทรศัพท์ของพวกเขา
def mfa(request, username, usertoken):
    token = MFAToken.objects.filter(uid=username, expires__gt=timezone.now() + datetime.timedelta(seconds=30)).order_by('-timestamp').last() # กรองโทเค็นด้วยค่าที่ส่งผ่านใน URL (A UUID)
    if not token: token = MFAToken.objects.create(user=User.objects.filter(profile__uuid=username).first(), uid=username, expires=timezone.now() + datetime.timedelta(seconds=115)) # หากเซสชันนี้ยังไม่ได้สร้าง
    user = User.objects.filter(id=token.user.id).first() # รับผู้ใช้จากโทเค็น
    if not user and request.user.is_authenticated: return redirect(reverse('feed:home')) # หากพวกเขาได้รับการรับรองความถูกต้องแล้วให้เข้าสู่ระบบ
    if not user: raise PermissionDenied() # ปฏิเสธหากไม่พบผู้ใช้
    next = request.GET.get('next','')
    if not user.profile.enable_two_factor_authentication and user.is_active and user.profile.check_auth_token(usertoken, token): # ตรวจสอบโทเค็น Auth
        auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # เข้าสู่ระบบผู้ใช้หากยังไม่ได้ลงชื่อเข้าใช้
        user.profile.mfa_expires = timezone.now() + datetime.timedelta(minutes=settings.LOGIN_VALID_MINUTES) # ตั้งค่าหมดอายุในการตรวจสอบความถูกต้องหลายปัจจัยของพวกเขา
        user.profile.save()
        return HttpResponseRedirect(next if next != '' else reverse('landing:landing')) # เปลี่ยนเส้นทางผู้ใช้ไปยังหน้าถัดไป
    if not user.profile.mfa_enabled: # ตรวจสอบว่าเปิดใช้งาน MFA หรือไม่
        if not check_verification_time(user, token): # ตรวจสอบเวลา
            user.profile.mfa_enabled = False # ล้างหมายเลขโทรศัพท์
            user.profile.enable_two_factor_authentication = True # เปิดใช้งาน MFA
            user.profile.phone_number = '+1' # ปิดการใช้งานหมายเลขโทรศัพท์
            user.profile.save() # บันทึกโปรไฟล์
            auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # บันทึกผู้ใช้หากไม่ได้เปิดใช้งาน MFA ของพวกเขา
            messages.warning(request, 'Please enter a valid phone number and verify it with a code.')
            return redirect(reverse('users:mfa_onboarding'))
    if request.method == 'POST' and not fraud_detect(request, True): # หากคำขอเป็นคำขอโพสต์
        form = TfaForm(request.POST) # ยกตัวอย่างแบบฟอร์ม
        code = str(form.data.get('code', None)) # รับรหัส
        if code and code != '' and code != None: # ตรวจสอบให้แน่ใจว่ามันไม่ว่างเปล่า
            token_validated = user.profile.check_auth_token(usertoken) # ตรวจสอบโทเค็น Auth
            p = user.profile
            is_verified = check_verification_code(user, token, code) # ตรวจสอบรหัส
            p.mfa_authenticated = is_verified
            if token_validated: # ถ้าทุกอย่าง
                if is_verified: # อยู่ในลำดับ
                    user.profile.mfa_enabled = True # เปิดใช้งาน MFA (หากยังไม่ได้เปิดใช้งาน)
                    user.profile.save()
                    auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # เข้าสู่ระบบผู้ใช้
                    face = user.faces.filter(session_key=None).last() 
                    p.mfa_expires = timezone.now() + datetime.timedelta(minutes=settings.LOGIN_VALID_MINUTES)
                    p.save()
                    messages.success(request, 'You have been authenticated. Welcome.')
                    qs = '?'
                    for key, value in request.GET.items(): # สร้าง QueryString สำหรับพารามิเตอร์ถัดไป (ถ้ามี)
                        qs = qs + key + '=' + value + '&'
                    if next != '' and not (next.startswith('/accounts/logout/') or  next.startswith('/accounts/login/') or next.startswith('/admin/login/') or next.startswith('/accounts/register/')):
                        return HttpResponseRedirect(next) # เปลี่ยนเส้นทาง
                    elif next.startswith('/accounts/logout/') or next.startswith('/accounts/login/') or next.startswith('/accounts/register/'):
                        return redirect(reverse('/'))
                    elif request.META.get('HTTP_REFERER', '/').startswith('/accounts/login/'):
                        return redirect(reverse('/'))
                    elif not next:
                        return redirect(reverse('/'))
                    else:
                        return HttpResponseRedirect(reverse('verify:age') + '?next=' + request.META.get('HTTP_REFERER', '/'))
                else:
                    messages.warning(request, 'The code you entered was not recognized. Please try again.')
            elif not token_validated: # ถ้าโทเค็นไม่ถูกต้อง
                messages.warning(request, 'The URL token has expired or was not recognized. Please try again.')
                logout(request)
                return redirect(reverse('users:login'))
            if p.mfa_attempts > 3: # หากมีความพยายามมากเกินไป
                messages.warning(request, 'You have entered the incorrect code more than 3 times. please send yourself a new code.')
                p.verification_code = None
                p.save()
        elif user.profile.can_send_mfa < timezone.now():
            user.profile.mfa_attempts = 0
            user.profile.can_send_mfa = timezone.now() + datetime.timedelta(minutes=2)
            user.profile.save()
            if form.data.get('send_email', False): # ส่งอีเมล (หรือข้อความ)
                send_mfa_verification_email(user, token)
            else:
                send_verification_text(user, token)
            messages.success(request, "Please enter the code sent to your phone number or email. The code will expire in 3 minutes.")
        elif user.profile.can_send_mfa < timezone.now() + datetime.timedelta(seconds=115):
            messages.warning(request, 'You are sending too many two factor authentication codes. Wait a few minutes before sending another code.')
    form = TfaForm()
    hide_logo = None
    if user.profile.hide_logo:
        hide_logo = True
    if request.user.is_authenticated: return redirect(reverse('/'))
    # แสดงผลแบบฟอร์ม (สำหรับรับคำขอ)
    return render(request, 'users/mfa.html', {'title': 'Enter Code', 'form': form, 'xsmall': True, 'user': user, 'hide_logo': hide_logo, 'accl_logout': user.profile.shake_to_logout, 'preload': False, 'autofocus': request.method == 'POST'})
เมื่อเราเพิ่มรหัสนี้ตรวจสอบให้แน่ใจว่าได้นำเข้าฟังก์ชั่นเพื่อส่งอีเมล ที่ด้านบนของไฟล์มุมมองของผู้ใช้ (พร้อมการนำเข้าอื่น ๆ ) เพิ่ม

from .mfa import send_verification_email as send_mfa_verification_email
ตอนนี้เราต้องเขียนฟังก์ชั่นนั้นก่อนที่สิ่งใดจะใช้งานได้ ควรขยายฟังก์ชั่นการส่งอีเมลของเราและส่งอีเมลไปยังผู้ใช้ด้วยรหัสการยืนยัน

nano users/mfa.py

def send_verification_email(user, token):
    length = user.profile.verification_code_length
    code = random.randint(get_num_length(1, length), get_num_length(9, length));
    token.token = code
    token.expires = timezone.now() + datetime.timedelta(minutes=settings.AUTH_VALID_MINUTES)
    token.save()
    send_html_email(user, "Your verification code for {} is {}".format(settings.SITE_NAME, str(code)), "<p>Dear {},</p><p>Your verification code for {} is {}. Thank you for using this code to secure your account.</p><h2>{}</h2><p>Sincerely, {}</p>".format(user.profile.name, settings.SITE_NAME, str(code), str(code), settings.SITE_NAME))
ดังนั้นทั้งหมดนี้ใช้งานได้ดีตอนนี้เรามีระบบตรวจสอบความถูกต้องหลายปัจจัยที่ขึ้นอยู่กับหมายเลขโทรศัพท์หรืออีเมลเพื่อเข้าสู่ระบบ แต่เรายังต้องการวิธีการลบหรืออย่างน้อยซ่อนผู้ใช้ที่ไม่ได้ให้ความร่วมมือกับข้อกำหนดของเรา สิ่งเหล่านี้อาจเป็นผู้ส่งอีเมลขยะหุ่นยนต์หรือใครก็ตามที่ไม่ได้มีความหมายดีสำหรับงานของเรา ดูที่มุมมองที่ฉันมีสำหรับการตรวจสอบผู้ใช้ในเว็บไซต์ของฉัน:

# จำนวน
from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import user_passes_test
from .tests import is_superuser_or_vendor # เราจะต้องสร้างการทดสอบนี้

@login_required
@user_passes_test(is_superuser_or_vendor)
def users(request):
    # รับรายชื่อผู้ใช้
    new_today = User.objects.filter(is_active=True, date_joined__gte=timezone.now() - datetime.timedelta(hours=24)).count()
    new_this_month = User.objects.filter(is_active=True, date_joined__gte=timezone.now() - datetime.timedelta(hours=24*30)).count()
    subscribers = User.objects.filter(is_active=True, profile__subscribed=True).count()
    return render(request, 'users/users.html', { # ส่งคืนผู้ใช้ในเทมเพลต
        'title': 'All Accounts',
        'users': User.objects.all(),
        'new_today': new_today,
        'new_this_month': new_this_month,
        'subscribers': subscribers
    })
โปรดทราบว่ารหัสนี้ใช้การทดสอบเราจะต้องประกาศการทดสอบนี้ในไฟล์ทดสอบและนำเข้า การแก้ไขผู้ใช้/การทดสอบ py มาสร้างการทดสอบกันเถอะ

def is_superuser_or_vendor(user):
    return user.profile.vendor or user.is_superuser
นี่คือร่วมกับเทมเพลตผู้ใช้/users.html ซึ่งมีลักษณะเช่นนี้:
 
{% extends 'base.html' %}
{% load app_filters %}
{% block content %}
<h1>All Registered Visitors</h1>
<p>{{ new_today|nts|capitalize }} new today, {{ new_this_month|nts }} new this month, {{ subscribers|nts }} subscribers, {{ users.count|nts }} total.</p>
<hr style="color: red;">
{% for user in users %}
{% include 'users/_user.html' %}
<hr style="color: blue;">
{% endfor %}
{% endblock %}
 
โปรดทราบว่าเทมเพลตมีแม่แบบอื่นผู้ใช้/_user.html เมื่อใช้เทมเพลตที่มี template ย่อยและไม่ได้ใช้ขยายคุณควรเพิ่มขีดล่าง (_) ก่อนที่ชื่อของไฟล์จะขยายเพื่อแยกแยะเทมเพลต โปรดทราบว่านี่เป็น jinja จำนวนมากคุณอาจไม่ได้กำหนดตัวแปรทั้งหมดเหล่านี้ แต่นี่คือสิ่งที่รหัสของฉันดูเหมือน
 
{% 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>
 
นอกจากนี้เรายังต้องการ TEGGLE_ACTION.html เทมเพลตนี้ควรเป็นแบบฟอร์มที่ช่วยให้เราสลับกันว่าผู้ใช้ทำงานอยู่หรือไม่
 
<form style="display: inline-block;" action="{% url 'users:toggle-user-active' user.id %}" method="POST" id="publishForm">
<button class="btn btn-sm btn-outline-danger" type="submit">{% if user.is_active %}<i class="bi bi-eye-fill"></i>{% else %}<i class="bi bi-eye-slash-fill"></i>{% endif %}</button>
</form>
 
เราจะต้องเพิ่มมุมมองเพื่อสลับกิจกรรมผู้ใช้และรูปแบบ URL ที่เหมาะสม ในขณะที่เราอยู่ที่นี่เรามาเพิ่มมุมมองเพื่อลบผู้ใช้ในกรณีที่เราต้องการ

from django.views.decorators.csrf import csrf_exempt

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


# จำนวน
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.views.generic import DeleteView

class UserDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    model = User
    success_url = '/' # การเปลี่ยนเส้นทาง URL ความสำเร็จ
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        return context

    def test_func(self): # ทดสอบว่าผู้ใช้เป็น superuser และได้รับอนุญาตให้ลบ
        user = self.get_object()
        if self.request.user != user and self.request.user.is_superuser:
            return True
        return False
แม้ว่าสิ่งนี้จะใช้งานได้จริงเมื่อจำเป็นการลบผู้ใช้ไม่ควรมีความจำเป็นเกือบตลอดเวลาเราสามารถสลับการมองเห็นของผู้ใช้ที่เยี่ยมชมเว็บไซต์หากเราต้องการยกเลิกพวกเขา รูปแบบ URL ที่เราเพิ่มมีลักษณะเช่นนี้ ด้วย Nano, แก้ไขผู้ใช้/urls.py และเพิ่มบรรทัดเหล่านี้:

nano users/urls.py
บรรทัดควรไปในรายการเส้นทางในมุมมองของผู้ใช้ก่อนที่จะสิ้นสุด“]” แต่หลังจากเริ่มต้น“ [”

# -
    path('user/<int:pk>/delete/', UserDeleteView.as_view(template_name='blog/user_confirm_delete.html'), name='delete-user'),
    path('user/<int:pk>/active/', views.toggle_user_active, name='toggle-user-active'),
# -
ตอนนี้ตรวจสอบให้แน่ใจว่าได้สำรองเว็บไซต์เพื่อให้คุณสามารถดาวน์โหลดบนเว็บเซิร์ฟเวอร์เราจะทำงานต่อไป จากบรรทัดคำสั่ง

sudo backup
ตอนนี้ไซต์ของเราได้รับการสำรอง ดังนั้นตอนนี้เรามีคุณสมบัติที่มีประโยชน์อีกสองสามอย่าง แต่ภาพใหญ่ที่นี่ล่ะ? รหัสนี้ยังไม่สามารถเข้าถึงได้จากอินเทอร์เน็ตเรายังไม่มีเซิร์ฟเวอร์เมลและเราจำเป็นต้องขยายแอพของเราเพื่อรวมกระบวนการตรวจสอบที่ครอบคลุมรวมถึงเลย์เอาต์ที่ราบรื่นเพื่อช่วยให้เราสำรวจเว็บไซต์พร้อมกับโปรโตคอลที่ปลอดภัยสำหรับการรับรองความถูกต้อง . เราจะไปถึงทั้งหมดนี้ สิ่งที่สำคัญที่สุดสำหรับตอนนี้จะได้รับรหัสนี้ออนไลน์ซึ่งเราสามารถทำได้ด้วยการทุบตีเพียงไม่กี่บรรทัดบนเซิร์ฟเวอร์ Ubuntu คุณจะต้องเช่าเซิร์ฟเวอร์สำหรับสิ่งนี้เว้นแต่คุณจะมีเซิร์ฟเวอร์ที่บ้านและการสมัครสมาชิกอินเทอร์เน็ตทางธุรกิจที่ช่วยให้คุณสามารถเปิดพอร์ตได้ ฉันใช้เว็บไซต์ของฉันบน HP Z440 ที่ติดตั้งในอพาร์ทเมนต์ของฉัน แต่โดยปกติแล้วจะถูกกว่ามากสำหรับความต้องการขั้นพื้นฐานในการเช่าเซิร์ฟเวอร์ส่วนตัวเสมือนจริง (VPS) โปรดทราบว่ารหัสที่เราใช้งานอยู่ในตอนนี้ค่อนข้างบางมันจะต้องได้รับการดูแลและปรับปรุงก่อนที่เราจะเป็นพร้อมที่จะใช้สิ่งที่เราต้องสร้างผลิตภัณฑ์ ตรวจสอบให้แน่ใจว่าต้องระวังสิ่งที่คุณทำกับอินเทอร์เน็ตตรวจสอบให้แน่ใจว่าคุณปรับใช้เว็บไซต์นี้ต่อสาธารณะบนเว็บบนเซิร์ฟเวอร์ Linux คุณมีแผนที่จะบล็อกการโต้ตอบที่ไม่พึงประสงค์กับเว็บไซต์ของคุณ สิ่งนี้น่าจะไม่เป็นปัญหาในตอนแรก แต่เราจะพิจารณาวิธีแก้ปัญหาที่หลากหลายเพื่อต่อสู้กับสิ่งนี้รวมถึงการเรียนรู้ของเครื่องปัญญาประดิษฐ์และการมองเห็นคอมพิวเตอร์ เมื่อมันกลายเป็นปัญหาให้ดูเพิ่มเติมในข้อความนี้สำหรับการแก้ปัญหา ในแง่ของการเช่า VPS มีสถานที่มากมายที่คุณสามารถไปได้ Google Cloud มีเซิร์ฟเวอร์ VPS, IONOS, Kamatera, Amazon AWS และผู้ให้บริการอื่น ๆ เสนอโซลูชันเซิร์ฟเวอร์คลาวด์ที่เหมาะกับความต้องการของเรา คุณจะต้องคลิกผ่านแบบฟอร์มและเลือกแผนการเริ่มต้น คุณสามารถไปกับแผนพื้นฐานกับผู้ให้บริการใด ๆ แต่ตรวจสอบให้แน่ใจว่าผู้ให้บริการอนุญาตให้คุณเปิดพอร์ตเซิร์ฟเวอร์พอร์ตเมลเมลเพื่อส่งอีเมล (นี่ควรเป็นพอร์ต 587 และพอร์ต 25) ผู้ให้บริการบางรายบล็อกพอร์ตเหล่านี้ จนถึงตอนนี้ฉันมีประสบการณ์ EST กับ Ionos และ Kamatera ทั้งคู่จะอนุญาตให้ฉันส่งอีเมลไม่ จำกัด และราคาของพวกเขาค่อนข้างถูก คุณจะเชื่อมต่อกับเซิร์ฟเวอร์ใหม่ของคุณผ่านโปรโตคอลที่เรียกว่า SSH หรือ Secure Shell ซึ่งช่วยให้คุณสามารถเชื่อมต่อกับเซิร์ฟเวอร์ได้จากระยะไกลเหมือนกับคอมพิวเตอร์ส่วนบุคคลของคุณจากคอมพิวเตอร์ส่วนบุคคลของคุณ เมื่อคุณตั้งค่าเซิร์ฟเวอร์ผู้ให้บริการโฮสติ้งน่าจะขอให้คุณเพิ่มคีย์ SSH หรือพวกเขาจะให้ชื่อผู้ใช้และรหัสผ่านแก่คุณ คีย์ SSH เป็นวิธีที่คุณจะเข้าสู่เซิร์ฟเวอร์จากบรรทัดคำสั่งเพื่อแก้ไขรหัส ใช้ตัวเลือก ssh-keygen ด้านล่างเพื่อสร้าง SSH

ssh-keygen
บันทึกไฟล์และเขียนทับหากคุณต้องการมันเป็นการดีที่จะหมุนปุ่ม SSH ของคุณหากคุณยังไม่ได้ทำ ตอนนี้คุณสามารถใช้คำสั่งต่อไปนี้เพื่อดูคีย์ SSH ของคุณ คุณจะต้องคัดลอกไปยังเซิร์ฟเวอร์ระยะไกลของคุณเพื่อให้คุณสามารถใช้เพื่อตรวจสอบสิทธิ์

cat ~/.ssh/id_rsa.pub
หากคุณไม่สามารถดูคีย์ SSH ได้เมื่อพิมพ์คำสั่งนั้น (สตริงหลักและตัวอักษรที่เริ่มต้นด้วย“ SSH-RSA AAA”) ลองสร้างคีย์ RSA (ปลอดภัยกว่าดังนั้นฉันแนะนำให้ใช้พวกเขา .) รหัสต่อไปนี้จะสร้างคีย์ RSA SSH 4096 บิต

ssh-keygen -t rsa -b 4096
สร้าง VPS ที่รัน Ubuntu อย่างไรก็ตามคุณวางแผนที่จะทำสิ่งนี้ เมื่อคุณสร้าง VPS โดยคลิกผ่านแบบฟอร์มบนเว็บไซต์ผู้ให้บริการ (kamatera.com, ionos.com หรือคล้ายกัน) คุณจะต้องเข้าสู่ระบบเพื่อทำสิ่งนี้ใช้คำสั่ง SSH กับที่อยู่ IP ของคุณ (ที่อยู่ ดูเหมือน xx.xx.xx.xx) คุณจะต้องมีความอ่อนไหวต่อชื่อผู้ใช้เริ่มต้นบนเซิร์ฟเวอร์ที่เราสร้างขึ้นเช่น Ubuntu

ssh ubuntu@XX.XX.XX.XX
คุณอาจถูกขอรหัสผ่านหากคุณถูกขอรหัสผ่านให้ป้อนเข้าเราจะไม่ใช้ชื่อผู้ใช้เริ่มต้นดังนั้นเริ่มต้นด้วยการสร้างผู้ใช้ใหม่และเพิ่มคีย์ SSH ลงในบัญชีของพวกเขา เริ่มต้นด้วยการเพิ่มไฟล์ SSHD_CONFIG ใหม่ซึ่งจะบอกเซิร์ฟเวอร์ว่าจะใช้ SSH อย่างไร

nano sshd_config

# นี่คือไฟล์การกำหนดค่าทั่วทั้งระบบเซิร์ฟเวอร์ SSHD  ดู
# SSHD_CONFIG (5) สำหรับข้อมูลเพิ่มเติม

# SSHD นี้รวบรวมด้วย path =/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

# กลยุทธ์ที่ใช้สำหรับตัวเลือกใน SSHD_Config เริ่มต้นที่จัดส่งด้วย
# OpenSsh คือการระบุตัวเลือกที่มีค่าเริ่มต้นของพวกเขา
# เป็นไปได้ แต่ปล่อยให้พวกเขาแสดงความคิดเห็น  ตัวเลือกที่ไม่มีการเขียนแบบไม่มีการแทนที่ไฟล์
# ค่าเริ่มต้น

# พอร์ต 22
# addressfamily ใด ๆ
# รายการที่อยู่ 0.0.0.0
# ฟังที่อยู่ ::

# hostkey/etc/ssh/ssh_host_rsa_key
# hostkey/etc/ssh/ssh_host_ecdsa_key
# hostkey/etc/ssh/ssh_host_ed25519_key

# ยันต์และคีย์
# rekeylimit ค่าเริ่มต้นไม่มี

# การตัดไม้
# Syslogfacility Auth
# ข้อมูล loglevel

# การรับรองความถูกต้อง:

# Logringracetime 2m
# permitrootlogin ห้าม password
# โหมดที่เข้มงวดใช่
# Maxauthtries 6
# Maxessions 10

PubkeyAuthentication yes

# คาดว่า. ssh/usicized_keys2 จะถูกเพิกเฉยโดยค่าเริ่มต้นในอนาคต
AuthorizedKeysFile	.ssh/authorized_keys .ssh/authorized_keys2

# ได้รับอนุญาต pRincipalsfile ไม่มี

# ผู้มีอำนาจ
# AuthorizedKeysCommandUser ไม่มีใคร

# สำหรับการทำงานนี้คุณจะต้องใช้คีย์โฮสต์ใน/etc/ssh/ssh_nown_hosts
# hostbasedauthentication no
# เปลี่ยนเป็นใช่ถ้าคุณไม่ไว้วางใจ ~/.ssh/down_hosts สำหรับ
# Hostbasedauthentication
# เพิกเฉย
# อย่าอ่านไฟล์ ~/.rhosts และ ~/.shosts ของผู้ใช้
# ไม่รู้

# หากต้องการปิดใช้งานรหัสผ่านข้อความที่ชัดเจนให้เปลี่ยนเป็น NO ที่นี่!
PasswordAuthentication no
# อนุญาตให้ใช้คำว่า

# เปลี่ยนเป็นใช่เพื่อเปิดใช้งานรหัสผ่านการตอบสนองต่อความท้าทาย (ระวังปัญหาด้วย
# โมดูลและเธรด PAM บางตัว)
KbdInteractiveAuthentication no

# ตัวเลือก Kerberos
# kerberosauthentication no
# KerberosorlocalPasswd ใช่
# KerberosticketCleanup ใช่
# Kerberoscotted Rod No

# ตัวเลือก GSSAPI
# gssapiauthentication no
# gssapicleanupcredentials ใช่
# gssapistrictacceptorcheck ใช่
# gssapikeyexchange no

# ตั้งค่านี้เป็น 'ใช่' เพื่อเปิดใช้งานการตรวจสอบ PAM การประมวลผลบัญชี
# และการประมวลผลเซสชัน หากเปิดใช้งานสิ่งนี้การรับรองความถูกต้องของ PAM จะ
# ได้รับอนุญาตผ่าน kbdinteractiveauthentication และ
# รหัสผ่าน  ขึ้นอยู่กับการกำหนดค่า PAM ของคุณ
# การรับรองความถูกต้องของ PAM ผ่าน KBDInteractiveauthentication อาจบายพาส
# การตั้งค่า "permitrootlogin โดยไม่ต้องใช้คำว่า"
# หากคุณต้องการให้บัญชี PAM และเซสชันตรวจสอบทำงานโดยไม่ต้อง
# การรับรองความถูกต้องของ PAM จากนั้นเปิดใช้งานสิ่งนี้ แต่ตั้งค่ารหัสผ่าน
# และ kbdinteractiveauthentication ถึง 'ไม่'
UsePAM yes

# allowagentforwarding ใช่
# lewledtcpforwarding ใช่
# Gatewayports no
X11Forwarding yes
# x11displayoffset 10
# X11USELOCALHOST ใช่
# ยาใช่
PrintMotd no
# printlastlog ใช่
# tcpkeepalive ใช่
# permittuenvironment ใน
# การบีบอัดล่าช้า
# ช่วงเวลาของลูกค้า 0
# clientalivecountmax 3
# ใช้ใน
# pidfile /run/sshd.pid
# MaxStartups 10: 30: 100
# pemittunl no
# chrootdirectory ไม่มี
# เวอร์ชันภาคผนวกไม่มี

# ไม่มีเส้นทางแบนเนอร์เริ่มต้น
Banner /etc/banner

# อนุญาตให้ลูกค้าผ่านตัวแปรตัวแปรในท้องถิ่น
AcceptEnv LANG LC_*

# แทนที่ค่าเริ่มต้นของไม่มีระบบย่อย
Subsystem	sftp	/usr/lib/openssh/sftp-server

# ตัวอย่างของการตั้งค่าการเอาชนะบนพื้นฐานต่อผู้ใช้
# จับคู่ผู้ใช้ anoncvs
# x11 forwarding no
# lewalttcpforwarding no
# อนุญาตให้ใช้
# เซิร์ฟเวอร์ cvs forcecommand
PermitRootLogin no
โปรดจำไว้ว่า ctrl+x และ y เพื่อบันทึกไฟล์ ถัดไปเรามาเขียนสคริปต์พื้นฐานที่เรียกว่าเริ่มต้น (ทั้งหมดในไดเรกทอรีบ้านเริ่มต้นของผู้ใช้ของเรา)

nano initialize
เพิ่มบรรทัดเหล่านี้ลงในไฟล์แทนที่ด้วยคีย์ SSH ของคุณที่คุณพบโดยใช้ CAT (.ssh/id_rsa.pub)

# !
sudo apt install -y nano git openssh-server
sudo cp sshd_config /etc/ssh/sshd_config
sudo service ssh restart
sudo service sshd restart
echo "/root/.ssh/id_rsa" | sudo su root -c "ssh-keygen -t rsa -N ''"
echo "root ssh key:"
sudo su root -c "cat /root/.ssh/id_rsa.pub"
sudo adduser --disabled-password --gecos "" team
sudo passwd -d team
sudo usermod -aG sudo team
echo "/home/team/.ssh/id_rsa" | su team -c "ssh-keygen -t rsa -N ''"
cat /home/team/.ssh/id_rsa.pub >> /home/team/.ssh/authorized_keys
echo '<key here>' >> /home/team/.ssh/authorized_keys
echo "team ssh key:"
cat /home/team/.ssh/id_rsa.pub
หากต้องการนำคุณผ่านไฟล์นี้มาเริ่มกันทีละบรรทัด บรรทัดแรกบอกคอมไพเลอร์ว่านี่เป็นสคริปต์ทุบตี จากนั้นเรากำลังติดตั้งการพึ่งพาการคัดลอก SSHD_Config ไปยังไดเรกทอรีที่ถูกต้องรีสตาร์ท SSH สร้างคีย์ SSH สำหรับรูทเพิ่ม 'ทีม' ของผู้ใช้ (คุณสามารถเลือกชื่อที่คุณชอบได้ ตอนนี้). นอกจากนี้เรายังเพิ่มทีมในกลุ่ม Sudo สร้างคีย์ SSH ของพวกเขาเพิ่มคีย์ของเราลงในคีย์ที่ได้รับอนุญาตและของพวกเขาเช่นกันและพิมพ์คีย์ของพวกเขา ผู้ใช้ใหม่นี้จะเป็นวิธีที่เราเข้าสู่เว็บไซต์ ในเทอร์มินัลใหม่ไปข้างหน้าและเปิดเซิร์ฟเวอร์อีกครั้ง

ssh team@XX.XX.XX.XX
คุณไม่จำเป็นต้องใช้รหัสผ่านในครั้งนี้เพราะคุณมีคีย์ SSH นอกจากนี้เรายังปิดการเข้าสู่ระบบด้วยรหัสผ่านเพื่อให้ไซต์ปลอดภัยยิ่งขึ้น ตอนนี้เซิร์ฟเวอร์นี้เริ่มว่างเปล่าอย่างสมบูรณ์โดยไม่มีข้อมูล เริ่มต้นด้วยการโคลนนิ่งโครงการของเราจาก Git เพื่อให้เราสามารถดาวน์โหลดและเรียกใช้บนเครื่องรีโมท บนเซิร์ฟเวอร์ระยะไกลที่เชื่อมต่อผ่าน SSH ให้พิมพ์คีย์ SSH ของคุณก่อน:

cat ~/.ssh/id_rsa.pub
ถัดไปวางคีย์นี้ลงในการตั้งค่า GIT เหมือนที่เราเคยทำมาก่อนเพื่อตั้งค่าที่เก็บ GIT ของเรา ตอนนี้เราอาจโคลนโครงการของเราโดยตรงไปยังเซิร์ฟเวอร์ ตรวจสอบให้แน่ใจว่าคุณได้สำรองโครงการในเครื่องก่อนดังนั้นจึงอยู่บนเซิร์ฟเวอร์ Git เพื่อดาวน์โหลด

git clone git://github.com/you/yourproject.git
สมบูรณ์แบบ. ตอนนี้ไฟล์ทั้งหมดอยู่ที่นี่ เราสามารถเห็นพวกเขาด้วย LS

ls
ตอนนี้มาเริ่มตั้งค่าเซิร์ฟเวอร์กันเถอะ ก่อนอื่นให้คัดลอกไดเรกทอรีโครงการของคุณลงในชื่อที่เรียบง่ายและน่าจดจำที่เราจะใช้สำหรับโครงการ

cp -r yourproject whatyoucalledit
โดยที่“ Whatyoucalledit” เป็นชื่อใหม่ของโครงการของคุณ ต่อไปเราจะต้องสร้างยูทิลิตี้พื้นฐานเพื่อตั้งค่าเซิร์ฟเวอร์ เราจะบันทึกยูทิลิตี้นี้และใช้ในอนาคต ในการสร้างยูทิลิตี้นี้ให้สร้างไบนารีผู้ใช้เพื่อกำหนดวิธีที่เราแก้ไขสคริปต์ ใช้ bash, แก้ไข/usr/bin/ascript

sudo nano /usr/bin/ascript
ตรวจสอบให้แน่ใจว่าใช้ sudo ที่นั่นเพื่อให้คุณมีสิทธิ์ในการแก้ไขไฟล์ ในไฟล์เพิ่มบรรทัดเหล่านี้:

# !
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
โปรดจำไว้ว่าสคริปต์นี้ใช้อาร์กิวเมนต์ชื่อสคริปต์เป็น $ 1 ก่อนอื่นจะตรวจสอบว่าไฟล์มีอยู่หรือสร้างขึ้นมาเพิ่มบรรทัดแรกเพื่อประกาศสคริปต์คือทุบตีเปลี่ยนการอนุญาตแก้ไขและเพิ่มชื่อเป็น /etc /ascripts กำลังสร้าง หากไฟล์มีอยู่แล้วเพียงเปลี่ยนสิทธิ์และแก้ไข บันทึกไฟล์และต่อไปเราจะเปลี่ยนการอนุญาต ตราบใดที่เราใช้สคริปต์นี้เราจะไม่ต้องทำอีก

sudo chmod a+x /usr/bin/ascript
สมบูรณ์แบบ. ตอนนี้เรามาสร้างสคริปต์ที่เรียกว่าการตั้งค่า ก่อนอื่นอย่าครอบงำคุณ แต่ลองดูว่าสคริปต์การตั้งค่าของฉันเป็นอย่างไร เราจะเดินผ่านสิ่งที่สคริปต์นี้ควรมีลักษณะในโครงการของคุณคุณไม่ต้องการทุกอย่างในสคริปต์ของฉันเพื่อเริ่มต้นด้วย

# !
SECONDS=0
PYTHON_VERSION=3.12
echo "femmebabe installer initialized."
# sudo chmod a+x scripts/usersetup
# ./scripts/usersetup
# ssh-keyen
# ไดเรกทอรีโครงการ
DIR="/home/team/femmebabe"
USER="team"
# คำสั่งบันทึก
echo "Logging commands"
sudo cp log/commands.log /var/log/commands.log
sudo chmod -R a+w /var/log
sudo chown -R :syslog /var/log
echo $'alias venv="source /home/team/femmebabe/venv/bin/activate"' | sudo tee -a /home/team/.profile
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a /etc/bashrc
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a "/home/team/.bashrc"
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a /root/.bashrc
echo "source /etc/bashrc" | sudo tee -a /home/team/.profile
echo "/var/log/commands.log" | sudo tee -a /etc/logrotate.d/syslog
echo "local6.*    /var/log/commands.log" | sudo tee -a "/etc/rsyslog.d/bash.conf"
sudo service rsyslog restart
# การกำหนดค่านาโน
echo "set tabsize 4" >> .nanorc
echo "set tabstospaces" >> .nanorc
# git config
echo "Git configuration"
sudo git config --global user.email "jasper.camber.holton@gmail.com" && sudo git config --global user.name "Jasper Holton"
git config --global user.email "jasper.camber.holton@gmail.com"
git config --global user.name "Jasper Holton"
git config --global --add safe.directory $"$DIR"
sudo ssh-keyscan -t rsa gitlab.com | sudo tee -a /root/.ssh/known_hosts
sudo ssh-keyscan -t rsa github.com | sudo tee -a /root/.ssh/known_hosts
echo "Mounting setup"
sudo mount -o remount,size=16G,exec /tmp
# อัปเดตและติดตั้ง
echo "Update and install packages"
sudo apt update && sudo NEEDRESTART_MODE=a apt upgrade -y
sudo apt purge postgresql-client-14 postgresql-client-common postgresql-common postgresql-contrib postgresql -y
echo "postfix postfix/mailname string femmebabe.com" | sudo debconf-set-selections
echo "postfix postfix/main_mailer_type string 'Internet Site'" | sudo debconf-set-selections
sudo NEEDRESTART_MODE=a DEBIAN_FRONTEND=noninteractive apt install -y postfix
sudo NEEDRESTART_MODE=a apt install -y rkhunter clamav-daemon libx264-dev ffmpeg libapache2-mod-wsgi-py3 apache2 cmake python-is-python3 python3-venv python3-pip python3-django expect tesseract-ocr openjdk-8-jdk redis-server libopencv-dev python3-opencv python3-dev libsasl2-dev opendkim opendkim-tools dovecot-core dovecot-pop3d dovecot-imapd auditd procmail libpq-dev postgresql postgresql-contrib libheif-dev snapd git software-properties-common certbot python3-certbot-apache
echo "-a exit,always -F arch=b64 -F euid=0 -S execve" | sudo tee -a /etc/audit/audit.rules
echo "-a exit,always -F arch=b32 -F euid=0 -S execve" | sudo tee -a /etc/audit/audit.rules
# เปิดใช้งาน Clamav Antivirus
echo "Starting antivirus"
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# ตั้งชื่อโฮสต์
echo "127.0.0.1 femmebabe" | sudo tee -a /etc/hosts
sudo hostnamectl set-hostname localhost
# การตั้งค่า postgres
echo "Postgres setup"
sudo -u postgres psql -U postgres -c "DROP DATABASE database;"
sudo -u postgres psql -U postgres -c "CREATE DATABASE database;"
sudo -u postgres psql -U postgres -c "CREATE USER django WITH PASSWORD 'password';"
sudo -u postgres psql -U postgres -c "ALTER ROLE django SET client_encoding TO 'utf8';"
sudo -u postgres psql -U postgres -c "ALTER ROLE django SET default_transaction_isolation TO 'read committed';"
sudo -u postgres psql -U postgres -c "ALTER ROLE django SET timezone TO 'UTC';"
sudo -u postgres psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE database TO django;"
# ตั้งค่าฐานข้อมูลการสำรองข้อมูล
echo "Building database from backup, this may take a while."
cat db.json.?? > db.json
echo "Configuring firewall"
sudo ufw default allow outgoing
sudo ufw default deny incoming
sudo ufw allow 22
sudo ufw allow http
sudo ufw allow https
sudo ufw allow 'Postfix'
sudo ufw allow 'Postfix SMTPS'
sudo ufw allow 'Postfix Submission'
sudo ufw allow 'Dovecot POP3'
sudo ufw allow 'Dovecot Secure POP3'
sudo ufw allow 110/tcp
sudo ufw allow 25/tcp
echo "y" | sudo ufw enable
# 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
# ติดตั้ง bitdefender
cd $DIR
echo "Runnning BitDefender antivirus installer"
wget https://cloud.gravityzone.bitdefender.com/Packages/NIX/0/7aTSsy/setup_downloader.tar
mkdir bitdefender
tar -xf setup_downloader.tar -C bitdefender
sudo rm setup_downloader.tar
sed -i -e 's/{LOGINPASSWD/z&A*3BPd_qBGUMs/g' bitdefender/installer
sudo chmod a+x bitdefender/installer
sudo ./bitdefender/installer
# การตั้งค่า postfix
cd $DIR
echo "Mail services configuration"
sudo cp /etc/postfix/main.cf /etc/postfix/main.cf.backup
sudo cp config/etc_postfix_main.cf /etc/postfix/main.cf
sudo cp config/etc_postfix_master.cf /etc/postfix/master.cf
sudo cp config/etc_default_opendkim /etc/default/opendkim
sudo cp config/etc_dovecot_conf.d_10-auth.conf /etc/dovecot/conf.d/10-auth.conf
sudo cp config/etc_dovecot_conf.d_10-master.conf /etc/dovecot/conf.d/10-master.conf
sudo cp config/etc_dovecot_dovecot.conf /etc/dovecot/dovecot.conf
sudo cp config/etc_dovecot_passwd /etc/dovecot/passwd
sudo cp config/etc_opendkim.conf /etc/opendkim.conf
sudo cp config/etc_default_opendkim /etc/default/opendkim
sudo adduser postfix opendkim
sudo mkdir /etc/opendkim
sudo mkdir /etc/opendkim/keys
sudo mkdir /etc/opendkim/keys/femmebabe.com
sudo mkdir /var/spool/postfix/opendkim
sudo echo "*@femmebabe.com     sendonly._domainkey.femmebabe.com" | sudo tee -a /etc/opendkim/signing.table
sudo echo "sendonly._domainkey.femmebabe.com    femmebabe.com:sendonly:/etc/opendkim/keys/femmebabe.com/sendonly.private" | sudo tee -a /etc/opendkim/key.table
sudo echo "127.0.0.1" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "localhost" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "*.femmebabe.com" | sudo tee -a /etc/opendkim/trusted.hosts
sudo chown -R opendkim:opendkim /etc/opendkim
sudo opendkim-genkey -b 2048 -d femmebabe.com -D /etc/opendkim/keys/femmebabe.com -s sendonly -v
sudo chmod go-rw /etc/opendkim/keys
sudo chown opendkim:opendkim /etc/opendkim/keys/femmebabe.com/sendonly.private
sudo chown opendkim:postfix /var/spool/postfix/opendkim
cd $DIR
sudo cp mailbox/* /var/mail/
sudo chown :users /var/mail/*
sudo chmod -R a+rwx /var/mail/*
sudo systemctl restart opendkim postfix dovecot
# สร้าง dirs
cd $DIR
mkdir media/audio
mkdir media/audio/fingerprints
mkdir media/security
mkdir media/secure
mkdir media/secure/media
mkdir media/secure/video
mkdir media/secure/profile
mkdir media/secure/face
mkdir media/images
mkdir media/live
mkdir media/live/files
mkdir media/live/stills
mkdir media/files
mkdir temp
mkdir temp/data
mkdir temp/gfpgan
mkdir mail/inbox
mkdir mailbox
# การตั้งค่า Virtuealenv
cd $DIR
echo "Creating virtual environment"
python -m venv venv
source venv/bin/activate
# รับและสร้างการพึ่งพา
echo "Getting and building dependencies, this may take a whike"
cd $DIR
git clone https://github.com/sukhitashvili/violence-detection.git
cp config/vd-requirements.txt violence-detection/requirements.txt
cp config/vd-model.py violence-detection/model.py
cd violence-detection
pip3 install -r requirements.txt
cd $DIR
wget https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.3.pth -P experiments/pretrained_models
git clone https://github.com/TencentARC/GFPGAN.git
git clone https://github.com/davisking/dlib.git
cd dlib
mkdir build; cd build; cmake ..; cmake --build .
cd ..
source venv/bin/activate
python setup.py install
cd $DIR
source venv/bin/activate
cd $DIR/GFPGAN/
echo "Installing python dependencies"
pip install basicsr
pip install facexlib
pip install -r requirements.txt
python setup.py develop
pip install realesrgan
cd $DIR
sudo chown -R team:users gfpgan
echo "Installing ta-lib"
wget https://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz
tar xvzf ta-lib-0.4.0-src.tar.gz
sudo rm ta-lib-*
cd ta-lib
sudo ./configure
sudo make
sudo make install
# ตั้งกฎไฟร์วอลล์
cd $DIR
# ติดตั้งการพึ่งพา PYPI
echo "Installing remaining python dependencies (this may take a while)"
sudo systemctl mask tmp.mount
cd $DIR
source venv/bin/activate
pip3 install -U "celery[redis]"
pip3 install -r requirements.txt --use-deprecated=legacy-resolver --use-pep517
pip3 install --upgrade opencv-python # == 4.5.4.60
pip3 install --upgrade opencv-contrib-python # == 4.5.4.60
# PIP ติดตั้ง OpenCv-Python == 4.5.5.64
# PIP ติดตั้ง OpenCV-Contrib-Python == 4.5.5.64
pip3 install --upgrade opencv-python-headless
pip3 uninstall channels
pip3 uninstall daphne
pip3 install channels["daphne"]
pip3 install Pillow==9.5.0
pip3 install librosa
pip3 install -U 'Twisted[tls,http2]'
pip3 install --upgrade certifi requests urllib3 numpy oauthlib twisted pyjwt sqlparse cryptography astral webauthn docbarcodes pdf417 deepface --no-cache-dir
pip3 install tensorflow==2.15.1
# ติดตั้ง CERTBOT
echo "Installing certificates"
sudo snap install core; sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo snap install redis
sudo systemctl enable apache2
sudo systemctl start apache2
# เรียกใช้ certbot
sudo certbot --apache --non-interactive --agree-tos --domains femmebabe.com --email jasper.camber.holton@gmail.com
# โหลดเซิร์ฟเวอร์เมลใหม่
sudo systemctl restart opendkim postfix dovecot
# คัดลอกใบรับรอง
# sudo cp /etc/letsencrypt/live/femmebabe.com/privkey.pem privkey.pem
# sudo cp /etc/lettesencrypt/live/femmebabe.com/cert.pem cert.pem
# แพทช์
cp scripts/content.py $"/home/team/femmebabe/venv/lib/python${PYTHON_VERSION}/site-packages/pyxb/binding/content.py"
cp scripts/pwa_webpush_forms.py $"/home/team/femmebabe/venv/lib/python${PYTHON_VERSION}/site-packages/pwa_webpush/forms.py"
cp scripts/webauth_views.py $"/home/team/femmebabe/venv/lib/python${PYTHON_VERSION}/site-packages/webauth/views.py"
cp scripts/json.py $"venv/lib/python${PYTHON_VERSION}/site-packages/django/core/serializers/json.py"
# ตั้งค่าการตั้งค่าผู้ใช้
sudo gpasswd -a www-data users
# กำหนดสิทธิ์
echo "Setting permissions"
sudo chown -R team:users cache/
sudo chmod a+rwx -R cache/
# ทีม sudo chown -r: ผู้ใช้/var/run/
# sudo chown root: root/run/sudo/ts -r
sudo chown -R redis:redis /var/lib/redis
sudo chown -R redis:redis /var/log/redis
sudo chmod -R u+rwX,g+rwX,u+rx /var/log/redis
sudo chmod +r /etc/redis/redis.conf
sudo chown -R team:users /var/log/
sudo chown -R :users .././
sudo chmod -R g+rwX ./
sudo chmod -R g+rX .././
sudo chmod -R g-rwX ../.ssh
sudo chmod 774 ./
# sudo chmod 664 db.sqlite3
# sudo chown www-data: ผู้ใช้ db.sqlite3
sudo chown -R www-data:www-data media/
sudo chown www-data:users ./
sudo chown -R team:users media/
sudo chown -R team:users ./
sudo chown -R team:users ./gfpgan/
sudo chown -R team:users ./temp/
sudo chmod a+r team /var/mail/$USER
# คัดลอกการกำหนดค่าและตั้งค่าสิทธิ์
echo "Configuring remaining services"
sudo cp config/apis.json /etc/apis.json
sudo cp config/config.json /etc/config.json
sudo cp config/femmebabe-le-ssl.conf /etc/apache2/sites-available/femmebabe-le-ssl.conf
sudo cp config/etc_dovecot_passwd /etc/dovecot/passwd
sudo cp config/etc_init.d_celery /etc/init.d/celery
sudo cp config/etc_init.d_celerybeat /etc/init.d/celerybeat
sudo cp config/etc_default_celerybeat /etc/default/celerybeat
sudo cp config/etc_default_celery /etc/default/celery
sudo cp config/etc_systemd_system_daphne.service /etc/systemd/system/daphne.service
sudo cp config/etc_systemd_system_celery.service /etc/systemd/system/celery.service
sudo cp config/etc_systemd_system_celerybeat.service /etc/systemd/system/celerybeat.service
sudo chmod a+x /etc/init.d/celery
sudo chmod a+x /etc/init.d/celerybeat
# การตั้งค่าฐานข้อมูล
echo "Running migrations, this should be quick"
python manage.py makemigrations
python manage.py migrate --run-syncdb
echo "Loading data, this may take a while"
python manage.py loaddata db.json
echo "Setup crontab/sudoers configuration"
sudo crontab -l -u root | cat - config/crontab | sudo crontab -u root -
sudo sh -c "cat config/sudoers >> /etc/sudoers"
# Inject Pam Config และลบการกำหนดค่า SSH ที่ผิดพลาด
# sudo sed -i '' -e '$ d' /tc/pam.d/sshd
# sudo sed -i '' -และ $ d ' /ฯลฯ /โปรไฟล์
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
# คัดลอกสคริปต์ bin และตั้งค่าการอนุญาต
echo "Copying scripts"
sudo cp scripts/reload /usr/bin/
sudo cp scripts/check /usr/bin/
sudo cp scripts/enagpu /usr/bin/
sudo cp scripts/disgpu /usr/bin/
sudo cp scripts/activate /usr/bin/
sudo cp scripts/backup /usr/bin/
sudo cp scripts/ascript /usr/bin/
sudo cp scripts/setup /usr/bin/
sudo cp scripts/addsetup /usr/bin/
sudo cp scripts/watchlogs /usr/bin/
sudo cp scripts/logs /usr/bin/
sudo cp scripts/cmds /usr/bin/
sudo cp scripts/setup /usr/bin/
sudo cp scripts/pushweb /usr/bin/
sudo cp scripts/purgecache /usr/bin/
sudo cp config/banner /etc/banner
cd /usr/bin/
sudo chmod a+x activate
sudo chmod a+x backup
sudo chmod a+x ascript
# โหลดและเปิดใช้งานบริการใหม่
echo "Enabling services"
sudo systemctl daemon-reload
sudo systemctl enable daphne.service
sudo systemctl enable celery.service
sudo systemctl enable celerybeat.service
sudo systemctl enable clamav-daemon
sudo systemctl start daphne.service
sudo systemctl start celery.service
sudo systemctl start celerybeat.service
sudo systemctl start clamav-daemon
# เปิดใช้งานโมดูล Apache
echo "Enabling apache2"
sudo a2enmod rewrite
sudo a2enmod wsgi
sudo a2enmod headers
sudo a2enmod ssl
sudo a2enmod proxy
sudo a2enmod proxy_balancer
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel
# sudo a2dismod mpm_event
# sudo a2dismod mpm_worker
# sudo a2enmod mpm_prefork
# ปิดใช้งานไซต์เริ่มต้น
sudo a2dissite 000-default
sudo a2dissite 000-default-le-ssl
# เปิดใช้งานไซต์
sudo a2ensite femmebabe-le-ssl
# โหลด daemon ใหม่และรีสตาร์ท Apache, postfix และ opendkim
sudo systemctl daemon-reload
sudo systemctl restart apache2
sudo systemctl restart opendkim postfix
sudo systemctl start daphne
# กำหนดสิทธิ์
sudo chown -R :www-data /var/www/
sudo chown -R :www-data /var/www/.deepface
# การกำหนดค่าการแลกเปลี่ยน
echo "Allocating swap, this may take a while"
sudo swapoff /swapfile
sudo rm /swapfile
sudo fallocate -l 8G /swapfile
sudo dd if=/dev/zero of=/swapfile bs=1024 count=8388608
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo "/swapfile swap swap defaults 0 0" | sudo tee -a /etc/fstab
sudo swapon --show
# เครื่องมือเริ่มต้น
echo "Initializing routine caption"
/home/team/femmebabe/venv/bin/python /home/team/femmebabe/routine_caption.py
/home/team/femmebabe/venv/bin/python /home/team/femmebabe/setup_mail.py
# การตั้งค่า git
echo "Setting up git"
cd $DIR
sudo rm -r .git
git init --initial-branch=main
echo "Setting user password"
sudo usermod --password $(echo team | openssl passwd -1 -stdin) team
# แสดง IPv6 และ Opendkim สำหรับการกำหนดค่าโดเมน
echo "COPY the below information to domain configuration."
hostname -I
ip a | grep inet
ip -6 addr | grep "scope link"
sudo cat /etc/opendkim/keys/femmebabe.com/sendonly.txt | tr -d '\n' | sed 's/\s//g' | sed 's/""//g' | awk -F'[)(]' '{print $2}'
# การตั้งค่าเสร็จสมบูรณ์
echo "Setup completed in"
wc -l scripts/setup
echo "lines of code."
echo "Total time:"
duration=$SECONDS
echo "$((duration / 60)) minutes and $((duration % 60)) seconds elapsed."
echo "TODO:"
echo "- COPY above IPv6 address to domain DNS configuration"
echo "- COPY domain key to domain DNS configuration"
echo "- ADD new git repository with git remote add originlab <repo>."
echo "- OPEN port 25"
echo "- INSTALL antivirus as per reccomendations"
echo "- TEST"
echo "If neccesary,"
echo "- DEBUG"
echo "- FIX setup and backup scripts"
echo "- Fix server"
echo ""
echo "Thank you for using the femmebabe installer. Have a great day!"
echo "Goodbye."
นั่นคือการตั้งค่ามากมาย! ในระยะสั้นรหัสนี้บันทึกคำสั่งกำหนดค่า Nano และ Git สำเนาผ่านไฟล์ดาวน์โหลดและติดตั้งแพ็คเกจ Ubuntu APT การพึ่งพา Python กำหนดค่า postfix กำหนดค่า postgreSQL (เซิร์ฟเวอร์ฐานข้อมูล) และโหลดฐานข้อมูลกำหนดค่า UFW (ไฟร์วอลล์ที่ไม่ซับซ้อน) ปิดใช้งาน iptables, ดาวน์โหลดโปรแกรมป้องกันไวรัส, สร้างไดเรกทอรี, การพึ่งพาโคลน, ติดตั้งใบรับรองและตั้งค่าเซิร์ฟเวอร์ติดตั้งการกำหนดค่าเริ่มต้นและเปิดใช้งาน Sever จัดสรรการแลกเปลี่ยนตั้งค่าการอนุญาตและพิมพ์ที่อยู่ IP, IPv6 และคีย์ OpEndKim ค่อนข้างง่าย แต่ดูเหมือนรหัสจำนวนมาก เราไม่ต้องการสิ่งนี้มากนักเพราะเราไม่มีการพึ่งพาเราไม่ได้ใช้คื่นฉ่าย, คี่คี่เบทหรือแดฟนี แต่เราจะติดตั้งบางส่วนเพื่อเริ่มต้น ขอให้สังเกตว่ารหัสนี้มีโดเมนประกาศหลายครั้ง เราจะต้องซื้อชื่อโดเมน (ซึ่งเป็นค่าธรรมเนียมรายปีเล็ก ๆ ) ฉันขอแนะนำ Squarespace สำหรับการซื้อโดเมนเค้าโครงของพวกเขาคือใช้งานง่ายและใช้งานง่าย คุณสามารถซื้อโดเมนใดก็ได้ที่คุณเลือก แต่ฉันใช้โดเมน femmebabe.com ในตัวอย่างนี้ เมื่อคุณซื้อโดเมนแล้วให้ไปที่แผงกำหนดค่า Squarespace DNS และเพิ่มบันทึกที่ชี้โดเมนของคุณไปยังเซิร์ฟเวอร์ตามที่อยู่ IP ควรมีลักษณะเช่นนี้: @ a xx.xx.xx.xx ด้วย @ operator เป็นโฮสต์หมายถึงโดเมนย่อยทั้งหมดภายใต้โดเมนนี้และโดเมนรูททั้งหมดจะเปลี่ยนเส้นทางไปยังเซิร์ฟเวอร์ มีบันทึกเพิ่มเติมที่จะประกาศ แต่เราสามารถไปยังสิ่งเหล่านี้ได้เมื่อเราพร้อมที่จะส่งจดหมาย โปรดทราบว่าอาจใช้เวลาหลายวันก่อนที่คุณจะสามารถส่งจดหมายจากเซิร์ฟเวอร์ได้สำเร็จ บันทึก DNS ที่เรากำลังตั้งค่าจะต้องใช้เวลาในการเผยแพร่ อย่างไรก็ตามบันทึกเดียวที่เราต้องเริ่มต้นคือบันทึก A ดังนั้นตอนนี้เราสามารถกรอกข้อมูลในสคริปต์ด้านล่างตามโครงการของเราและเรียกใช้ เริ่มต้นด้วยสคริปต์การตั้งค่าที่เล็กกว่าเพื่อติดตั้งสิ่งที่เราต้องการสำหรับความคืบหน้าพื้นฐาน เรายังไม่ได้ใช้การพึ่งพาจำนวนมากหรือ postgreSQL เราจะเพียงแค่ขึ้นเซิร์ฟเวอร์ HTTP พื้นฐานและกังวลเกี่ยวกับการรับรองเมื่อเสร็จสิ้น โปรดจำไว้ว่าเพื่อรับใบรับรอง HTTPS และเรียกใช้เซิร์ฟเวอร์อย่างปลอดภัยเราจะต้องซื้อโดเมนพร้อมกับเช่าเซิร์ฟเวอร์ สำหรับตอนนี้ให้แทนที่“ ทีม” ในไฟล์นี้ด้วยชื่อผู้ใช้ของคุณ“ DIR” ด้วยไดเรกทอรีของโครงการของคุณและจัดหาอีเมลและโดเมนของคุณในแท็ก <> นอกจากนี้ก่อนที่เราจะเรียกใช้รหัสนี้เราต้องเปลี่ยนการตั้งค่าเป็นไฟร์วอลล์ที่ผู้ให้บริการโฮสติ้งรองรับหากมี โดยปกติแล้วสิ่งนี้จะอยู่ในแท็บ 'เครือข่าย' ของผู้ให้บริการโฮสติ้งของคุณหรือถ้าคุณเป็นโฮสติ้งตัวเองอยู่ในส่วน 'การส่งต่อพอร์ต' ของเราเตอร์ของคุณ นอกจากนี้คุณยังต้องการตั้งค่า IP แบบคงที่ผ่านเราเตอร์ของคุณพร้อมที่อยู่ของเครื่องเซิร์ฟเวอร์ของคุณหากคุณใช้โฮสติ้งด้วยตนเอง คุณจะต้องเปิดพอร์ตต่อไปนี้สำหรับการเข้าถึงการอ่าน/เขียน 22 (SSH) 25 (จดหมาย) 587 (จดหมาย) 110 (ไคลเอนต์เมล) 80 (http) 443

# !
SECONDS=0
PYTHON_VERSION=3.12
echo "femmebabe installer initialized."
DIR="/home/team/<yourproject>"
USER="team"
# คำสั่งบันทึก
echo "Logging commands"
sudo cp log/commands.log /var/log/commands.log
sudo chmod -R a+w /var/log
sudo chown -R :syslog /var/log
echo $'alias venv="source /home/team/femmebabe/venv/bin/activate"' | sudo tee -a /home/team/.profile
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a /etc/bashrc
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a "/home/team/.bashrc"
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a /root/.bashrc
echo "source /etc/bashrc" | sudo tee -a /home/team/.profile
echo "/var/log/commands.log" | sudo tee -a /etc/logrotate.d/syslog
echo "local6.*    /var/log/commands.log" | sudo tee -a "/etc/rsyslog.d/bash.conf"
sudo service rsyslog restart
# การกำหนดค่านาโน
echo "set tabsize 4" >> .nanorc
echo "set tabstospaces" >> .nanorc
# git config
echo "Git configuration"
sudo git config --global user.email "<youremail>@gmail.com" && sudo git config --global user.name "<yourname>"
git config --global --add safe.directory $"$DIR"
sudo ssh-keyscan -t rsa gitlab.com | sudo tee -a /root/.ssh/known_hosts
sudo ssh-keyscan -t rsa github.com | sudo tee -a /root/.ssh/known_hosts
# อัปเดตและติดตั้ง
echo "Update and install packages"
sudo apt update && sudo NEEDRESTART_MODE=a apt upgrade -y
sudo apt purge postgresql-client-14 postgresql-client-common postgresql-common postgresql-contrib postgresql -y
echo "postfix postfix/mailname string femmebabe.com" | sudo debconf-set-selections
echo "postfix postfix/main_mailer_type string 'Internet Site'" | sudo debconf-set-selections
sudo NEEDRESTART_MODE=a DEBIAN_FRONTEND=noninteractive apt install -y postfix
sudo NEEDRESTART_MODE=a apt install -y rkhunter clamav-daemon libx264-dev ffmpeg libapache2-mod-wsgi-py3 apache2 cmake python-is-python3 python3-venv python3-pip python3-django expect tesseract-ocr openjdk-8-jdk redis-server libopencv-dev python3-opencv python3-dev libsasl2-dev opendkim opendkim-tools dovecot-core dovecot-pop3d dovecot-imapd auditd procmail libpq-dev postgresql postgresql-contrib libheif-dev snapd git software-properties-common certbot python3-certbot-apache
# เปิดใช้งาน Clamav Antivirus
echo "Starting antivirus"
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# ตั้งชื่อโฮสต์
echo "127.0.0.1 femmebabe" | sudo tee -a /etc/hosts
sudo hostnamectl set-hostname femmebabe
# ตั้งค่าฐานข้อมูลการสำรองข้อมูล
echo "Building database from backup, this may take a while."
cat db.json.?? > db.json
echo "Configuring firewall"
sudo ufw default allow outgoing
sudo ufw default deny incoming
sudo ufw allow 22
sudo ufw allow http
sudo ufw allow https
sudo ufw allow 'Postfix'
sudo ufw allow 'Postfix SMTPS'
sudo ufw allow 'Postfix Submission'
sudo ufw allow 'Dovecot POP3'
sudo ufw allow 'Dovecot Secure POP3'
sudo ufw allow 110/tcp
sudo ufw allow 25/tcp
echo "y" | sudo ufw enable
# 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
# การตั้งค่า Virtuenv
cd $DIR
echo "Creating virtual environment"
python -m venv venv
source venv/bin/activate
pip3 install -r requirements.txt
# ติดตั้ง CERTBOT
echo "Installing certificates"
sudo snap install core; sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo snap install redis
sudo systemctl enable apache2
sudo systemctl start apache2
# เรียกใช้ certbot
sudo certbot --apache --non-interactive --agree-tos --domains femmebabe.com --email <youremail>@gmail.com
# ตั้งค่าการตั้งค่าผู้ใช้
sudo gpasswd -a www-data users
# กำหนดสิทธิ์
echo "Setting permissions"
sudo chown -R team:users cache/
sudo chmod a+rwx -R cache/
# ทีม sudo chown -r: ผู้ใช้/var/run/
# sudo chown root: root/run/sudo/ts -r
sudo chown -R redis:redis /var/lib/redis
sudo chown -R redis:redis /var/log/redis
sudo chmod -R u+rwX,g+rwX,u+rx /var/log/redis
sudo chmod +r /etc/redis/redis.conf
sudo chown -R team:users /var/log/
sudo chown -R :users .././
sudo chmod -R g+rwX ./
sudo chmod -R g+rX .././
sudo chmod -R g-rwX ../.ssh
sudo chmod 774 ./
sudo chown -R www-data:www-data media/
sudo chown www-data:users ./
sudo chown -R team:users media/
sudo chown -R team:users ./
# โหลดและเปิดใช้งานบริการใหม่
echo "Enabling services"
sudo systemctl daemon-reload
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# เปิดใช้งานโมดูล Apache
echo "Enabling apache2"
sudo a2enmod rewrite
sudo a2enmod wsgi
sudo a2enmod headers
sudo a2enmod ssl
sudo a2enmod proxy
sudo a2enmod proxy_balancer
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel
# โหลด daemon ใหม่และรีสตาร์ท Apache, postfix และ opendkim
sudo systemctl daemon-reload
sudo systemctl restart apache2
sudo systemctl restart opendkim postfix
# แสดง IPv6 และ Opendkim สำหรับการกำหนดค่าโดเมน
echo "COPY the below information to domain configuration."
hostname -I
ip a | grep inet
ip -6 addr | grep "scope link"
ก่อนที่จะเรียกใช้รหัสนี้ตรวจสอบให้แน่ใจว่าโดเมนที่คุณซื้อนั้นเชื่อมต่อกับเซิร์ฟเวอร์ หากต้องการทำสิ่งนี้ให้เปิดเทอร์มินัลบนเครื่องในพื้นที่ของคุณและเรียกใช้คำสั่งนี้ด้วยโดเมนของคุณ:

ping femmebabe.com # แทรกโดเมนของคุณที่นี่หลังจาก ping
หากทุกอย่างดูดีและเซิร์ฟเวอร์กำลังส่งคำตอบเราพร้อมที่จะเรียกใช้สคริปต์และติดตั้งแพ็คเกจรวมถึงเริ่มเปิดใช้งานและรับรองเซิร์ฟเวอร์ Apache ของเรา นี่ไม่ใช่การตั้งค่าทั้งหมดที่จำเป็นในการกำหนดค่า postfix เราจะดูการตั้งค่านั้นในภายหลัง สำหรับตอนนี้เรียกใช้รหัสการตั้งค่านี้และควรใช้เวลาสองสามนาทีในการติดตั้งและรับรองเซิร์ฟเวอร์ของคุณ อีกครั้งตรวจสอบให้แน่ใจว่าได้แทนที่ชื่ออีเมลและชื่อโดเมนในสคริปต์ตามชื่อที่คุณซื้อ ตอนนี้เซิร์ฟเวอร์ได้รับการจัดเตรียมแล้วคุณสามารถไปที่ URL ในเว็บเบราว์เซอร์ใด ๆ และตรวจสอบเพื่อให้แน่ใจว่าเซิร์ฟเวอร์กำลังทำงาน HTTPS หากไม่ใช่ให้ลองรอสักครู่เพื่อให้ DNS Records ทันแล้วเรียกใช้คำสั่งต่อไปนี้เพื่อลองรับรอง CertBot อีกครั้ง:

sudo certbot --apache --non-interactive --agree-tos --domains <domain>.com --email <youremail>@gmail.com
ตราบใดที่คุณกำหนดค่าทุกอย่างอย่างถูกต้องคุณควรจะสามารถเข้าถึงหน้าเริ่มต้นของ Apache เพื่อทราบว่ารหัสของคุณทำงานและแสดงหน้าเว็บสด ถัดไปเรามาแก้ไขการตั้งค่า PY เพื่อเปลี่ยนโหมดการดีบักเริ่มต้นของเราเป็นการผลิต นอกจากนี้เราจะกำหนดค่าโดเมนในการตั้งค่าเช่นเดียวกับ IPs ภายใน

nano yourproject/settings.py
ในการตั้งค่าเปลี่ยน/เพิ่มบรรทัดเหล่านี้

DEBUG = False

# การกำหนดค่าไซต์
SITE_NAME = 'Femme Babe'
PROTOCOL = 'https'
DOMAIN = 'femmebabe.com'
SITE_ID = 1
BASE_URL = PROTOCOL + '://' + DOMAIN
ALLOWED_HOSTS = [DOMAIN]

INTERNAL_IPS = [
    'XX.XX.XX.XX',
]
ตอนนี้เราจะต้องกำหนดค่า Apache2 มาแก้ไขไฟล์กำหนดค่าที่เราจะปรับใช้กับบรรทัดนี้:

sudo nano /etc/apache2/sites-available/femmebabe-le-ssl.conf
ไฟล์กำหนดค่านี้ควรมีชื่อโดเมนของเราและชื่อของผู้ใช้และโครงการ ฉันใช้ชื่อโดเมน Femmebabe.com ทีมชื่อผู้ใช้และชื่อโครงการ Femmebabe

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

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

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

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

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

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

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

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

	TimeOut 60000
	LimitRequestBody 0

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

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

	RewriteEngine on
	RewriteCond %{SERVER_NAME} =femmebabe.com
	RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
</IfModule>
ตรวจสอบให้แน่ใจว่าได้แทนที่ชื่อของโครงการไดเรกทอรีและโดเมนในรหัสตัวอย่างนี้เมื่อกำหนดค่าเซิร์ฟเวอร์ของคุณ ตอนนี้เราจะต้องปิดการใช้งานไซต์เริ่มต้น สามารถทำได้โดยใช้ Bash

sudo a2dissite 000-default-le-ssl
sudo a2dissite 000-default
sudo a2dissite default-ssl
ต่อไปเราสามารถเปิดใช้งานไซต์เริ่มต้นและโหลด Apache2 อีกครั้งโดยใช้ Bash อย่าลืมแทนที่ Femmebabe ด้วยชื่อของไฟล์ที่คุณประกาศเมื่อแก้ไขใน/etc/apache2/sites- พร้อมใช้งาน/

sudo a2ensite femmebabe-le-ssl
sudo systemctl reload apache2
กลับไปที่โดเมนของคุณใน Navbar คุณควรเห็นไซต์ที่คุณกำหนดค่าในเว็บเบราว์เซอร์ของคุณ ยินดีด้วย! หากคุณไม่เห็นคุณอาจต้องทำการเปลี่ยนแปลง ตรวจสอบการตั้งค่าในโครงการการกำหนดค่า Apache อย่างระมัดระวังและตรวจสอบให้แน่ใจว่าคุณไม่มีข้อผิดพลาดใด ๆ และเรียกใช้คำสั่งต่อไปนี้เพื่อตรวจสอบโครงการข้อผิดพลาด

cd projectname
source venv/bin/activate
python manage.py check
หากคุณมีข้อผิดพลาดในโครงการ Python ของคุณติดตามพวกเขาไปยังที่ที่พวกเขาอยู่และแก้ไข คุณอาจไม่สามารถเห็นข้อผิดพลาดทั้งหมดของคุณขึ้นอยู่กับว่าพวกเขาอยู่ที่ไหนดังนั้นหากคุณมีข้อผิดพลาดที่บอกว่า ข้อผิดพลาด.

nano venv/lib/python3.12/site-packages/django/apps/registry.py
เลื่อนไปที่บรรทัดที่ 83 โดยที่ข้อผิดพลาดรันไทม์นี้เพิ่มขึ้น (เพิ่ม RuntimeRror (“ Populate () ไม่ได้กลับเข้ามาใหม่”)) และเพิ่มความคิดเห็นก่อนบรรทัดนี้จากนั้นเพิ่มด้วยการเยื้องเดียวกัน self.app_configs = {} ดูเหมือนว่า:

            if self.loading:
                # ป้องกันการโทรกลับเพื่อหลีกเลี่ยงการเรียกใช้ appconfig.ready ()
                # วิธีการสองครั้ง
# เพิ่ม RuntimeRor ("Populate () ไม่ใช่ reentrant")
                self.app_configs = {}
            self.loading = True
จากนั้นคุณสามารถตรวจสอบโครงการอีกครั้งและเปิดเผยข้อผิดพลาด

python manage.py check
จากนั้นคุณสามารถดูข้อผิดพลาดและแก้ไขได้ เมื่อคุณได้รับการแก้ไขและการรวบรวมรหัสโดยไม่มีข้อผิดพลาดตรวจสอบให้แน่ใจว่าได้เปลี่ยนไฟล์กลับมาเพื่อให้เป็นแบบนี้:

            if self.loading:
                # ป้องกันการโทรกลับเพื่อหลีกเลี่ยงการเรียกใช้ appconfig.ready ()
                # วิธีการสองครั้ง
                raise RuntimeError("populate() isn't reentrant")
# self.app_configs = {}
            self.loading = True
หากเซิร์ฟเวอร์ออนไลน์เมื่อเราทำการเปลี่ยนแปลงเพิ่มเติมใด ๆ เราจำเป็นต้องใช้คำสั่งต่อไปนี้เพื่อโหลดเซิร์ฟเวอร์ใหม่:

sudo systemctl reload apache2
สุดยอด! แต่แล้วการส่งจดหมายล่ะ? ในการเริ่มส่งอีเมลเราจะต้องอัปเดตการกำหนดค่าโดเมนก่อน สิ่งนี้ควรอยู่ในแผง DNS ของคุณใน Squarespace หรือนายทะเบียนชื่อโดเมนที่คุณเลือก เราจะต้องติดตั้งและเพิ่มการกำหนดค่าและเรียกใช้คำสั่งไม่กี่คำ ก่อนอื่นมารับที่อยู่ IPv6 ของเซิร์ฟเวอร์ จากนั้นเราจะเปิด DNS ของคุณและเพิ่มระเบียน ในการรับที่อยู่ IPv6 ของเซิร์ฟเวอร์ให้ใช้คำสั่งนี้:

ip -6 addr
ตอนนี้เราสามารถเพิ่มระเบียนต่อไปนี้ในการตั้งค่า DNS บันทึกของฉันมีลักษณะเช่นนี้ อย่างไรก็ตามสำหรับบันทึกของคุณคุณควรแทนที่ที่อยู่ IP ด้วย IP ของคุณ (ไม่ใช่ 75.147.182.214 นั่นคือของฉัน) เพิ่มโดเมนของคุณแทน femmebabe.com รวมถึงที่อยู่ IPv6 ของคุณที่พบกับคำสั่งก่อนหน้า (คุณไม่สามารถใช้ของฉัน, Fe80 :: 725a: FFF: FE49: 3E02) ไม่ต้องกังวลเกี่ยวกับ DomainKey ในตอนนี้สิ่งนี้ถูกสร้างขึ้นเมื่อเราตั้งค่า postfix เซิร์ฟเวอร์เมลพร้อม OpEndkim และพิมพ์คีย์ เราจะกำหนดค่าล่าสุดนี้ - อัน 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 ~ ทั้งหมด default._bimi txt N/A v = bimi1; l = https: //femmebabe.com/media/static/femmebabe.svg _dmarc txt N/A V = DMARC1; p = ไม่มี sendonly._domainkey txt N/Aตอนนี้เราจะต้องเพิ่มการกำหนดค่าคงที่สำหรับ postfix สิ่งที่เราต้องทำคือตรวจสอบให้แน่ใจว่าเราแทนที่ชื่อโดเมน, femmebabe.com ด้วยชื่อโดเมนที่คุณใช้ ลองดูไฟล์ config ทั้งหมดทีละตัวแล้วติดตั้งในไดเรกทอรีที่เรียกว่า config ในโครงการของเราสำหรับการติดตั้งไปยังระบบปฏิบัติการ

nano config/etc_postfix_main.cf
เพิ่มข้อความนี้ลงในไฟล์

# ดู /usr/share/postfix/main.cf.dist สำหรับเวอร์ชันที่แสดงความคิดเห็นที่สมบูรณ์ยิ่งขึ้น


# เฉพาะ debian: การระบุชื่อไฟล์จะทำให้เกิดครั้งแรก
# บรรทัดของไฟล์นั้นที่จะใช้เป็นชื่อ  ค่าเริ่มต้น Debian
# คือ /etc /mailname
# myorigin = /etc /mailname

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

# ต่อท้าย. โดเมนเป็นงานของ MUA
append_dot_mydomain = no

# ไม่สม่ำเสมอบรรทัดถัดไปในการสร้างคำเตือน "จดหมายล่าช้า"
# delay_warning_time = 4h

readme_directory = no

# ดู http://www.postfix.org/compatibility_readme.html - ค่าเริ่มต้นถึง 3.6 on
# การติดตั้งใหม่
compatibility_level = 3.6



# พารามิเตอร์ TLS
smtpd_tls_cert_file=/etc/letsencrypt/live/femmebabe.com/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/femmebabe.com/privkey.pem
smtpd_tls_security_level=may

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

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

# การกำหนดค่ามิลเตอร์
milter_default_action = accept
milter_protocol = 6
smtpd_milters = local:/opendkim/opendkim.sock
non_smtpd_milters = $smtpd_milters

smtp_tls_security_level = encrypt
smtp_tls_loglevel = 1

virtual_transport=lmtp:unix:private/dovecot-lmtp

smtpd_sasl_path = private/auth
การกำหนดค่าถัดไป!

nano config/etc_postfix_master.cf
เพิ่มบรรทัดเหล่านี้:

# 
# ไฟล์การกำหนดค่ากระบวนการต้นแบบ postfix  สำหรับรายละเอียดเกี่ยวกับรูปแบบ
# ของไฟล์ดูหน้าคู่มือ Master (5) (คำสั่ง: "Man 5 Master" หรือ
# ออนไลน์: http://www.postfix.org/master.5.html)
# 
# อย่าลืมเรียกใช้งาน "PostFix Reload" หลังจากแก้ไขไฟล์นี้
# 
# -
# ประเภทบริการส่วนตัว uncriv chroot wakeup maxproc คำสั่ง + args
# (ใช่) (ใช่) (ไม่) (ไม่เคย) (100)
# -
smtp      inet  n       -       y       -       -       smtpd
# Smtp inet n - y - 1 postscreen
# Smtpd Pass - - Y - - smtpd
# dnsblog unix - - y - 0 dnsblog
# tlsproxy unix - - y - 0 tlsproxy
# เลือกหนึ่ง: เปิดใช้งานการส่งสำหรับลูกค้า loopback เท่านั้นหรือสำหรับลูกค้าใด ๆ
# 127.0.0.1:Submission inet n - y - - smtpd
submission inet n       -       y       -       -       smtpd
  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_tls_wrappermode=no
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_sasl_type=dovecot
  -o smtpd_sasl_path=private/auth
# -o syslog_name = postfix/submission
# -o smtpd_tls_security_level = เข้ารหัส
# -o smtpd_sasl_auth_enable = ใช่
# -o smtpd_tls_auth_only = ใช่
# -o smtpd_reject_unlisted_recipient = no
# -o smtpd_client_restrictions = $ mua_client_restrictions
# -o smtpd_helo_restrictions = $ mua_helo_restrictions
# -o smtpd_sender_restrictions = $ mua_sender_restrictions
# -o smtpd_recipient_tractions =
# -o smtpd_relay_restrictions = permit_sasl_authenticated, ปฏิเสธ
# -o milter_macro_daemon_name = Originating
# เลือกหนึ่ง: เปิดใช้งาน SMTPS สำหรับไคลเอนต์ loopback เท่านั้นหรือสำหรับไคลเอนต์ใด ๆ
# 127.0.0.1:Smtps inet n - y - - smtpd
# Smtps inet n - y - - smtpd
# -o syslog_name = postfix/smtps
# -o smtpd_tls_wrappermode = ใช่
# -o smtpd_sasl_auth_enable = ใช่
# -o smtpd_reject_unlisted_recipient = no
# -o smtpd_client_restrictions = $ mua_client_restrictions
# -o smtpd_helo_restrictions = $ mua_helo_restrictions
# -o smtpd_sender_restrictions = $ mua_sender_restrictions
# -o smtpd_recipient_restrictions =
# -o smtpd_relay_restrictions = permit_sasl_authenticated, ปฏิเสธ
# -o milter_macro_daemon_name = Originating
# 628 inet n - y - - qmqpd
pickup    unix  n       -       y       60      1       pickup
cleanup   unix  n       -       y       -       0       cleanup
qmgr      unix  n       -       n       300     1       qmgr
# QMGR UNIX N - N 300 1 OQMG
tlsmgr    unix  -       -       y       1000?   1       tlsmgr
rewrite   unix  -       -       y       -       -       trivial-rewrite
bounce    unix  -       -       y       -       0       bounce
defer     unix  -       -       y       -       0       bounce
trace     unix  -       -       y       -       0       bounce
verify    unix  -       -       y       -       1       verify
flush     unix  n       -       y       1000?   0       flush
proxymap  unix  -       -       n       -       -       proxymap
proxywrite unix -       -       n       -       1       proxymap
smtp      unix  -       -       y       -       -       smtp
relay     unix  -       -       y       -       -       smtp
        -o syslog_name=postfix/$service_name
# -o smtp_helo_timeout = 5 -o smtp_connect_timeout = 5
showq     unix  n       -       y       -       -       showq
error     unix  -       -       y       -       -       error
retry     unix  -       -       y       -       -       error
discard   unix  -       -       y       -       -       discard
local     unix  -       n       n       -       -       local
virtual   unix  -       n       n       -       -       virtual
lmtp      unix  -       -       y       -       -       lmtp
anvil     unix  -       -       y       -       1       anvil
scache    unix  -       -       y       -       1       scache
postlog   unix-dgram n  -       n       -       1       postlogd
# 
# -
# อินเทอร์เฟซกับซอฟต์แวร์ที่ไม่ใช่ PostFix อย่าลืมตรวจสอบคู่มือ
# หน้าของซอฟต์แวร์ที่ไม่ใช่ PostFix เพื่อค้นหาว่าต้องการตัวเลือกใด
# 
# บริการต่อไปนี้จำนวนมากใช้การจัดส่ง Postfix Pipe (8)
# ตัวแทน.  ดูหน้า Pipe (8) Woman สำหรับข้อมูลเกี่ยวกับ $ {ผู้รับ}
# และตัวเลือกซองข้อความอื่น ๆ
# -
# 
# MailDrop ดูไฟล์ Postfix MailDrop_Readme สำหรับรายละเอียด
# ยังระบุใน main.cf: maildrop_destination_recipient_limit = 1
# 
maildrop  unix  -       n       n       -       -       pipe
  flags=DRXhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
# 
# -
# 
# รุ่น Cyrus ล่าสุดสามารถใช้รายการ "LMTP" ที่มีอยู่ในรายการ CF
# 
# ระบุใน cyrus.conf:
# lmtp cmd = "lmtpd -a" ฟัง = "localhost: lmtp" proto = tcp4
# 
# ระบุใน main.cf อย่างน้อยหนึ่งรายการต่อไปนี้:
# mailbox_transport = lmtp: inet: localhost
# virtual_transport = lmtp: inet: localhost
# 
# -
# 
# Cyrus 2.1.5 (Amos Gouaux)
# ยังระบุใน main.cf: cyrus_destination_recipient_limit = 1
# 
# Cyrus UNIX - N N - - ท่อ
# Flags = drx user = cyrus arg =/cyrus/bin/deliver -e -r $ {ผู้ส่ง} -m $ {ส่วนขยาย} $ {user}
# 
# -
# ตัวอย่างเก่าของการจัดส่งผ่านไซรัส
# 
# Old -Cyrus UNIX - N N - - PIPE
# flags = r user = cyrus argv =/cyrus/bin/deliver -e -m $ {ส่วนขยาย} $ {ผู้ใช้}
# 
# -
# 
# ดูไฟล์ postfix uucp_readme สำหรับรายละเอียดการกำหนดค่า
# 
uucp      unix  -       n       n       -       -       pipe
  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
# 
# วิธีการจัดส่งภายนอกอื่น ๆ
# 
ifmail    unix  -       n       n       -       -       pipe
  flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
bsmtp     unix  -       n       n       -       -       pipe
  flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
scalemail-backend unix -       n       n       -       2       pipe
  flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
mailman   unix  -       n       n       -       -       pipe
  flags=FRX user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py ${nexthop} ${user}
และการกำหนดค่า Opendkim Opendkim ระบุเซิร์ฟเวอร์อีเมลด้วยคีย์โดเมนเพื่อให้ปลอดภัยยิ่งขึ้น หากไม่มีมันจดหมายจะไม่ลงนามและอาจไม่ได้ไปที่กล่องจดหมาย

nano config/etc_default_opendkim
เพิ่มบรรทัดเหล่านี้:

# หมายเหตุ: นี่คือไฟล์การกำหนดค่าดั้งเดิม มันไม่ได้ใช้โดย opendkim
# บริการระบบ โปรดใช้พารามิเตอร์การกำหนดค่าที่เกี่ยวข้องใน
# /etc/opendkim.conf แทน
# 
# ก่อนหน้านี้หนึ่งจะแก้ไขการตั้งค่าเริ่มต้นที่นี่แล้วดำเนินการ
# /lib/opendkim/opendkim.service.generate เพื่อสร้าง Systemd แทนที่ไฟล์ไปที่
# /etc/systemd/system/opendkim.service.d/override.conf และ
# /etc/tmpfiles.d/opendkim.conf ในขณะที่ยังคงเป็นไปได้ แต่ตอนนี้
# แนะนำให้ปรับการตั้งค่าโดยตรงใน /etc/opendkim.conf
# 
# daemon_opts = ""
# เปลี่ยนเป็น/var/spool/postfix/run/opendkim เพื่อใช้ซ็อกเก็ต Unix ด้วย
# postfix ใน chroot:
# rundir =/was/spool/postfix/run/opendkim
RUNDIR=/run/opendkim
# 
# ไม่เกี่ยวกับการระบุช่องเสียบซ็อกเก็ตสำรอง
# โปรดทราบว่าการตั้งค่านี้จะแทนที่ค่าซ็อกเก็ตใด ๆ ใน opendkim.conf
# ค่าเริ่มต้น:
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
# ฟังทุกอินเตอร์เฟสบนพอร์ต 54321:
# ซ็อกเก็ต = inet: 54321
# ฟังบน Loopback บนพอร์ต 12345:
# ซ็อกเก็ต = inet: 12345@localhost
# ฟังคือ 192.0.2.1 คือพอร์ต 12345:
# ซ็อกเก็ต = inet: 12345@192.0.2.1
USER=opendkim
GROUP=opendkim
PIDFILE=$RUNDIR/$NAME.pid
EXTRAAFTER=

nano config/etc_dovecot_conf.d_10-master.conf
เพิ่มบรรทัดเหล่านี้:

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

# ค่าเริ่มต้น VSZ (ขนาดหน่วยความจำเสมือน) สำหรับกระบวนการบริการ นี่คือส่วนใหญ่
# ตั้งใจที่จะจับและฆ่ากระบวนการที่รั่วไหลของหน่วยความจำก่อนที่พวกเขาจะกิน
# ทุกอย่าง.
# default_vsz_limit = 256m

# ผู้ใช้เข้าสู่ระบบถูกใช้งานภายในกระบวนการเข้าสู่ระบบ นี่คือสิ่งที่ไม่น่าเชื่อถือที่สุด
# ผู้ใช้ในระบบ DoveCot ไม่ควรเข้าถึงอะไรเลย
# default_login_user = devenull

# ผู้ใช้ภายในใช้โดยกระบวนการที่ไม่มีสิทธิ์ ควรแยกออกจาก
# ผู้ใช้เข้าสู่ระบบเพื่อให้กระบวนการเข้าสู่ระบบไม่สามารถรบกวนกระบวนการอื่นได้
# default_internal_user = dovecot

service imap-login {
  inet_listener imap {
    # พอร์ต = 143
  }
  inet_listener imaps {
    # พอร์ต = 993
    # SSL = ใช่
  }

  # จำนวนการเชื่อมต่อที่จะจัดการก่อนเริ่มกระบวนการใหม่ โดยทั่วไป
  # ค่าที่มีประโยชน์เพียงอย่างเดียวคือ 0 (ไม่ จำกัด ) หรือ 1. 1 มีความปลอดภัยมากกว่า แต่ 0
  # เร็วกว่า <doc/wiki/loginprocess.txt>
  # service_count = 1

  # จำนวนกระบวนการที่จะรอการเชื่อมต่อมากขึ้นเสมอ
  # process_min_avail = 0

  # หากคุณตั้งค่า service_count = 0 คุณอาจต้องเติบโตสิ่งนี้
  # vsz_limit = $ default_vsz_limit
}

service pop3-login {
  inet_listener pop3 {
    # พอร์ต = 110
  }
  inet_listener pop3s {
    # พอร์ต = 995
    # SSL = ใช่
  }
}

service submission-login {
  inet_listener submission {
    # พอร์ต = 587
  }
}

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

  # สร้าง Inet Listener เฉพาะในกรณีที่คุณไม่สามารถใช้ซ็อกเก็ต Unix ด้านบน
  # inet_lister lmtp {
    # หลีกเลี่ยงการทำให้ LMTP สามารถมองเห็นได้สำหรับอินเทอร์เน็ตทั้งหมด
    # ที่อยู่ =
    # พอร์ต =
  # -
}

service imap {
  # หน่วยความจำส่วนใหญ่ไปที่ไฟล์ mmap () ing คุณอาจต้องเพิ่มสิ่งนี้
  # จำกัด หากคุณมีกล่องจดหมายขนาดใหญ่
  # vsz_limi = $ default_vsz_limit

  # สูงสุด จำนวนกระบวนการ IMAP (การเชื่อมต่อ)
  # process_limit = 1024
}

service pop3 {
  # สูงสุด จำนวนกระบวนการ POP3 (การเชื่อมต่อ)
  # process_limit = 1024
}

service submission {
  # สูงสุด จำนวนกระบวนการส่ง SMTP (การเชื่อมต่อ)
  # process_limit = 1024
}

service auth {
  # Auth_socket_Path ชี้ไปที่ซ็อกเก็ต UserDB นี้โดยค่าเริ่มต้น โดยทั่วไปแล้ว
  # ใช้โดย dovecot-lda, doveadm, กระบวนการ IMAP ฯลฯ
  # สิทธิ์เต็มรูปแบบสำหรับซ็อกเก็ตนี้สามารถรับรายการชื่อผู้ใช้ทั้งหมดและ
  # รับผลลัพธ์ของการค้นหา USERDB ของทุกคน
  # 
  # โหมดเริ่มต้น 0666 อนุญาตให้ทุกคนเชื่อมต่อกับซ็อกเก็ต แต่
  # userdb lookups จะประสบความสำเร็จเฉพาะในกรณีที่ userdb ส่งคืนฟิลด์ "uid" นั้น
  # ตรงกับ UID ของกระบวนการโทร นอกจากนี้หาก UID หรือ GID ของผู้โทรตรงกับไฟล์
  # UID ของซ็อกเก็ตหรือ GID การค้นหาประสบความสำเร็จ สิ่งอื่นใดทำให้เกิดความล้มเหลว
  # 
  # เพื่อให้ผู้โทรเต็มสิทธิ์ในการค้นหาผู้ใช้ทั้งหมดให้ตั้งค่าโหมดเป็น
  # อย่างอื่นนอกเหนือจาก 0666 และ DoveCot ช่วยให้เคอร์เนลบังคับใช้
  # การอนุญาต (เช่น 0777 อนุญาตให้ทุกคนได้รับอนุญาตอย่างเต็มที่)
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix
  }
}

service auth-worker {
  # กระบวนการ Auth Worker ทำงานเป็นรูทโดยค่าเริ่มต้นเพื่อให้สามารถเข้าถึงได้
  # /etc/shadow หากไม่จำเป็นผู้ใช้ควรเปลี่ยนเป็น
  # $ default_interal_user
  # ผู้ใช้ = รูท
}

service dict {
  # หากมีการใช้พร็อกซี DICT กระบวนการทางจดหมายควรมีการเข้าถึงซ็อกเก็ต
  # ตัวอย่างเช่น: mode = 0660, group = vmail และ global mail_access_groups = vmail
  unix_listener dict {
    # โหมด = 0600
    # ผู้ใช้ =
    # กลุ่ม =
  }
}
อีกครั้งตรวจสอบให้แน่ใจว่าได้แทนที่โดเมนในไฟล์เหล่านี้ทั้งหมด femmebabe.com ด้วยโดเมนที่คุณเลือก แก้ไขไฟล์ถัดไปการกำหนดค่าของ DoveCot

nano config/etc_dovecot_dovecot
และเพิ่มบรรทัดเหล่านี้

## ไฟล์การกำหนดค่า Ovecot

# หากคุณรีบไปดู http://wiki2.dovecot.org/quickconfiguration

# คำสั่ง "doveconf -n" ให้เอาต์พุตที่สะอาดของการตั้งค่าที่เปลี่ยนแปลง ใช้มัน
# แทนที่จะคัดลอกและวางไฟล์เมื่อโพสต์ไปยังรายการจดหมาย DoveCot

# '# 'ตัวละครและทุกอย่างหลังจากได้รับการปฏิบัติเป็นความคิดเห็น พื้นที่พิเศษ
# และแท็บจะถูกละเว้น หากคุณต้องการใช้อย่างใดอย่างหนึ่งอย่างชัดเจนให้ใส่ไฟล์
# value inside quotes, eg.: key = "# ถ่านและช่องว่างระหว่างทาง "

# การตั้งค่าส่วนใหญ่ (แต่ไม่ใช่ทั้งหมด) สามารถถูกแทนที่ด้วยโปรโตคอลและ/หรือ
# IPS ที่มา/ปลายทางโดยวางการตั้งค่าไว้ในส่วนต่างๆเช่น:
# โปรโตคอล IMAP {}, ท้องถิ่น 127.0.0.1 {}, รีโมต 10.0.0.0/8 {}

# ค่าเริ่มต้นจะแสดงขึ้นสำหรับการตั้งค่าแต่ละครั้งไม่จำเป็นต้องไม่มีการยกเลิก
# เหล่านั้น. นี่เป็นข้อยกเว้นสำหรับสิ่งนี้: ไม่มีส่วน (เช่นเนมสเปซ {})
# หรือการตั้งค่าปลั๊กอินจะถูกเพิ่มโดยค่าเริ่มต้นพวกเขาอยู่ในรายการเป็นตัวอย่างเท่านั้น
# เส้นทางยังเป็นเพียงตัวอย่างที่มีค่าเริ่มต้นจริงขึ้นอยู่กับการกำหนดค่า
# ตัวเลือก. เส้นทางที่แสดงที่นี่มีไว้สำหรับการกำหนดค่า -prefix =/usr
# --sysconfdir =/etc-localstatedir =/var

# เปิดใช้งานโปรโตคอลที่ติดตั้ง
!include_try /usr/share/dovecot/protocols.d/*.protocol

# รายการจุลภาคที่แยกจาก IPS หรือโฮสต์ที่จะฟังเพื่อรับการเชื่อมต่อ
# "*" ฟังในอินเทอร์เฟซ IPv4 ทั้งหมด "::" ฟังในอินเทอร์เฟซ IPv6 ทั้งหมด
# หากคุณต้องการระบุพอร์ตที่ไม่ได้รับการป้องกันหรืออะไรที่ซับซ้อนกว่านี้
# แก้ไข conf.d/master.conf
# ฟัง = *, ::

# ไดเรกทอรีพื้นฐานที่จะจัดเก็บข้อมูลรันไทม์
# base_dir =/var/run/dovecot/

# ชื่อของอินสแตนซ์นี้ ในการตั้งค่าหลายอินสแตนซ์ DOVEADM และคำสั่งอื่น ๆ
# สามารถใช้ -i <instance_name> เพื่อเลือกอินสแตนซ์ที่ใช้ (ทางเลือกอื่น
# ถึง -C <COFFING_PATH>) ชื่ออินสแตนซ์จะถูกเพิ่มในกระบวนการ DoveCot
# ในเอาต์พุต PS
# instance_name = doveCot

# ข้อความอวยพรสำหรับลูกค้า
# LOGIN_GREETING = DOVECOT พร้อม

# รายการแยกพื้นที่ของช่วงเครือข่ายที่เชื่อถือได้ การเชื่อมต่อจากสิ่งเหล่านี้
# IPS ได้รับอนุญาตให้แทนที่ที่อยู่ IP และพอร์ตของพวกเขา (สำหรับการบันทึกและ
# สำหรับการตรวจสอบการรับรองความถูกต้อง) disable_plaintext_auth ก็ถูกละเว้นสำหรับ
# เครือข่ายเหล่านี้ โดยทั่วไปคุณจะระบุเซิร์ฟเวอร์พร็อกซี IMAP ของคุณที่นี่
# LOGIN_TRUSTED_NETWORKS =

# รายการแยกพื้นที่ของซ็อกเก็ตตรวจสอบการเข้าถึงเข้าสู่ระบบ (เช่น TCPWRAP)
# login_access_sockets =

# ด้วย proxy_maybe = ใช่ถ้า proxy ปลายทางตรงกับ IP ใด ๆ เหล่านี้อย่าทำ
# พร็อกซ์ ไม่จำเป็นตามปกติ แต่อาจมีประโยชน์หากปลายทาง
# IP คือเช่น IP ของ Load Balancer
# auth_proxy_self =

# แสดงชื่อกระบวนการ verbose เพิ่มเติม (ใน PS) ปัจจุบันแสดงชื่อผู้ใช้และ
# ที่อยู่ IP มีประโยชน์สำหรับการดูว่าใครใช้กระบวนการ IMAP จริง
# (เช่นกล่องจดหมายที่ใช้ร่วมกันหรือหากใช้ UID เดียวกันสำหรับหลายบัญชี)
# verbose_proctitle = ไม่

# ควรฆ่ากระบวนการทั้งหมดเมื่อกระบวนการหลักของ DoveCot ปิดตัวลง
# การตั้งค่านี้เป็น "ไม่" หมายความว่าสามารถอัพเกรด doveCot ได้โดยไม่ต้อง
# บังคับให้การเชื่อมต่อไคลเอ็นต์ที่มีอยู่ปิด (แม้ว่าจะเป็นเช่นนั้น
# ปัญหาหากการอัพเกรดเป็นเช่น เนื่องจากการแก้ไขความปลอดภัย)
# shutdown_clients = ใช่

# หากไม่เป็นศูนย์ให้เรียกใช้คำสั่งเมลผ่านการเชื่อมต่อจำนวนมากนี้ไปยังเซิร์ฟเวอร์ DOVEADM
# แทนที่จะเรียกใช้โดยตรงในกระบวนการเดียวกัน
# doveadm_worker_count = 0
# UNIX SOCKET หรือ HOST: พอร์ตที่ใช้ในการเชื่อมต่อกับ DOVEADM SERVER
# doveadm_socket_path = doveadm-server

# รายการแยกพื้นที่ของตัวแปรสภาพแวดล้อมที่เก็บรักษาไว้ใน dovecot
# เริ่มต้นและส่งผ่านไปยังกระบวนการเด็กทั้งหมด คุณยังสามารถให้
# key = คู่ค่าเพื่อตั้งค่าการตั้งค่าเฉพาะเสมอ
# import_environment = tz

## 
## การตั้งค่าเซิร์ฟเวอร์พจนานุกรม
## 

# พจนานุกรมสามารถใช้ในการจัดเก็บคีย์ = รายการค่า สิ่งนี้ถูกใช้โดยหลาย ๆ
# ปลั๊กอิน พจนานุกรมสามารถเข้าถึงได้โดยตรงหรือแม้ว่าก
# เซิร์ฟเวอร์พจนานุกรม ชื่อพจนานุกรม Dict Block Maps ต่อไปนี้เป็น URIS
# เมื่อใช้เซิร์ฟเวอร์ สิ่งเหล่านี้สามารถอ้างอิงได้โดยใช้ uris ในรูปแบบ
# "พร็อกซี :: <ชื่อ>"

dict {
  # โควต้า = mysql: /andc/dovecot/dovecot-dic-sql.conf.ext
}

# การกำหนดค่าที่แท้จริงส่วนใหญ่จะรวมอยู่ด้านล่าง ชื่อไฟล์คือ
# จัดเรียงครั้งแรกโดยค่า ASCII และแยกวิเคราะห์ตามลำดับนั้น 00-prefixes
# ในชื่อไฟล์มีวัตถุประสงค์เพื่อให้เข้าใจการสั่งซื้อได้ง่ายขึ้น
!include conf.d/*.conf

# ไฟล์กำหนดค่าสามารถพยายามรวมได้โดยไม่ต้องให้ข้อผิดพลาดหาก
# ไม่พบ:
!include_try local.conf

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

protocols = imap pop3

# อนุญาตให้ DoveCot รับฟังการเชื่อมต่ออินพุตทั้งหมด (IPv4 / IPv6)

listen = *, ::
เพิ่มรหัสผ่านสำหรับผู้ใช้ DoveCot:

nano config/etc_dovecot_passwd
ส่วนแรกของไฟล์ก่อนที่ลำไส้ใหญ่คือชื่อผู้ใช้ ส่วนสุดท้าย“ YourPassword” หมายถึงรหัสผ่านที่คุณต้องการให้เซิร์ฟเวอร์เมลของคุณ

team:{plain}yourpassword
ถัดไปการกำหนดค่า Opendkim

nano config/etc_opendkim.conf
และเพิ่มบรรทัดเหล่านี้:

# นี่คือการกำหนดค่าพื้นฐานสำหรับการลงนามและตรวจสอบ มันสามารถทำได้อย่างง่ายดาย
# ปรับให้เหมาะกับการติดตั้งขั้นพื้นฐาน ดู opendkim.conf (5) และ
# /usr/share/doc/opendkim/examples/opendkim.conf.sample สำหรับการเสร็จสมบูรณ์
# เอกสารของพารามิเตอร์การกำหนดค่าที่มีอยู่

Syslog			yes
SyslogSuccess		yes
# logwhy no

# พารามิเตอร์การลงนามและการตรวจสอบทั่วไป ใน Debian ส่วนหัว "จาก" คือ
# oversigned เพราะมักจะเป็นคีย์ตัวตนที่ใช้โดยระบบชื่อเสียง
# และทำให้ความปลอดภัยค่อนข้างไว
Canonicalization	relaxed/simple
Mode			s
SubDomains		no
OversignHeaders		From

# การลงนามโดเมนตัวเลือกและคีย์ (จำเป็น) ตัวอย่างเช่นดำเนินการลงนาม
# สำหรับโดเมน "ตัวอย่าง" พร้อมตัวเลือก "2020" (2020._domainkey.example.com)
# การใช้คีย์ส่วนตัวที่เก็บไว้ใน /etc/dkimkeys/example.Private ละเอียดมากขึ้น
# ตัวเลือกการตั้งค่าสามารถพบได้ใน /usr/share/doc/opendkim/readme.opendkim
# domain example.com
# ตัวเลือก 2020
# keyfile /etc/dkimkeys/example.private

# ใน Debian Opendkim ทำงานเป็นผู้ใช้ "OpEndkim" จำเป็นต้องใช้ Umask ของ 007 เมื่อ
# การใช้ซ็อกเก็ตท้องถิ่นที่มี MTAs ที่เข้าถึงซ็อกเก็ตเป็นแบบไม่ได้
# ผู้ใช้ (ตัวอย่างเช่น postfix) คุณอาจต้องเพิ่ม "postfix" ของผู้ใช้เป็นกลุ่ม
# "Opendkim" ในกรณีนั้น
UserID			opendkim
UMask			007

# ซ็อกเก็ตสำหรับการเชื่อมต่อ MTA (จำเป็น) หาก MTA อยู่ในคุก Chroot
# จะต้องมั่นใจได้ว่าซ็อกเก็ตสามารถเข้าถึงได้ ใน Debian, postfix วิ่งเข้ามา
# chroot in/var/spool/postfix ดังนั้นซ็อกเก็ต Unix จะต้องเป็น
# กำหนดค่าตามที่แสดงในบรรทัดสุดท้ายด้านล่าง
# ซ็อกเก็ตท้องถิ่น: /run/opendkim/opendkim.sock
# ซ็อกเก็ต Inet: 8891@localhost
# ซ็อกเก็ต Inet: 8891
Socket			local:/var/spool/postfix/opendkim/opendkim.sock

PidFile			/run/opendkim/opendkim.pid

# โฮสต์ที่จะลงนามแทนที่จะตรวจสอบค่าเริ่มต้นคือ 127.0.0.1 ดู
# ส่วนการดำเนินการของ Opendkim (8) สำหรับข้อมูลเพิ่มเติม
# InternalHosts 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12

# สมอ Trust เปิดใช้งาน DNSSEC ใน Debian จะมีไฟล์ Anchor Trust
# โดยแพ็คเกจ DNS-Root-Data
TrustAnchorFile		/usr/share/dns/root.key
# Nameservers 127.0.0.1

# แผนที่โดเมนในจากที่อยู่ไปยังคีย์ที่ใช้ลงนามข้อความ
KeyTable           refile:/etc/opendkim/key.table
SigningTable       refile:/etc/opendkim/signing.table

# ชุดโฮสต์ภายในที่ควรมีการลงนามในจดหมาย
InternalHosts       /etc/opendkim/trusted.hosts

nano config/etc_default_opendkim
และเพิ่มบรรทัดเหล่านี้

# หมายเหตุ: นี่คือไฟล์การกำหนดค่าดั้งเดิม มันไม่ได้ใช้โดย opendkim
# บริการระบบ โปรดใช้พารามิเตอร์การกำหนดค่าที่เกี่ยวข้องใน
# /etc/opendkim.conf แทน
# 
# ก่อนหน้านี้หนึ่งจะแก้ไขการตั้งค่าเริ่มต้นที่นี่แล้วดำเนินการ
# /lib/opendkim/opendkim.service.generate เพื่อสร้าง Systemd แทนที่ไฟล์ไปที่
# /etc/systemd/system/opendkim.service.d/override.conf และ
# /etc/tmpfiles.d/opendkim.conf ในขณะที่ยังคงเป็นไปได้ แต่ตอนนี้
# แนะนำให้ปรับการตั้งค่าโดยตรงใน /etc/opendkim.conf
# 
# daemon_opts = ""
# เปลี่ยนเป็น/var/spool/postfix/run/opendkim เพื่อใช้ซ็อกเก็ต Unix ด้วย
# postfix ใน chroot:
# rundir =/was/spool/postfix/run/opendkim
RUNDIR=/run/opendkim
# 
# ไม่เกี่ยวกับการระบุช่องเสียบซ็อกเก็ตสำรอง
# โปรดทราบว่าการตั้งค่านี้จะแทนที่ค่าซ็อกเก็ตใด ๆ ใน opendkim.conf
# ค่าเริ่มต้น:
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
# ฟังทุกอินเตอร์เฟสบนพอร์ต 54321:
# ซ็อกเก็ต = inet: 54321
# ฟังบน Loopback บนพอร์ต 12345:
# ซ็อกเก็ต = inet: 12345@localhost
# ฟังคือ 192.0.2.1 คือพอร์ต 12345:
# ซ็อกเก็ต = inet: 12345@192.0.2.1
USER=opendkim
GROUP=opendkim
PIDFILE=$RUNDIR/$NAME.pid
EXTRAAFTER=
เมื่อเราพร้อมที่จะตั้งค่าเซิร์ฟเวอร์ postfix ของเราเราจะเรียกใช้รหัสด้านล่างด้วยชื่อโดเมนที่เหมาะสมที่ฝังอยู่ เริ่มต้นด้วยการสร้างสคริปต์

touch scripts/postfixsetup
sudo chmod a+x scripts/postfixsetup
nano scripts/postfixsetup
ตอนนี้ในนาโนตัวแก้ไขข้อความแก้ไขไฟล์นี้เพื่อให้มีชื่อโดเมนของคุณแทน femmebabe.com

# !
# การตั้งค่า postfix
cd $DIR
echo "Mail services configuration"
sudo cp /etc/postfix/main.cf /etc/postfix/main.cf.backup
sudo cp config/etc_postfix_main.cf /etc/postfix/main.cf
sudo cp config/etc_postfix_master.cf /etc/postfix/master.cf
sudo cp config/etc_default_opendkim /etc/default/opendkim
sudo cp config/etc_dovecot_conf.d_10-auth.conf /etc/dovecot/conf.d/10-auth.conf
sudo cp config/etc_dovecot_conf.d_10-master.conf /etc/dovecot/conf.d/10-master.conf
sudo cp config/etc_dovecot_dovecot.conf /etc/dovecot/dovecot.conf
sudo cp config/etc_dovecot_passwd /etc/dovecot/passwd
sudo cp config/etc_opendkim.conf /etc/opendkim.conf
sudo cp config/etc_default_opendkim /etc/default/opendkim
sudo adduser postfix opendkim
sudo mkdir /etc/opendkim
sudo mkdir /etc/opendkim/keys
sudo mkdir /etc/opendkim/keys/femmebabe.com
sudo mkdir /var/spool/postfix/opendkim
sudo echo "*@femmebabe.com     sendonly._domainkey.femmebabe.com" | sudo tee -a /etc/opendkim/signing.table
sudo echo "sendonly._domainkey.femmebabe.com    femmebabe.com:sendonly:/etc/opendkim/keys/femmebabe.com/sendonly.private" | sudo tee -a /etc/opendkim/key.table
sudo echo "127.0.0.1" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "localhost" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "*.femmebabe.com" | sudo tee -a /etc/opendkim/trusted.hosts
sudo chown -R opendkim:opendkim /etc/opendkim
sudo opendkim-genkey -b 2048 -d femmebabe.com -D /etc/opendkim/keys/femmebabe.com -s sendonly -v
sudo chmod go-rw /etc/opendkim/keys
sudo chown opendkim:opendkim /etc/opendkim/keys/femmebabe.com/sendonly.private
sudo chown opendkim:postfix /var/spool/postfix/opendkim
cd $DIR
sudo cp mailbox/* /var/mail/
sudo chown :users /var/mail/*
sudo chmod -R a+rwx /var/mail/*
sudo systemctl restart opendkim postfix dovecot
sudo cat /etc/opendkim/keys/femmebabe.com/sendonly.txt | tr -d '\n' | sed 's/\s//g' | sed 's/""//g' | awk -F'[)(]' '{print $2}'
ตอนนี้เรียกใช้สคริปต์ที่เสร็จสมบูรณ์เพื่อกำหนดค่า postfix, opendkim และ dovecot

./scripts/postfixsetup
เมื่อสคริปต์นี้ทำงานแล้วให้คัดลอกบรรทัดสุดท้ายที่พิมพ์และวางลงในการกำหนดค่า DNS ของคุณเป็นค่าสำหรับ sendonly._domainkey นี่คือคีย์ OpendKim ที่ใช้ในการระบุโดเมนของคุณเมื่อส่งจดหมายที่ปลอดภัย สุดยอด! ภายในไม่กี่วันคุณควรจะสามารถส่งจดหมายจากเซิร์ฟเวอร์ได้หากมีการกำหนดค่าทุกอย่างอย่างถูกต้อง หากคุณเพิ่งกำหนดค่า DNS สำหรับเซิร์ฟเวอร์เมลของคุณควรใช้เวลาน้อยกว่า 72 ชั่วโมงเพื่อให้บันทึกการอัปเดต โดยปกติแล้วจะเร็วกว่ามาก คุณสามารถตรวจสอบว่าเซิร์ฟเวอร์ของคุณทำงานโดยใช้คำสั่งนี้หรือไม่ให้อีเมลของคุณ:

echo “test” | mail -s “Test Email” youremail@gmail.com
หากทุกอย่างดูเหมือนจะทำงานได้อย่างถูกต้องคุณควรส่งอีเมลพร้อมเซิร์ฟเวอร์ของคุณ หากไม่ทำงานให้ลองดูบันทึกเพื่อดูว่าข้อผิดพลาดอาจเป็นอย่างไร

tail –lines 150 /var/log/mail.log
สิ่งนี้จะให้ข้อมูล verbose เกี่ยวกับจดหมายที่เซิร์ฟเวอร์ส่งและไม่ว่าจะทำงานได้อย่างถูกต้องหรือไม่ คุณควรจะเห็นอีเมลในกล่องจดหมายของคุณเช่นกันหากไม่มีให้ตรวจสอบโฟลเดอร์สแปมของคุณ คุณจะต้องกำหนดค่าการตั้งค่าของคุณในการตั้งค่าของคุณ py เพื่อให้เซิร์ฟเวอร์อีเมลของคุณสามารถพูดคุยกับแอพ Django ของคุณโครงการ เพิ่มหรือแทนที่บรรทัดเหล่านี้ในการตั้งค่าของคุณ

EMAIL_HOST = DOMAIN
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_ADDRESS = 'team@femmebabe.com'
EMAIL_HOST_USER = 'team' # 'love@mamasheen.com'
EMAIL_HOST_PASSWORD = config['EMAIL_HOST_PASSWORD']
DEFAULT_FROM_EMAIL = '{} <{}>'.format(SITE_NAME, EMAIL_HOST_USER)
ขอให้สังเกตว่าเรากำลังใช้ไฟล์กำหนดค่าเพื่อรับรหัสผ่าน มาโหลดไฟล์นี้ในการตั้งค่าเช่นกันที่จุดเริ่มต้นของไฟล์:

import os
import json

# เปิดและโหลดการกำหนดค่า
with open('/etc/config.json') as config_file:
    config = json.load(config_file)
มาสร้างไฟล์นี้และเพิ่มคีย์ลับให้กับมันรวมถึงรหัสผ่านเมล ในการสร้างคีย์ลับให้ใช้คำสั่งนี้โดยที่คุณต้องการความยาวใด ๆ ในตอนท้าย:

openssl rand -base64 64
ตอนนี้คัดลอกข้อความที่ OpenSSL สร้างขึ้นและแก้ไข /etc/config.json

sudo nano /etc/config.json
เพิ่มบรรทัดต่อไปนี้ในไฟล์ของคุณด้วยคีย์ที่ OpenSSL สร้างเป็นคีย์ลับ

{
	"SECRET_KEY": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX-generated-using-openssl)",
	"EMAIL_HOST_PASSWORD": "yourpassword"
}
รูปแบบ JSON นั้นง่ายและใช้งานง่ายเราสามารถประกาศคีย์อื่น ๆ ที่เราต้องการใช้ในโครงการของเราด้วยวิธีนี้เช่นกันและแยกพวกเขาออกจากไดเรกทอรีโครงการของเราเพื่อให้ผู้ใช้รายอื่นไม่สามารถเขียนถึงพวกเขาได้ จากไดเรกทอรีโครงการของเราเพียงอย่างเดียว นี่คือวิธีปฏิบัติที่แนะนำสำหรับคีย์ API ซึ่งเราจะใช้มากกว่าสองสามที่นี่ นอกจากนี้คุณยังต้องการสำรองโครงการของคุณเพื่อให้แน่ใจว่าทุกอย่างได้รับการบันทึกและคุณจะสามารถกู้คืนงานของคุณได้ในภายหลังแม้ว่าคุณจะไม่ต้องการเช่าเซิร์ฟเวอร์อีกต่อไป

sudo backup
ตอนนี้ลองส่งอีเมล HTML จากเว็บเซิร์ฟเวอร์โดยมีการส่งข้อความจากบรรทัดคำสั่งใช้งานได้ สอบถามอินสแตนซ์ของผู้ใช้ของคุณในเชลล์และส่งอีเมล HTML ไปยังผู้ใช้นั้นผ่าน Django เปลี่ยนชื่อของฉันในรหัส Charlotte เป็นชื่อผู้ใช้ของคุณ

python manage.py shell
from django.contrib.auth.models import User
u = User.objects.get(username='Charlotte')
from users.email import send_welcome_email
send_welcome_email(u)
exit()
หากคำสั่งแรกไม่ทำงานตรวจสอบให้แน่ใจว่าใช้

source venv/bin/activate
ให้การตั้งค่าทุกอย่างอย่างถูกต้องตอนนี้คุณจะได้รับอีเมลต้อนรับในกล่องจดหมายของคุณที่ส่งโดยเว็บแอปของคุณ ทำได้ดีมาก! คุณมาไกล ฉันต้องการเพิ่มหากคุณเคยดิ้นรนกับข้อผิดพลาดใด ๆ เลยในขณะที่ทำงานในโครงการเช่นนี้อย่าลังเลที่จะค้นหาคำตอบและขอความช่วยเหลือ Google ในบรรดาเครื่องมือค้นหาอื่น ๆ เป็นแหล่งข้อมูลที่ยอดเยี่ยมในการค้นหาความช่วยเหลือในการเขียนโปรแกรม เพียงค้นหาข้อผิดพลาดที่คุณได้รับและคุณจะสามารถดูว่าคนอื่นแก้ปัญหาได้อย่างไร นอกจากนี้คุณยินดีที่จะติดต่อฉันนักการศึกษาของคุณ (อาจารย์อาจารย์ผู้สอน) เพื่อนร่วมงานทุกคนบนอินเทอร์เน็ตที่พร้อมสำหรับความช่วยเหลือในการเขียนโปรแกรมหรือปรึกษาหนังสือเล่มนี้อีกครั้งหรือแหล่งข้อมูลอื่น ๆ เพื่อค้นหาวิธีแก้ไขปัญหาที่คุณประสบ ฉันเข้าใจว่านี่ไม่ใช่เรื่องง่าย แต่แม้ว่าคุณจะได้อ่านในตอนนี้และไม่ได้เขียนโค้ดใด ๆ คุณกำลังเรียนรู้มากมายเกี่ยวกับการสร้างเว็บแอปตั้งแต่เริ่มต้น ตบหลังตัวเองคุณทำได้ดีมากงาน. ขอขอบคุณที่สละเวลาอ่านคู่มือการพัฒนาเว็บฉบับที่สามนี้ ในรุ่นอนาคตฉันจะรวมตัวอย่างสำคัญเพิ่มเติมที่กล่าวถึงในตอนต้นของเอกสารและเราจะดำน้ำลึกลงไปในโลกของการพัฒนาซอฟต์แวร์และฮาร์ดแวร์ คอยติดตามสิ่งที่จะเกิดขึ้นและฉันหวังว่าจะได้สอนคุณถึงวิธีการสร้างซอฟต์แวร์ที่น่าทึ่ง พบกันใหม่






ปิด
หน้าหนังสือ 1
กระโดด
ดูบทความฉบับเต็ม
อ่านต่อ

ซื้อ | ซื้อด้วย crypto



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


(คลิกหรือแตะเพื่อดาวน์โหลดภาพ)
ความบันเทิงระดับมืออาชีพ, ภาพถ่าย, วิดีโอ, เสียง, การถ่ายทอดสดและการเล่นเกมแบบไม่เป็นทางการรวมถึงการสแกน ID, การพัฒนาเว็บและบริการการตั้งครรภ์แทน

ทิ้งเคล็ดลับไว้ใน Bitcoin โดยใช้ที่อยู่นี้: 3KhDWoSve2N627RiW8grj6XrsoPT7d6qyE

© Glam Girl X 2025

ข้อกำหนด