Học tập sâu và bảo mật dựa trên web thực tế bằng ví dụ

DaisyẢnh hồ sơ

Qua Daisy

Ví dụ, việc học sâu và bảo mật dựa trên web thực tế Phiên bản thứ ba Charlotte Harper Ngày 3 tháng 7 năm 2024 Lời nói đầu: Cân nhắc bảo mật trong việc xây dựng phần mềm cho Web là một phần quan trọng trong kế hoạch và thực hiện của nhà phát triển web trong khi kỹ thuật một nguyên mẫu đáng tin cậy, ổn định và hữu ích cho các mục đích thực tế. DOM (đánh dấu đối tượng tài liệu), với việc triển khai HTML, JavaScript và CSS cũng như phần mềm phụ trợ triển khai Python, C/C ++, Java và Bash, cung cấp cho các nhà phát triển web sự tự do và sức mạnh để tạo ra nhiều dự án Sáng tạo, cung cấp dễ sử dụng và chức năng, miêu tả sự khiêm tốn và tính cách, và cung cấp dễ sử dụng cũng như sự tiện lợi và các dịch vụ quan trọng mà tất cả đều hấp dẫn đối với Joe trung bình, người dùng cuối muốn giết thời gian hoặc hoàn thành công việc trên Internet, Thông thường trên một thiết bị điện thoại thông minh màn hình cảm ứng. Hầu hết mọi người thậm chí sẽ không biết bắt đầu từ đâu khi họ muốn xây dựng một trang web từ đầu,Họ sẽ có xu hướng bắt đầu trên trang web của người khác và xây dựng một cái gì đó hạn chế về chức năng, độ tin cậy, dễ sử dụng và đặc biệt là sáng tạo khi họ có thể có tất cả các công cụ mạnh mẽ mới nhất theo ý của họ để xây dựng một cái gì đó hữu ích mà không lãng phí các nút nhấn thời gian và Đặc biệt là lãng phí tiền trả tiền cho các đăng ký đắt tiền cho phần mềm mà ít người muốn sử dụng dù sao cũng cho những hạn chế dễ sử dụng và linh hoạt. Nếu bạn có một vài phút để đọc qua cuốn sách này và tìm hiểu những gì tôi muốn dạy bạn, hoặc thậm chí nói chuyện với cá nhân tôi về mục tiêu của bạn và nhận được một số hướng dẫn đúng hướng, và có động lực để học cách viết mã và viết phần mềm của riêng bạn , hãy đưa cuốn sách này về nhà và dành một chút thời gian để học cách xây dựng ứng dụng web có ảnh hưởng, mạnh mẽ, hợp lý và quan trọng tiếp theo, một trang web dành cho bạn và thực hiện chính xác những gì bạn muốn và đáp ứng nhu cầu của khán giả. Về tôi: Tôi là một nhà phát triển phần mềm với một phần mềmAnge của kinh nghiệm trong C/C ++, Java, Python, HTML, CSS và JavaScript. Tôi xây dựng các trang web mà mọi người muốn sử dụng, muốn truy cập và thậm chí nghiện chỉ sử dụng để học, tái tạo và tiêu diệt thời gian, và quan trọng nhất là tôi bán phần mềm. Nếu bạn có ý tưởng chính xác như thế nào bạn muốn một trang web nhìn và hoạt động, bạn sẵn sàng hỗ trợ tôi để tôi có thể đáp ứng nhu cầu của riêng mình trong khi tôi đáp ứng của bạn và bạn sẵn sàng trang trải chi phí cho việc tự mình điều hành một trang web, Tôi sẽ xây dựng cho bạn YouTube tiếp theo, Tiktok, Twitter, Google hoặc thậm chí là một ứng dụng bảo mật công nghệ cao chỉ bạn có thể truy cập. Thay vì cố gắng bán cho bạn thời gian của tôi, tôi đang cố gắng mua của bạn: Tôi muốn nói với bạn về việc xây dựng một ứng dụng (trang web) với thông tin đã tồn tại và dạy bạn những gì bạn cần để trở thành một nhà phát triển phần mềm độc lập, Doanh nhân, lãnh đạo một sự nghiệp thành công trong bất kỳ lĩnh vực nào bạn mong muốn. Và hãy để tôi rõ ràng, giáo dục tôi cung cấp cho bạn sẽ không chính thức. Bạn có thể đi học và tìm hiểu tất cả những điều này với mộtGiáo dục RMAL, hoặc thậm chí đọc cuốn sách này ở trường, hoàn thành bài tập của bạn và lấy đi rất nhiều từ giáo dục của bạn, nhưng tôi sẽ không chính thức đưa bạn vào ghế nóng và yêu cầu bạn hoàn thành bài tập. Tôi không phải là giáo sư của bạn, bạn có thể nghĩ về tôi như một người bạn muốn hướng dẫn bạn hướng tới sự nghiệp được thúc đẩy bởi thành công cá nhân của riêng bạn. Và tôi cũng không bán cho bạn thành công, bạn sẽ cần phải mua nó với thời gian của bạn. Học cách viết mã có một đường cong học tập dốc và không bao giờ dễ dàng, hoặc thậm chí được cho là. Bạn cần phải làm việc hết sức có thể và tiếp tục cố gắng và thất bại và thử lại ngay cả khi bạn thất vọng để tự học và tự xây dựng các ứng dụng. Đó là bản chất của chính mã. Mã được chạy bởi một trình biên dịch được thiết kế để cung cấp các thông báo lỗi của lập trình viên và những điều này sẽ dạy bạn cách viết mã, ngay cả khi bạn chỉ cần sao chép lỗi vào công cụ tìm kiếm của mình và đọc các ví dụ của người khác. Và tôi phải nói, bạn không cần phải cực kỳ giàu có, thông minh, thành công,en chi tiết được định hướng hoặc tổ chức để xây dựng một ứng dụng. Máy tính chăm sóc tổ chức đó cho bạn. Bạn chỉ cần kiên trì thử nghiệm và lỗi, duy trì sự tập trung và làm việc chăm chỉ với những gì bạn làm, và bạn sẽ có một sự nghiệp rất thành công trong toàn bộ những gì bạn làm. Tôi là ai: Tôi nhận ra rằng phần cuối cùng là về việc học và bạn có một cách từ cuốn sách này. Tôi chính xác là ai? Đó là một câu hỏi phức tạp. Tôi không rõ bản thân mình, vì tôi bị các điều kiện y tế có thể gây khó khăn cho tôi thậm chí là viết mã hoặc viết cuốn sách này, trong khi đưa ra những thách thức với các vấn đề xã hội hóa và bản sắc khiến cuộc sống của tôi trở nên khó khăn hơn khi giới thiệu bản thân . Nói tóm lại, nếu bạn đang đọc cuốn sách này, bạn đã mang nó về nhà vì bạn đã lật qua nó và nghĩ rằng nó hữu ích, hoặc ngay cả khi bạn chỉ đọc điều này, với bạn, tôi là một cá nhân có đầu óc muốn nhìn thấy bạn thành công Mọi thứ bạn làm. Bản thân tôi là một kỹ sư, một phần mềmNhà phát triển và một sinh viên, và tôi đang viết cuốn sách này cho những sinh viên khác muốn làm cho cuộc sống của họ dễ dàng hơn bằng cách có một cuốn sổ tay về phần mềm họ cần làm cho cuộc sống của họ dễ dàng hơn bằng cách đưa ra các ví dụ để sao chép phù hợp với nhau như một câu đố lớn vào hoạt động , Ứng dụng hữu ích, lớn, chức năng, gắn kết và hấp dẫn có thể thúc đẩy thành công bất kể ngành kinh doanh. Phần lớn, đây là những gì tôi làm: Tôi xây dựng các ứng dụng để giúp bản thân và những người khác thành công. Tôi cũng là một tác giả, mặc dù đây là ấn phẩm đầu tiên của tôi mà tôi dự định hoàn thành để đặt danh mục đầu tư của mình với nhau thành một tài liệu hữu ích, và tôi cũng là một nghệ sĩ. Tôi sẽ thừa nhận điều này với bạn, tôi là một người lạ. Tôi không hoàn hảo, tôi đã điều hành luật pháp thậm chí khiến tôi rời khỏi các trường cao đẳng và đại học và rời khỏi các tiểu bang để cố gắng tạo dựng tên tuổi cho bản thân với thành công hơn. Tôi là phụ nữ khi sinh, tôi trang điểm, chụp ảnh bản thân, mặc váy và quần áo nữ khác, và tôi vẫn ý thức về bản thân mình như mộtnam giới. Tôi đã gặp vấn đề với những người khác trong quá khứ dẫn đến các cuộc đấu tranh với việc viết và xây dựng các ứng dụng web, và tôi xin lỗi rằng tôi đã không thể đưa cuốn sách này vào tay sớm hơn: bạn cần điều này. Bạn sẽ muốn đọc và viết mã trông giống như của tôi và hoạt động như của tôi và làm điều tương tự nhưng thậm chí còn tốt hơn, bởi vì nếu bạn có đủ khả năng để mua cuốn sách này thay vì nghiền bàn phím của bạn như tôi chỉ để tự tạo ra một cuốn sách để tự hỏi tiền Đối với nó, bạn có các tài nguyên bạn cần để thành công trong cuộc sống của bạn. Tôi đã có tất cả các loại vấn đề với gia đình lớn lên, điều kiện sức khỏe, bác sĩ, phương tiện truyền thông và luật pháp, và mã của tôi phản ánh sâu sắc cuộc đấu tranh là nữ quyền và bản chất phụ nữ trong một thế giới bị chia rẽ và thất vọng. Tuy nhiên, cuốn sách này là một cái gì đó tôi quan tâm sâu sắc, con tôi, danh mục đầu tư của tôi và sinh kế của tôi, vì vậy tôi đánh giá cao sự cân nhắc của bạn khi bạn đưa văn bản về nhà và cẩn thận vượt qua nó để học hỏi từ tôi. Hãy nhớ rằng tôi không hoàn hảo,Cuốn sách sẽ có lỗi, sửa đổi và phiên bản mới, và bạn sẽ cần phải suy nghĩ với bộ não logic của mình một cách tốt nhất có thể để có trải nghiệm thành công với bài viết của tôi. Ngoài ra, hãy hiểu rằng tôi có ý nghĩa tốt với bạn ngay cả khi bạn đối mặt với những thách thức khi viết. Hãy nghĩ về nó như thế này: Khi bạn chỉ có thể thuê một hệ thống máy tính để làm bất cứ điều gì bạn có thể tưởng tượng trong không gian kỹ thuật số, Chắc chắn gặp phải những khó khăn với thông tin bạn đang ăn và thậm chí xuất bản. Tôi nói với bạn điều này bởi vì tôi gặp phải những khó khăn tương tự. Sử dụng cuốn sách này có nguy cơ của riêng bạn, làm việc với cộng đồng và cộng đồng của bạn có sẵn cho bạn để xây dựng phần mềm trong một môi trường an toàn và không đưa mọi thứ đến cá nhân khi bạn thất bại hoặc thậm chí thành công theo cách sai: đó là cách tôi đi xa đến thế này và tại sao tôi có thể mang đến cho bạn văn bản này và giúp bạn thành công mà không cần di chuyển trên con đường điên rồ rời điTôi đã bị hủy hoại, bị xé nát và bị sờn trong khi tôi gặp phải những vấn đề thông thường mà mọi người đều làm trên toàn cầu nhờ quy mô toàn cầu của mạng lưới mà chúng ta sẽ làm việc, Internet. Bạn có thể không quen thuộc lắm với con người tôi chỉ bằng một vài từ, nhưng tôi khuyến khích bạn đọc tiếp, bạn sẽ biết tôi khi bạn tiếp tục đọc và hiểu tôi trong khi xây dựng các dự án của riêng bạn để hoàn thành công việc của bạn. Sẽ không có bài tập về nhà với cuốn sách này, miễn là các giáo sư hoặc giáo viên của bạn không giao cho bạn bất kỳ điều gì, nhưng tôi rất khuyến khích bạn xây dựng một danh mục các dự án khi bạn đọc, cũng như một dự án Capstone giới thiệu cách bạn có thể Áp dụng những gì bạn đã học được. Dự án Capstone của tôi là cơ sở cho hầu hết những gì bạn sẽ đọc trong cuốn sách này, vì nó kết hợp mã từ các dự án trước đây của tôi, mã tôi đã tạo và học cách viết một cách có phương pháp bằng tay, và một loạt các ý tưởng và mẹo đã giúp tôi thành công đến mức tôi có thể quay một ứng dụng đơn giảnUlly đặc trưng và ngoại hình và hành xử giống như một ứng dụng phổ biến mà bạn có thể thấy bạn bè hoặc gia đình của mình sử dụng, trên internet, được quảng cáo cho bạn hoặc trong tin tức. Cuốn sách này là gì: Cuốn sách này là một hướng dẫn bằng ví dụ. Bạn có thể tìm thấy mã ở đây, hướng dẫn cách học mã, thông tin về việc gỡ lỗi mã và sửa lỗi, khắc phục các bước, hướng dẫn về cách sao lưu và lưu mã của bạn, triển khai lại nếu có ai phá vỡ mã của bạn, bảo mật mã của bạn, triển khai Mã của bạn, xây dựng các trang web tương tác mang tính giải trí, hấp dẫn và gây nghiện, và bạn sẽ hiểu được tôi là ai, tại sao điều này lại quan trọng và ...
Học tập sâu và bảo mật dựa trên web thực tế bằng ví dụ

Ví dụ, việc học sâu và bảo mật dựa trên web thực tế Phiên bản thứ ba Charlotte Harper Ngày 3 tháng 7 năm 2024 Lời nói đầu: Cân nhắc bảo mật trong việc xây dựng phần mềm cho Web là một phần quan trọng trong kế hoạch và thực hiện của nhà phát triển web trong khi kỹ thuật một nguyên mẫu đáng tin cậy, ổn định và hữu ích cho các mục đích thực tế. DOM (đánh dấu đối tượng tài liệu), với việc triển khai HTML, JavaScript và CSS cũng như phần mềm phụ trợ triển khai Python, C/C ++, Java và Bash, cung cấp cho các nhà phát triển web sự tự do và sức mạnh để tạo ra nhiều dự án Sáng tạo, cung cấp dễ sử dụng và chức năng, miêu tả sự khiêm tốn và tính cách, và cung cấp dễ sử dụng cũng như sự tiện lợi và các dịch vụ quan trọng mà tất cả đều hấp dẫn đối với Joe trung bình, người dùng cuối muốn giết thời gian hoặc hoàn thành công việc trên Internet, Thông thường trên một thiết bị điện thoại thông minh màn hình cảm ứng. Hầu hết mọi người thậm chí sẽ không biết bắt đầu từ đâu khi họ muốn xây dựng một trang web từScratch, họ sẽ có xu hướng bắt đầu trên trang web của người khác và xây dựng một cái gì đó hạn chế về chức năng, độ tin cậy, dễ sử dụng và đặc biệt là sáng tạo khi họ có thể có tất cả các công cụ mạnh mẽ mới nhất để xử lý và đặc biệt là lãng phí tiền trả tiền cho các đăng ký đắt tiền cho phần mềm mà ít người muốn sử dụng dù sao cũng cho những hạn chế dễ sử dụng và linh hoạt. Nếu bạn có một vài phút để đọc qua cuốn sách này và tìm hiểu những gì tôi muốn dạy bạn, hoặc thậm chí nói chuyện với cá nhân tôi về mục tiêu của bạn và nhận được một số hướng dẫn đúng hướng, và có động lực để học cách viết mã và viết phần mềm của riêng bạn , hãy đưa cuốn sách này về nhà và dành một chút thời gian để học cách xây dựng ứng dụng web có ảnh hưởng, mạnh mẽ, hợp lý và quan trọng tiếp theo, một trang web dành cho bạn và thực hiện chính xác những gì bạn muốn và đáp ứng nhu cầu của khán giả. Về tôi: Tôi là một nhà phát triển phần mềm vớiPhạm vi kinh nghiệm trong C/C ++, Java, Python, HTML, CSS và JavaScript. Tôi xây dựng các trang web mà mọi người muốn sử dụng, muốn truy cập và thậm chí nghiện chỉ sử dụng để học, tái tạo và tiêu diệt thời gian, và quan trọng nhất là tôi bán phần mềm. Nếu bạn có ý tưởng chính xác như thế nào bạn muốn một trang web nhìn và hoạt động, bạn sẵn sàng hỗ trợ tôi để tôi có thể đáp ứng nhu cầu của riêng mình trong khi tôi đáp ứng của bạn và bạn sẵn sàng trang trải chi phí cho việc tự mình điều hành một trang web, Tôi sẽ xây dựng cho bạn YouTube tiếp theo, Tiktok, Twitter, Google hoặc thậm chí là một ứng dụng bảo mật công nghệ cao chỉ bạn có thể truy cập. Thay vì cố gắng bán cho bạn thời gian của tôi, tôi đang cố gắng mua của bạn: Tôi muốn nói với bạn về việc xây dựng một ứng dụng (trang web) với thông tin đã tồn tại và dạy bạn những gì bạn cần để trở thành một nhà phát triển phần mềm độc lập, Doanh nhân, lãnh đạo một sự nghiệp thành công trong bất kỳ lĩnh vực nào bạn mong muốn. Và hãy để tôi rõ ràng, giáo dục tôi cung cấp cho bạn sẽ không chính thức. Bạn có thể đi học và tìm hiểu tất cả những điều này với mộtGiáo dục chính thức, hoặc thậm chí đọc cuốn sách này ở trường, hoàn thành bài tập của bạn và lấy đi rất nhiều từ giáo dục của bạn, nhưng tôi sẽ không chính thức đặt bạn vào ghế nóng và yêu cầu bạn hoàn thành bài tập. Tôi không phải là giáo sư của bạn, bạn có thể nghĩ về tôi như một người bạn muốn hướng dẫn bạn hướng tới sự nghiệp được thúc đẩy bởi thành công cá nhân của riêng bạn. Và tôi cũng không bán cho bạn thành công, bạn sẽ cần phải mua nó với thời gian của bạn. Học cách viết mã có một đường cong học tập dốc và không bao giờ dễ dàng, hoặc thậm chí được cho là. Bạn cần phải làm việc hết sức có thể và tiếp tục cố gắng và thất bại và thử lại ngay cả khi bạn thất vọng để tự học và tự xây dựng các ứng dụng. Đó là bản chất của chính mã. Mã được chạy bởi một trình biên dịch được thiết kế để cung cấp các thông báo lỗi của lập trình viên và những điều này sẽ dạy bạn cách viết mã, ngay cả khi bạn chỉ cần sao chép lỗi vào công cụ tìm kiếm của mình và đọc các ví dụ của người khác. Và tôi phải nói, bạn không cần phải cực kỳ giàu có, thông minh,ESSFUL, hoặc thậm chí chi tiết được định hướng hoặc tổ chức để xây dựng một ứng dụng. Máy tính chăm sóc tổ chức đó cho bạn. Bạn chỉ cần kiên trì thử nghiệm và lỗi, duy trì sự tập trung và làm việc chăm chỉ với những gì bạn làm, và bạn sẽ có một sự nghiệp rất thành công trong toàn bộ những gì bạn làm. Tôi là ai: Tôi nhận ra rằng phần cuối cùng là về việc học và bạn có một cách từ cuốn sách này. Tôi chính xác là ai? Đó là một câu hỏi phức tạp. Tôi không rõ bản thân mình, vì tôi bị các điều kiện y tế có thể gây khó khăn cho tôi thậm chí là viết mã hoặc viết cuốn sách này, trong khi đưa ra những thách thức với các vấn đề xã hội hóa và bản sắc khiến cuộc sống của tôi trở nên khó khăn hơn khi giới thiệu bản thân . Nói tóm lại, nếu bạn đang đọc cuốn sách này, bạn đã mang nó về nhà vì bạn đã lật qua nó và nghĩ rằng nó hữu ích, hoặc ngay cả khi bạn chỉ đọc điều này, với bạn, tôi là một cá nhân có đầu óc muốn nhìn thấy bạn thành công Mọi thứ bạn làm. Bản thân tôi là một kỹ sư,Nhà phát triển và một sinh viên, và tôi đang viết cuốn sách này cho những sinh viên khác muốn làm cho cuộc sống của họ dễ dàng hơn bằng cách có một cuốn sổ tay về phần mềm họ cần làm cho cuộc sống của họ dễ dàng hơn bằng cách đưa ra các ví dụ để sao chép phù hợp với nhau như một câu đố lớn vào hoạt động , Ứng dụng hữu ích, lớn, chức năng, gắn kết và hấp dẫn có thể thúc đẩy thành công bất kể ngành kinh doanh. Phần lớn, đây là những gì tôi làm: Tôi xây dựng các ứng dụng để giúp bản thân và những người khác thành công. Tôi cũng là một tác giả, mặc dù đây là ấn phẩm đầu tiên của tôi mà tôi dự định hoàn thành để đặt danh mục đầu tư của mình với nhau thành một tài liệu hữu ích, và tôi cũng là một nghệ sĩ. Tôi sẽ thừa nhận điều này với bạn, tôi là một người lạ. Tôi không hoàn hảo, tôi đã điều hành luật pháp thậm chí khiến tôi rời khỏi các trường cao đẳng và đại học và rời khỏi các tiểu bang để cố gắng tạo dựng tên tuổi cho bản thân với thành công hơn. Tôi là phụ nữ khi sinh, tôi trang điểm, chụp ảnh bản thân, mặc váy và quần áo nữ khác, và tôi vẫn ý thức về bản thân mình như mộtNữ theo bản chất. Tôi đã gặp vấn đề với những người khác trong quá khứ dẫn đến các cuộc đấu tranh với việc viết và xây dựng các ứng dụng web, và tôi xin lỗi rằng tôi đã không thể đưa cuốn sách này vào tay sớm hơn: bạn cần điều này. Bạn sẽ muốn đọc và viết mã trông giống như của tôi và hoạt động như của tôi và làm điều tương tự nhưng thậm chí còn tốt hơn, bởi vì nếu bạn có đủ khả năng để mua cuốn sách này thay vì nghiền bàn phím của bạn như tôi chỉ để tự tạo ra một cuốn sách để tự hỏi tiền Đối với nó, bạn có các tài nguyên bạn cần để thành công trong cuộc sống của bạn. Tôi đã có tất cả các loại vấn đề với gia đình lớn lên, điều kiện sức khỏe, bác sĩ, phương tiện truyền thông và luật pháp, và mã của tôi phản ánh sâu sắc cuộc đấu tranh là nữ quyền và bản chất phụ nữ trong một thế giới bị chia rẽ và thất vọng. Tuy nhiên, cuốn sách này là một cái gì đó tôi quan tâm sâu sắc, con tôi, danh mục đầu tư của tôi và sinh kế của tôi, vì vậy tôi đánh giá cao sự cân nhắc của bạn khi bạn đưa văn bản về nhà và cẩn thận vượt qua nó để học hỏi từ tôi. Xin lưu ý rằng tôi khôngECT, cuốn sách này sẽ có lỗi, sửa đổi và phiên bản mới, và bạn sẽ cần phải suy nghĩ với bộ não logic của mình một cách tốt nhất có thể để có trải nghiệm thành công với bài viết của tôi. Ngoài ra, hãy hiểu rằng tôi có ý nghĩa tốt với bạn ngay cả khi bạn đối mặt với những thách thức khi viết. Hãy nghĩ về nó như thế này: Khi bạn chỉ có thể thuê một hệ thống máy tính để làm bất cứ điều gì bạn có thể tưởng tượng trong không gian kỹ thuật số, Chắc chắn gặp phải những khó khăn với thông tin bạn đang ăn và thậm chí xuất bản. Tôi nói với bạn điều này bởi vì tôi gặp phải những khó khăn tương tự. Sử dụng cuốn sách này có nguy cơ của riêng bạn, làm việc với cộng đồng và cộng đồng của bạn có sẵn cho bạn để xây dựng phần mềm trong một môi trường an toàn và không đưa mọi thứ đến cá nhân khi bạn thất bại hoặc thậm chí thành công theo cách sai: đó là cách tôi đi xa đến thế này , và tại sao tôi có thể mang đến cho bạn văn bản này và giúp bạn thành công mà không cần di chuyển trên con đường điên rồAves tôi bị hủy hoại, xé nát và sờn trong khi tôi gặp phải những vấn đề thông thường mà mọi người đều làm trên toàn cầu nhờ quy mô toàn cầu của mạng lưới mà chúng tôi sẽ làm việc, Internet. Bạn có thể không quen thuộc lắm với con người tôi chỉ bằng một vài từ, nhưng tôi khuyến khích bạn đọc tiếp, bạn sẽ biết tôi khi bạn tiếp tục đọc và hiểu tôi trong khi xây dựng các dự án của riêng bạn để hoàn thành công việc của bạn. Sẽ không có bài tập về nhà với cuốn sách này, miễn là các giáo sư hoặc giáo viên của bạn không giao cho bạn bất kỳ điều gì, nhưng tôi rất khuyến khích bạn xây dựng một danh mục các dự án khi bạn đọc, cũng như một dự án Capstone giới thiệu cách bạn có thể Áp dụng những gì bạn đã học được. Dự án Capstone của tôi là cơ sở cho hầu hết những gì bạn sẽ đọc trong cuốn sách này, vì nó kết hợp mã từ các dự án trước đây của tôi, mã tôi đã tạo và học cách viết một cách có phương pháp bằng tay, và một loạt các ý tưởng và mẹo đã giúp tôi thành công đến mức tôi có thể quay một ứng dụng đơn giảnĐầy đủ nổi bật và ngoại hình và hành xử giống như một ứng dụng phổ biến mà bạn có thể thấy bạn bè hoặc gia đình của mình sử dụng, trên internet, được quảng cáo cho bạn hoặc trong tin tức. Cuốn sách này là gì: Cuốn sách này là một hướng dẫn bằng ví dụ. Bạn có thể tìm thấy mã ở đây, hướng dẫn cách học mã, thông tin về việc gỡ lỗi mã và sửa lỗi, khắc phục các bước, hướng dẫn về cách sao lưu và lưu mã của bạn, triển khai lại nếu có ai phá vỡ mã của bạn, bảo mật mã của bạn, triển khai Mã của bạn, xây dựng các trang web tương tác mang tính giải trí, hấp dẫn và gây nghiện, và bạn sẽ hiểu được tôi là ai, tại sao điều này lại quan trọng và làm thế nào để miêu tả bản thân, ứng dụng và hình ảnh của công ty, cũng như phần mềm bạn xây dựng Trong ánh sáng tốt nhất tuyệt đối để trở nên hấp dẫn nhất có thể đối với người dùng cuối của bạn, khách truy cập của trang web của bạn. Trong cuốn sách này, tôi sẽ trình bày một số ví dụ về thiết kế phần mềm tập trung vào web dưới dạng nền tảng cũng như bảo mật. Chúng tôi sẽ bắt đầu trải nghiệm học tập bằng cách xây dựng một cơ bảnOject bằng cách sử dụng shell unix, với các tính năng sao lưu và kịch bản. Sau đó, chúng tôi sẽ kiểm tra một trang web blog cơ bản, nâng cấp blog của chúng tôi với các tính năng ảnh và video cũng như sử dụng các tính năng này để sử dụng các giải pháp bảo mật bằng phần mềm miễn phí và bảo mật máy chủ của chúng tôi bằng mô -đun xác thực có thể cắm (PAM). Sau đó, chúng tôi sẽ xem xét xử lý và xử lý tệp, khám phá chỉnh sửa video, quyên góp giọng nói, quét mã vạch và nhận dạng ký tự quang học, trong số các khái niệm khác. Trên đường đi, chúng tôi sẽ kiểm tra API sẽ giúp chúng tôi làm cho phần mềm của chúng tôi hữu ích và an toàn hơn, với các tùy chọn miễn phí và trả phí. Trên đường đi, chúng tôi sẽ khám phá các công cụ bảo mật và chiến binh vật lý như thiết kế và sản xuất đạn dược và đạn dược bao gồm thiết kế thùng và bộ lặp, tháp pháo và thiết kế máy bay không người lái, và các hiệu trưởng khác, chúng tôi sẽ tích hợp với phần mềm của mình trên mạng hiện có để bảo vệ phần mềm của chúng tôi và thể hiện sự tự vệ và phục hồi. Chúng tôi sẽ nghỉ ngơi trên đường để xây dựng các trò chơi, 2D và 3DĐộng cơ kết thúc và làm việc với phần cứng nhúng trong các ví dụ nghiên cứu trường hợp về phần mềm kết xuất kích thước cơ bản và máy mát xa rung điện tử được đúc trong cao su silicon tương ứng. Trên đường đi, chúng tôi cũng sẽ sử dụng các giải pháp học máy đã có sẵn để bảo mật tốt hơn phần mềm của chúng tôi. Chúng tôi cũng sẽ sử dụng các công cụ chứng khoán có sẵn cho web để hợp lý hóa và bảo mật quy trình. Cuốn sách này là một hướng dẫn cho sự thành công của bạn trong việc xây dựng một ứng dụng web và tích hợp nó với một mạng lưới chuyên nghiệp về máy tính và các hệ thống cơ khí nhúng, và tổng thể hướng dẫn xây dựng phần mềm và phần cứng nhúng mà không có kiến ​​thức nền hoặc kinh nghiệm trước đó. Cuốn sách này không phải là gì: Nếu bạn thực sự muốn có một trang web, bạn chỉ có thể thiết lập một cửa hàng đơn giản và bán những gì bạn cần, đăng blog, đăng ảnh hoặc video, hoặc nếu không mà không cần viết một dòng mã nào. Cuốn sách này không phải là như vậy. Cuốn sách này sẽ dạy bạn cách xây dựng phần mềm hữu ích hơn, đầy đủđặc trưng, ​​chức năng và an toàn so với bất kỳ phần mềm nào bạn có thể tìm thấy, bởi vì nó triển khai phần mềm mới nhất vẫn là nguyên mẫu, có thể tốn kém để chạy ở quy mô các công ty cũ hoạt động và không hấp dẫn các công ty ngược, được thiết lập Kiếm tiền cho những người không thực sự làm bất cứ điều gì. Nếu bạn theo dõi cuốn sách này chặt chẽ, bạn sẽ muốn viết mã, mã nghiên cứu, xây dựng các ứng dụng của riêng bạn và bạn sẽ kiếm tiền từ những gì bạn làm. Tôi sẽ kiếm tiền từ cuốn sách này, ngay cả trong giai đoạn đầu, vì nó chứa thông tin mọi người cần và muốn đọc, và đã mua khi họ mua hoặc sử dụng ứng dụng của tôi. Cuốn sách này sẽ không xây dựng một ứng dụng cho bạn, nhưng nó sẽ chỉ cho bạn đúng hướng và cung cấp cho bạn các công cụ bạn cần và các kỹ năng và mẹo sẽ tạo điều kiện cho thành công của bạn trong việc xây dựng phần mềm cho web, với mọi dòng Mã bạn sẽ cần phải viết làm ví dụ, sẵn sàng để được ghép lại thành phần mềm mà bạn và những người ủng hộ, khách, khách hàng của bạn,Riends, gia đình, khách truy cập, nhà thầu và người dân internet muốn sử dụng và hỗ trợ. Những gì bạn sẽ học: Cuốn sách này sẽ dạy bạn cách xây dựng và bán phần mềm, thực sự chức năng, phần mềm hữu ích, ghi phương tiện, các tính năng bảo mật như nhận dạng khuôn mặt, quét mã vạch vùng có thể đọc được, API Web để xác thực, ghi và hiển thị video và ảnh, và trao đổi thông điệp như Bluetooth và giao tiếp gần trường (NFC). Cuốn sách này sẽ dạy bạn cách sử dụng máy tính nối mạng, tập trung vào Debian Linux, cách xây dựng mã bash để cài đặt và sao lưu phần mềm của bạn một làn gió tự động, liền mạch, cách xây dựng mã Python như một phụ trợ để phục vụ các thông điệp động, phong cách Những thứ sử dụng các kiểu CSS với bootstrap, cho phép đăng nhập và tính tương tác của người dùng thông qua các thiết bị được nối mạng, xây dựng phương tiện tương tác và mạng với các trang web khác để cung cấp các tính năng bảo mật như tin nhắn văn bản để xác minh hoặc các mục đích khác, quét ID, kiểm duyệt hình ảnh và video, dữ liệuRansaction để giữ cho phần mềm của bạn an toàn, xử lý thanh toán, giao dịch tiền điện tử, các nhiệm vụ không đồng bộ, v.v. Bạn sẽ tìm hiểu cách xây dựng các thiết bị Bluetooth của riêng mình, với pin, bộ sạc, bộ vi điều khiển, mạch, động cơ và cảm biến, sử dụng hàn, dây và 3D được in cũng như vật liệu đúc. Tôi sẽ trình diễn các hiệu trưởng thiết kế 3D được áp dụng cho sản xuất và công cụ phụ gia và chế tạo khuôn, vì vậy bạn có thể sản xuất các thiết bị phần cứng nhúng, phần cứng của riêng mình với pin tích hợp, bộ sạc, mạch điện tử và đầu ra chức năng. và kết nối chúng với Bluetooth và web. Cụ thể, chúng tôi sẽ kiểm tra hai nghiên cứu trường hợp, máy mát xa rung động và súng tự chế, cả hai được lập trình trong OpenScad, có sẵn dưới dạng giao diện đồ họa hoặc tiện ích dòng lệnh và có thể được tích hợp vào một web để có kết quả nhanh hơn. Bạn sẽ học cách xây dựng và triển khai một trang web từ đầu không có kinh nghiệm trước đó, làm cho nó hoạt động, an toàn, đẹp, hữu ích và hầu hếtthực tế một cách đáng kinh ngạc. Bạn sẽ học cách sử dụng máy học và tầm nhìn máy tính để làm cho một trang web an toàn và thiết thực hơn, quay video và âm thanh từ trang web của bạn, tặng giọng nói của bạn, tạo nhạc và điều chỉnh âm thanh để tạo các mẫu hữu ích và cách vượt qua tiếng ồn bằng cách Tận dụng các trang web khác để xây dựng mạng lưới trang web tốt nhất có thể mà bạn có thể liên kết trực tiếp với bạn để chia sẻ tất cả các thông tin hữu ích bạn cung cấp và thậm chí quan trọng hơn là đưa mọi người đến phần mềm và doanh nghiệp của bạn. Cuốn sách này sẽ tập trung nhiều nhất vào phương tiện truyền thông, bảo mật và học máy, là ba thành phần chính sẽ giúp bạn xây dựng phần mềm hữu ích cho web bằng cách thu hút người dùng phù hợp và giải phóng những người sai theo cách thực tế, thực tế, thực tế, thực tế, thực tế, Tay và tham gia trong khi cũng tự động, và mạnh mẽ. Cuốn sách này dạy Unix, cụ thể là Debian (Ubuntu), Bash Shell, Python, HTML, CSS, JavaScript và một số gói phần mềm hữu ích chon thích các yêu cầu, cũng như phần mềm bash hữu ích như Git và FFMPEG. Tôi cũng sẽ dạy bạn cách giao dịch tiền điện tử tự động và nhận thanh toán bằng tiền điện tử hoặc từ thẻ ghi nợ thông thường trong khi thậm chí thanh toán cho khách truy cập của bạn một phần doanh thu của bạn nếu bạn chọn làm như vậy. Tôi sẽ dạy bạn cách kiếm tiền từ trang web của bạn thông qua quảng cáo, cách sẵn sàng ứng dụng của bạn cho các công cụ tìm kiếm và làm cho nó nhanh chóng, được xếp hạng trong bảng xếp hạng đầu tiên cho những gì khách hàng của bạn sẽ tìm kiếm để tìm thấy bạn và xếp hạng tìm kiếm càng tốt. Tôi sẽ dạy bạn cách bán phần mềm của bạn, quảng cáo nó, thu hút khách hàng đang tìm kiếm dịch vụ của bạn và tự đặt tên cho mình trên internet thông qua các con đường đã tồn tại, không tốn kém và hoạt động tốt. Tôi sẽ dạy bạn cách lưu dữ liệu của bạn trên các máy tính đám mây hoạt động cho bạn và lưu dữ liệu của bạn với giá rẻ, cách lập kế hoạch và xây dựng một trang web làm những gì người dùng của bạn muốn và những gì bạn muốn và cách giữ cho người dùng của bạn tham giaing trang web của bạn một cách nhấn vào điện thoại của họ với thông báo, email, tin nhắn văn bản, cuộc gọi điện thoại và nhiều con đường hơn để đưa người dùng của bạn trở lại trang web của bạn theo ý của bạn sau khi nhấp vào nút được bảo mật cho bạn. Cuốn sách này sẽ tập trung vào tính thực tế của việc xuất bản và phân phối phương tiện với số lượng lớn, từ văn bản đến ảnh đến video đến âm thanh, tạo ấn tượng tốt cho người dùng cuối (khách hàng của bạn) và bán cho mình theo bất kỳ cách nào bạn làm để tạo Một trang web, một ứng dụng chỉ đại diện cho bạn và bạn, và làm cho bạn, phần mềm của bạn và công ty của bạn trông tốt theo cách tốt nhất có thể. Bạn cũng sẽ học được một vài mẹo và thủ thuật từ tôi, từ các mẹo mã hóa, sự phù phiếm thực tế như trang điểm và nhiếp ảnh, người mẫu và diễn xuất, và nhiều hơn nữa, điều này sẽ rất quan trọng để miêu tả bản thân và công ty của bạn trong ánh sáng tốt nhất có thể sử dụng tất cả các công cụ có sẵn có sẵn có sẵn có sẵn cho bạn trong khi phân phối nhiều nội dung như bạn cần trên một sự cân bằng lành mạnh của các nền tảng để mangE Để kết quả không có nhiều nỗ lực, công việc hoặc tiền bạc hơn là cần thiết. Cuốn sách này được gọi là Web thực tế dựa trên học tập và bảo mật bằng ví dụ về ví dụ: vì một lý do: nó liên quan đến việc học tập mã, cụ thể cho web, đặc biệt tập trung vào bảo mật, từ quan điểm thực tế, với các ví dụ về mã làm việc phục vụ Các mục đích thực tế được nêu trong văn bản. Thành phần học tập của văn bản này cũng bao gồm việc học máy, mã tôi sẽ chỉ cho bạn cách chạy cho web sẽ xử lý tầm nhìn máy tính, nhận dạng khuôn mặt, kiểm duyệt hình ảnh và video, tăng cường hình ảnh, nâng cao độ phân giải, chú thích hình ảnh và các tác vụ khác như Các số liệu dự đoán có nguồn gốc từ các hình ảnh, chẳng hạn như bản chất của hình ảnh như một hình ảnh xác thực, chuyển đổi máy tính hoặc một bản sao quang học (một bức ảnh của hình ảnh hoặc ảnh in). Học máy là rất quan trọng khi nói đến bảo mật và bảo mật phần mềm web, bởi vì nó có thể tạo thành các tác vụ không thể. Máy tính của bạnĐăng nhập cho bạn bằng mật mã, nhưng có thể an toàn hơn khi sử dụng nó nếu nó đăng nhập bạn bằng khuôn mặt của bạn. Bạn có thể tạo một máy tính máy chủ này an toàn, một máy tính thường hỏi bạn tên người dùng và mật mã và đăng nhập cho bạn, có thể với mã thông báo xác nhận cho mỗi đăng nhập mới hoặc địa chỉ IP mới, nhưng nếu bạn đang xây dựng quy mô lớn, dễ dàng Sử dụng, về cơ bản an toàn và phần mềm mạnh mẽ, điều này có thể là đủ. Việc buộc phần mềm của bạn quá chặt chẽ với phần mềm của người khác, như dịch vụ email hoặc dịch vụ tin nhắn văn bản, không đủ để làm cho phần mềm của bạn an toàn hoặc bất kỳ ai (bất kỳ trang web nào bạn sử dụng). Bất cứ ai xây dựng phần mềm an toàn hoàn hảo đều có ý nghĩa về những gì điều này ngụ ý. Phần mềm vốn dĩ không an toàn vì các thiết bị và tài khoản chúng tôi sử dụng để truy cập nó không phải lúc nào cũng được chúng tôi xử lý, chúng có thể nằm trong tay của bất kỳ ai có ý định xấu cho phần mềm và do đó có thể gây rủi ro cho chính phần mềm. Đây là một cái gì đó tập trung của cuốn sách này. Một máy tính được nối mạng theo mặc địnhĐược bảo mật bằng một mã thông báo khóa dài, được gọi và phím SSH hoặc Secure Shell và được bảo mật tốt nhất với máy chủ web, bởi vì máy chủ web cung cấp truy cập mở cũng như trạng thái của các công cụ bảo mật nghệ thuật đang chạy trên máy chủ. Máy chủ web có quyền truy cập vào trình duyệt web của người dùng, đây là phần mạnh nhất của thiết bị người dùng, bởi vì đó là nơi người dùng có thể truy cập phần mềm được nối mạng. Bộ công cụ này có thể hiển thị văn bản, các trang web bạn nhìn thấy và cũng có thể ghi lại hình ảnh, âm thanh và video (như ảnh của khuôn mặt hoặc ID trạng thái), có thể đọc và ghi vào các thiết bị radio Bluetooth và có thể đọc và ghi vào trường gần trường Thẻ transponder, thẻ khóa rẻ tiền, fobs, nhãn dán, nhẫn và thậm chí cấy ghép chip với các số sê -ri duy nhất có thể được đọc và ghi với dữ liệu được tạo và xác thực bởi máy chủ web gắn liền với trang web. Sử dụng tất cả các công cụ theo ý của bạn, với cuốn sách này, bạn sẽ trang bị cho mình kiến ​​thức để xây dựng một trang web an toàn và tổng thểHệ thống máy tính mạng URE hoạt động cho bạn, đấu thầu của bạn, và trông và cảm thấy đúng. Bắt đầu từ đâu: Bạn được chào đón để bỏ qua phần tôi bắt đầu cuốn sách này hoặc bất kỳ phần nào, theo mã chính xác bạn cần, đặc biệt nếu bạn có kinh nghiệm về mã hóa trước hoặc bất kỳ công cụ nào đã nói ở trên mà tôi sẽ mô tả chi tiết trong cuốn sách này cũng như ghi lại các trường hợp sử dụng và các ví dụ thực tế của chúng. Nếu bạn không có kinh nghiệm viết mã, tôi khuyên bạn nên đọc tất cả cuốn sách này và đặc biệt khuyên bạn nên đọc các phần trước, để đảm bảo cuốn sách này phù hợp với bạn. Nếu cuốn sách này không phù hợp với bạn, hãy xem xét việc tặng nó cho một người bạn hoặc người thân, những người có thể quan tâm đến việc tìm hiểu về phát triển web, và thậm chí xem xét mượn nó và học hỏi từ họ để lấp đầy những khoảng trống mà tôi đã thất bại giáo viên, hoặc các giáo viên khác đã làm trước tôi. Bắt đầu nơi bạn sẽ làm, mọi phần của cuốn sách này sẽ hữu ích nếu bạn có ý định xây dựng mộtPP và xem xét rằng các ứng dụng tốt nhất được xây dựng với người dùng cuối: biết khách hàng của bạn. Bây giờ bạn biết tôi, bạn biết cuốn sách này, và bạn đã sẵn sàng để bắt đầu. Để bắt đầu, hãy lấy một máy tính (ngay cả máy tính xách tay rẻ nhất từ ​​cửa hàng hộp, Amazon hoặc máy tính để bàn cũ hoạt động và thiết lập nó theo cách phù hợp với bạn. Cách đọc cuốn sách này: Văn bản được tô sáng, biểu thị rằng văn bản thuộc về một dấu nhắc lệnh, nơi bạn sẽ viết mã bạn chạy. Lời nhắc lệnh là tập trung nhiều bàn phím và yêu cầu ít hoặc không nhấp chuột, tăng tốc độ công việc của bạn và làm cho mọi thứ dễ dàng hơn với bạn. Bắt đầu: Hãy đi vào. Chúng tôi sẽ bắt đầu bằng cách xây dựng mã trên máy cục bộ và bắt đầu mà không xây dựng một trang web được kết nối với Internet. Điều này là an toàn hơn để bắt đầu, không tốn kém gì và dễ dàng cho bạn. Tùy thuộc vào hệ điều hành của bạn, việc vào vỏ bash sẽ khác một chút. Đối với Mac OS, tôi khuyên bạn nên cài đặt một máy ảo vào thời điểm này, vì bạn sẽ nhận được khả năng tương thích nhất vớimáy ảo. Các nhà cung cấp khác nhau như VirtualBox và Paralells có thể chạy máy ảo cho bạn, mặc dù cũng có thể cài đặt Ubuntu trực tiếp trên máy, nếu bạn muốn sử dụng môi trường gốc được khuyến nghị để tạo trải nghiệm nhanh chóng, hợp lý. Nếu bạn đang sử dụng Linux hoặc Windows, mà tôi đề xuất, sẽ khá dễ dàng để tạo một dự án. Mở thiết bị đầu cuối của bạn, điều chỉnh kích thước khi bạn thấy phù hợp và bắt đầu theo bước 2. Nếu bạn đang sử dụng Windows, vui lòng làm theo bước 1. Bước 1: - Chỉ người dùng Windows Trong Windows, Mở Lệnh nhắc nhở với tư cách là Quản trị viên và Loại WSLTHERInstall Bước 2: - Tiếp tục ở đây hoặc bỏ qua Bước 1 đến đây nếu bạn không sử dụng Windows Trong một thiết bị đầu cuối mở, (tùy thuộc vào hệ điều hành của bạn, được gọi là Ubuntu trong Windows, thiết bị đầu cuối trong Mac hoặc Linux hoặc một tên tương tự), bắt đầu bằng cách tạo một dự án. Chúng tôi làm điều này với lệnh mkdir, tạo ra một thư mục. Nếu bạn cần tạo một thư mục để lưu trữ dự án của mình, được khuyến nghị, hãy sử dụnglệnh CD để thay đổi thư mục và và CD/path/to/thư mục - Đường dẫn là các thư mục (tệp) đi trước thư mục đích của bạn, đường dẫn mặc định của bạn là ~ hoặc/home/tên người dùng (trong đó tên người dùng là tên người dùng của bạn). Để thay đổi sang thư mục mặc định, gõ CD hoặc CD ~ Ví dụ về MKDIR - Thay thế ví dụ “Ví dụ” bằng tên của thư mục Bây giờ bạn có một thư mục làm việc cho dự án của bạn. Vì nó rất quan trọng để lưu thư mục này được lưu trong trường hợp bạn cần chuyển sang một máy khác hoặc triển khai mã bạn viết để nó sẵn sàng cho web, chúng tôi sẽ xây dựng một tập lệnh để sao lưu thư mục của bạn trong vài bước tiếp theo. Nhưng việc xây dựng một tập lệnh cần một chút mã và mã cần được tự động hóa để hữu ích nhất có thể. Vì vậy, hãy xây dựng một tập lệnh để xây dựng các tập lệnh trước. Hãy bắt đầu bằng cách tạo tập lệnh và làm cho nó thực thi. Chúng tôi sẽ sử dụng sudo, chmod và chạm cho điều này và gọi cho tập lệnh


sudo touch /usr/bin/ascript
sudo chmod a+x /usr/bin/ascript
sudo nano /usr/bin/ascript
Bây giờ chúng tôi đã tạo ra tập lệnh, làm cho nó thực thi và sẵn sàng chỉnh sửa nó. Nano là một trình soạn thảo văn bản sẽ cho phép bạn chỉnh sửa văn bản mà không cần nhấp, dễ dàng hơn nhiều so với việc sử dụng giao diện người dùng đồ họa. Để chỉnh sửa một tệp có nano, sử dụng nano và sau đó là đường dẫn đến tệp. Để tạo một kịch bản tạo ra một kịch bản, nó khá giống với việc tạo kịch bản của chúng tôi ngay từ đầu. Chúng tôi sẽ sử dụng cùng một mã như trên, thay thế tên của tập lệnh, as ascript bằng một tham số đối số, $ 1. Điều này cho phép chúng tôi gọi tập lệnh bằng cách gõ đơn giản là Sudo Ascript News, tại thời điểm đó chúng tôi có thể tạo bất kỳ tập lệnh mới nào bằng cách thay thế bản tin của Hồi giáo bằng tên của tập lệnh của bạn. Mã trong nano sẽ trông giống như:

sudo touch /usr/bin/$1
sudo chmod a+x /usr/bin/$1
sudo nano /usr/bin/$1
Và để đóng Nano, chúng ta có thể giữ khóa điều khiển và nhấn X, sau đó y để biểu thị chúng ta đang lưu tệp và nhấn trả lại. Bây giờ thay vì gõ ba lệnh này để chỉnh sửa tập lệnh, chúng tôi sẽ có thể nhập sudo ascript để chỉnh sửa tập lệnh một lần nữa. Điều này hoạt động! Và bất kỳ tập lệnh mới nào cũng có thể được chạy dễ dàng bằng cách gọi nó trong shell. Hãy lưu công việc của chúng tôi ngay bây giờ: Hãy viết một tập lệnh sao lưu để lưu tập lệnh mới của chúng tôi và sau đó sao lưu nó trong thư mục dự án của chúng tôi, đồng thời sao lưu tập lệnh sao lưu.

sudo ascript backup
Bây giờ, trong Nano:

sudo cp /usr/bin/backup /path/to/directory/
sudo cp /usr/bin/ascript /path/to/directory/
Trong đó/đường dẫn/đến/thư mục là đường dẫn đến dự án bạn đã tạo với MKDIR. Sau này, chúng tôi sẽ học cách sao chép các đường dẫn lặp lại như thế này với một vòng lặp và một danh sách, ít hơn mã, nhưng bây giờ chúng ta hãy giữ cho nó đơn giản và có một vài dòng. Để chạy tập lệnh này và sao lưu mã của bạn, hãy lưu tệp trong nano với điều khiển+x, y và trả về và nhập bên dưới vào shell của bạn

backup
Nếu bạn được nhắc về mật khẩu trong khi đọc cuốn sách này và theo dõi chính xác, vui lòng nhập mật khẩu người dùng của bạn, bạn sẽ có ba lần thử trước khi bạn cần chạy lại lệnh. Bạn có thể sử dụng các mũi tên lên và xuống để chạy lại các lệnh và chỉnh sửa chúng, nếu bạn cần phải chạy bất cứ thứ gì hai lần. Nhấn đơn giản lên và xuống không liên tục để chọn một lệnh, trước khi chỉnh sửa lệnh bằng bên phải, mũi tên trái và xóa khóa cũng như bàn phím và chạy nó với return. Chúc mừng! Bạn đã quản lý để tạo ra một tập lệnh sao lưu tuyệt vời sao lưu hai tập lệnh shell quan trọng trong thư mục làm việc của bạn. Chúng tôi có thể di chuyển mọi thứ sau này khi dự án trở nên lớn hơn, nhưng điều này hoạt động ngay bây giờ. Chúng ta hãy chuyển sang sao lưu trên đám mây, chúng ta sẽ sử dụng GitHub cho việc này (mặc dù có rất nhiều giải pháp GIT khác để sao lưu, tất cả đều giống nhau.) Git là một phần mềm kiểm soát xác thực cho phép bạn sao lưu chỉnh sửa cho phần mềm khi bạn làm chúng đến một máy chủ, trong khiCũng cho phép bạn tải xuống toàn bộ bản sao của phần mềm đằng sau mật khẩu hoặc khóa. Đó là công cụ để lưu phần mềm của bạn, đặc biệt là khi chúng tôi di chuyển sang các trường hợp Linux được bảo mật, đôi khi bị hỏng khi một dòng mã không thành công, khiến bạn bị khóa trong khi mã của bạn có thể không được sao lưu nếu bạn không có cơ hội sao lưu nó Tự động lên, mà chúng tôi sẽ bao gồm. Nếu bạn chưa sử dụng máy ảo Ubuntu vào thời điểm này, tôi sẽ sử dụng máy ảo Ubuntu vào thời điểm này vì nó sẽ giúp cuộc sống của bạn dễ dàng hơn khi cài đặt tất cả các gói cần thiết để xây dựng một trang web hoạt động và học sâu trước hoạt động trên máy tính của bạn. Chúng tôi sẽ chuyển mã đến một máy chủ web trong tương lai gần, nhưng chúng tôi muốn đảm bảo có ít nhất một vài lớp bảo mật đằng sau máy chủ web của chúng tôi có khả năng chống lừa đảo và sử dụng một số gói Linux để thực hiện cái này. Nếu bạn vẫn muốn sử dụng Mac OS, bạn có thể tìm kiếm và cài đặtE Các gói cần thiết trực tuyến, nhưng có thể không có lựa chọn thay thế cho mỗi gói sách hoặc loạt này sẽ bao gồm. Hãy thêm một vài lệnh để cam kết công việc của chúng tôi với tập lệnh sao lưu bằng cách chạy lệnh sudo ascript

# …
git add –all
git commit -m “backup”
git push -u origin master
Một lần nữa, kiểm soát x để lưu. Bây giờ chúng ta cần thực hiện cấu hình một lần cho dự án này. Bởi vì nó sẽ sớm là một dự án Git, chúng tôi không cần gõ mọi lệnh mỗi khi chúng tôi triển khai từ kho lưu trữ Git, nhưng chúng tôi sẽ hiểu được điều này khi chúng tôi viết các tập lệnh triển khai. Để bắt đầu, hãy đảm bảo rằng chúng tôi đang ở trong thư mục phù hợp và khởi tạo kho lưu trữ Git và tạo các khóa SSH.

cd /path/to/directory
git init
git branch -m master
ssh-keygen
Sau khi chúng tôi nhập SSH-Keygen, khóa mới sẽ được lưu trong thư mục gia đình theo thư mục có tên .SSH. Nó được gọi là id_rsa.pub. Hãy tìm khóa này và sao chép nó. Để xem nó,

cd ~
cat .ssh/id_rsa.pub
Sao chép văn bản được trả về bởi lệnh cuối cùng và tạo tài khoản với nhà cung cấp Git của bạn (lý tưởng là GitHub), trước khi thêm khóa SSH vào tài khoản của bạn. Khi bạn có một tài khoản, nhấp vào menu trên bên phải và nhập cài đặt, trước khi thêm khóa SSH của bạn vào các phím SSH và GPG dưới quyền truy cập trong menu. Chọn Thêm phím SSH và thêm của bạn bằng cách dán nó vào và cho nó một tiêu đề, trước khi lưu và quay lại GitHub để tạo một kho lưu trữ mới. Điều này tương tự đối với các nhà cung cấp Git khác, bạn sẽ cần đọc tài liệu của họ. Trong cấu hình kho lưu trữ mới, hãy đặt cho kho lưu trữ của bạn một tên mô tả và quyết định xem bạn có muốn xuất bản nó hay không và đảm bảo cấu hình chưa có tệp nào để đưa vào. Khi kho lưu trữ được tạo, hãy sao chép bản sao với URL SSH và dán nó vào lệnh sau.

git remote add git://… (your remote URL)
Bây giờ bạn có thể quay trở lại kho lưu trữ của mình với CD, bạn sẽ quen với việc này. Hãy thử tập lệnh sao lưu của bạn ngay bây giờ với bản sao lưu Tuyệt vời! Bây giờ chúng ta thực sự có thể nhận được mã hóa. Bây giờ chúng ta hãy cài đặt Django để chúng ta nắm bắt tốt Bash và Git. Django sẽ cho phép chúng tôi tự động sao lưu phần mềm của mình, Bash cũng có thể làm điều này nhưng Django nên có một triển khai an toàn hơn đơn giản hơn (nó có thể bị vô hiệu hóa và cấu hình dễ dàng hơn). Để cài đặt phần mềm trong Ubuntu, chúng tôi sẽ sử dụng lệnh sudo apt-get. Đầu tiên, hãy cập nhật và nâng cấp phần mềm chúng tôi đã có. Điều này có thể được thực hiện với bản cập nhật sudo apt-get và nâng cấp sudo apt-get -y. Tiếp theo, hãy cài đặt Python và môi trường ảo của chúng tôi, nhà của mã của chúng tôi, với lệnh sau: sudo apt-get install python-is-python3 python3-venvv Đây là tất cả những gì bạn cần để đi với Django về cài đặt phần mềm trong trường hợp Ubuntu. Đối với Windows và Linux, điều này khá đơn giản, nhưng đối với Mac, bạn có thể muốn cài đặt một máy ảo vàLinux trên đó bằng cách sử dụng môi trường ảo miễn phí hoặc được trả tiền như VirtualBox hoặc Paralells Desktop và tạo lại các bước trên để thiết lập môi trường Ubuntu. Ubuntu rất quan trọng trong trường hợp này vì đây là phần mềm mà các trang web chạy và nó cho phép họ lưu trữ các trang web với tất cả các phần mềm đã nói ở trên. Hãy đào sâu vào Django. Trong thư mục của chúng tôi một lần nữa, với

python -m venv venv # Tạo môi trường ảo nơi mã được lưu trữ
source venv/bin/activate # Kích hoạt môi trường ảo
pip install Django
django-admin startproject mysite . # MySite là dự án tôi đang bắt đầu trong thư mục hiện tại của mình.
Django chỉ bắt đầu chúng tôi, bởi vì Django đang lưu trữ máy chủ web và đang làm mọi thứ chúng tôi cần để có được một trang web cơ bản địa phương và chạy. Bây giờ chúng tôi đã cài đặt Django, hãy chỉnh sửa cài đặt một chút để làm cho nó hoạt động theo cách chúng tôi cần. Đầu tiên, hãy tạo một ứng dụng mới

python manage.py startapp feed
Bạn sẽ nhận thấy ứng dụng đầu tiên được gọi là nguồn cấp dữ liệu. Ứng dụng nên được gọi là bất cứ điều gì bạn thích và chúng tôi sẽ tạo các ứng dụng mới, nhưng tên của mỗi ứng dụng phải nhất quán mỗi khi ứng dụng được tham chiếu trong mã. Để thêm một ứng dụng mới, chúng tôi sẽ luôn chỉnh sửa cài đặt trong thư mục khác mà ứng dụng đã tạo, được đặt tên trong Ứng dụng StartProject, sau đây. Sử dụng nano,

nano app/settings.py
Trong cài đặt, tìm installed_apps và tách [] thành 3 dòng. Sử dụng bốn khoảng trống trên đường trung tâm trống, thêm 'nguồn cấp dữ liệu' hoặc tên của ứng dụng của bạn. Phần này của Cài đặt.py sẽ trông giống như:

INSTALLED_APPS = [
    'feed',
]
Trước khi chúng ta quên, hãy kiểm tra rằng Django đang làm việc. Sử dụng lệnh Python Management.py RunServer 0.0.0.0:8000, chúng ta có thể chạy máy chủ và sau đó điều hướng trong trình duyệt web trên máy tính chạy mã đến http: // localhost: 8000 và xem trang web ví dụ (nó hoạt động!) Thoát khỏi máy chủ với điều khiển C, giống như bất kỳ lệnh nào khác. Bây giờ, chúng ta hãy tìm hiểu một số mã Python. Django có ba thành phần chính, tất cả đều được chạy bằng mã hoàn toàn. Các thành phần được gọi là mô hình, chế độ xem và mẫu và mỗi thành phần ở mức cao hơn và thấp hơn tương ứng trước khi trang web được gửi cho người dùng. Mô hình là mã lưu trữ thông tin trong cơ sở dữ liệu để truy xuất, sắp xếp và kết xuất. Chế độ xem quyết định làm thế nào mô hình được hiển thị, thao tác và sửa đổi, hầu hết mọi chế độ xem sẽ sử dụng trực tiếp một mô hình. Mẫu là mã HTML với một số chuông và còi được gọi là ngôn ngữ mẫu. Mẫu được hiển thị bởi chế độ xem nó chứa đầy mã python vàBối cảnh như mô hình và thông tin (chuỗi Usuall và số nguyên) từ chế độ xem. Django cũng có các thành phần khác, bao gồm nhưng không giới hạn ở: Cài đặt, cấu hình ứng dụng như chúng ta đã thảo luận. URL, là các mẫu mà người dùng tuân theo để có quyền truy cập vào các phần cụ thể của ứng dụng web. Các biểu mẫu, xác định cách thông tin được gửi đến máy chủ được xử lý và hiển thị cho cơ sở dữ liệu cũng như cho người dùng. Đây là nền tảng của việc xử lý thông tin ở phía máy chủ và có thể chấp nhận bất kỳ loại thông tin nào mà máy tính lưu trữ, đáng chú ý nhất là chuỗi văn bản, số và booleans đúng/sai (thường là hộp kiểm). Các mẫu, là mã HTML và ngôn ngữ mẫu và thu hẹp khoảng cách giữa Python và HTML, có nghĩa là thông tin Python có thể được phục vụ dưới dạng mã HTML mà bất kỳ ai cũng có thể truy cập và có thể bảo mật một trang web có quyền truy cập hạn chế, trong khi làm cho mã Python có thể truy cập được vào web và hữu ích cho nhiều mục đích khác nhau trên một thiết bị từ xa khôngeed ở gần máy chủ. Các tệp tĩnh, thường là JavaScript và các thư viện mà máy chủ phục vụ và được liên kết với mẫu. Các tệp phương tiện, mà máy chủ phục vụ hoặc được lưu trữ bên ngoài hoặc chỉ được ghi vào máy chủ trước khi được xử lý và đăng lên một máy chủ khác (một thùng) để lưu trữ. Middleware, đó là các đoạn mã được chạy cùng lúc với mọi chế độ xem và được coi là bao gồm trên các chế độ xem. Bộ xử lý bối cảnh, xử lý bối cảnh của từng chế độ xem và được sử dụng để thêm bối cảnh. Các thử nghiệm, xác nhận rằng người dùng hoặc yêu cầu vượt qua các yêu cầu nhất định trước khi xem được hiển thị. Người tiêu dùng, chỉ ra cách WebSockets xử lý và phản ứng với giao tiếp. Quản trị viên, được sử dụng để đăng ký các mô hình để chúng có thể được thao tác chi tiết trong trang quản trị Django, trong đó cơ sở dữ liệu có thể được quản lý thông qua giao diện đồ họa. Cần tây, xác định các nhiệm vụ không đồng bộ các phần của mã Django có thể bắt đầunning trước khi ngay lập tức tiến hành nhiệm vụ hoặc dòng mã tiếp theo. Django có thể có nhiều thành phần khác, mà chúng ta sẽ thảo luận chi tiết ở đây. Có rất nhiều cách để làm cho Django trở nên chức năng hơn, thêm websockets, là các kênh liên lạc nhanh, hợp lý Mã được thực thi. Xem các chức năng là chìa khóa vì chúng thường khai báo mọi đoạn mã dành riêng cho mẫu URL cụ thể hoặc một phần của máy chủ. Đầu tiên, hãy khám phá các chức năng xem. Xem các chức năng bắt đầu bằng việc nhập biểu thị mã sẽ được sử dụng trong chế độ xem và được xác định bằng cách sử dụng các định nghĩa hoặc lớp chức năng chính quy. Các chế độ xem đơn giản nhất được xác định bởi Def định nghĩa chức năng và trả về HTTPresponse với một mẫu cơ bản. Hãy bắt đầu bằng cách xác định chế độ xem cơ bản để trả về văn bản Hello Hello World. Hãy nhớ rằng mỗi lần bạn thêmMột câu lệnh như def, nếu, trong khi, vì, v.v., bạn sẽ cần thêm 4 khoảng trống cho mỗi định nghĩa trước bạn muốn áp dụng cho chức năng của mình. Chúng tôi sẽ sớm nhận được những gì trong số những phương tiện này. Từ thư mục của trang web của chúng tôi, chỉnh sửa tệp Feed/Views.py bằng Nano và thêm các dòng sau vào cuối

from django.http import HttpResponse

def hello(request):
    return HttpResponse('hello world')
HTTPresponse của Django trả lời bằng một chuỗi văn bản, được biểu thị bằng phần mở và đóng '. Mỗi khi bạn chuyển thông tin đến một chức năng hoặc lớp, như yêu cầu hoặc chuỗi, bạn sẽ cần sử dụng dấu ngoặc đơn (, mở và đóng). Đây không phải là tất cả những gì chúng ta cần để xem quan điểm của chúng ta. Tất nhiên, chúng tôi chưa nói với máy chủ nơi chế độ xem chính xác, chúng tôi vẫn cần xác định một đường dẫn mà chế độ xem sẽ hiển thị. Hãy bắt đầu bằng cách xác định một đường dẫn cơ bản trong ứng dụng/urls.py và chúng tôi sẽ vào các nhóm đường dẫn sau. Trong ứng dụng/urls.py, thêm một dòng sau các câu lệnh nhập sau khi bắt đầu nhập quan điểm mà chúng tôi vừa tạo.

from feed import views as feed_views
Bây giờ, hãy xác định mẫu chế độ xem. Các mẫu xem có ba thành phần, thành phần đường dẫn, cho máy chủ cho thấy chế độ xem tồn tại trong máy chủ (đường dẫn URL mà người dùng nhập vào thanh điều hướng để nhập trang web), thành phần xem có quan điểm và Tên thân thiện cho chế độ xem để dễ dàng truy xuất mẫu của nó khi làm việc với một mẫu, đặc biệt là tên của nó có thể được thay đổi và cập nhật nếu cần thiết để tạo không gian cho một chế độ xem khác hoặc lấy tên hợp lý hơn. Thật hợp lý khi làm mọi thứ theo cách này và linh hoạt, bởi vì cơ sở mã của bạn sẽ là một môi trường luôn thay đổi cần sự linh hoạt và ngẫu hứng để có giá trị và dễ làm việc. Dưới đây là quan điểm của bạn sẽ trông như thế nào, bạn có thể thêm điều này vào URLPOTTERNS = [phần Ứng dụng/URLS.Py. Mẫu chế độ xem được xác định với ba thành phần được mô tả ở trên và một hàm gọi là đường dẫn. Các mẫu URL của bạn là một danh sách, vì vậy hãy đảm bảo luôn kết thúc từng mục trong chúngvới một dấu phẩy, bởi vì điều này tách biệt từng người. Mỗi mục cũng sẽ đi trên một dòng mới, một lần nữa với bốn khoảng trống trước đó, giống như ứng dụng trong Cài đặt.py. Chúng tôi sẽ xác định thành phần đầu tiên của chế độ xem với hàm chuỗi trống, để tạo chế độ xem chạy trên thư mục gốc của máy chủ web. Urls.py của bạn bây giờ trông giống như

from feed import views as feed_views

urlpatterns = [
    path('', feed_views.hello, name='hello'),
]
Đây là cơ sở để tạo một trang web với Django hoàn toàn tĩnh. Để tạo một trang web năng động hơn, nơi chúng tôi có thể bắt đầu bộ nhớ đệm thông tin, như hình ảnh, video, âm thanh và nhiều hơn nữa, chúng tôi sẽ cần sử dụng các mô hình, mà chúng tôi sẽ khám phá tiếp theo. Hiện tại, hãy kiểm tra mã của chúng tôi và chạy máy chủ. Để kiểm tra mã cho lỗi, hãy chạy:

python manage.py check
Nếu có bất kỳ thông báo lỗi nào, bạn nên xem xét cẩn thận những thay đổi bạn đã thực hiện đối với ứng dụng của mình và xem liệu có bất cứ điều gì cần được sửa chữa không, như không có không gian không liên quan, đã xóa ký tự, hoặc bất cứ điều gì khác. Đọc qua thông báo lỗi (nếu bạn có một) . Nếu bạn đã khắc phục sự cố, hãy chạy lại lệnh trên. Khi phần mềm của bạn đã sẵn sàng để chạy và đang hoạt động, bạn sẽ thấy đầu ra kiểm tra hệ thống được xác định không có vấn đề gì. Bây giờ bạn đã sẵn sàng để đi. Chạy máy chủ với:

python manage.py runserver 0.0.0.0:8000
Bây giờ hãy mở một trình duyệt web và điều hướng đến http: // localhost: 8000. Bạn sẽ thấy văn bản được trả về trong dấu ngoặc đơn và trích dẫn của hàm httpresponse trong quan điểm của bạn. Đây chỉ là một ví dụ cơ bản, nhưng nếu bạn làm cho nó đến nay, bạn hiểu những điều cơ bản về cách thức hoạt động của Linux, Bash, Python và Django. Hãy tìm hiểu sâu hơn vào một số mô hình cơ sở dữ liệu và khám phá sức mạnh của một lớp Python trong việc lưu trữ thông tin. Sau đó, chúng tôi sẽ bắt đầu nắm bắt HTML và CSS trước khi chúng tôi làm cho trang web của chúng tôi nổi bật, linh hoạt và an toàn bằng cách sử dụng JavaScript và máy học. Các lớp được lưu trữ trong các mô hình.py của ứng dụng của bạn. Sử dụng Nano, Chỉnh sửa ứng dụng/model.py và thêm một lớp mới. Một lớp được xác định với định nghĩa lớp và được thông qua một siêu lớp mà nó kế thừa, trong trường hợp này là model.model. Tên của lớp được đưa ra theo định nghĩa lớp và sau khi định nghĩa lớp A: (Đại tràng) được sử dụng, trước khi các thuộc tính và định nghĩa chức năng gắn với lớp được ký hiệu bên dưới. Lớp học của chúng tôiCần một ID chúng ta có thể sử dụng để lấy nó và giữ cho nó độc đáo, và nó cũng cần một trường văn bản để lưu trữ một số thông tin. Sau này, chúng tôi có thể thêm dấu thời gian, tệp, booleans (định nghĩa đúng hoặc sai có thể giúp mã của chúng tôi đưa ra quyết định về những việc cần làm với mô hình và có thể được sử dụng để sắp xếp nó), một thể hiện để buộc mô hình với người dùng đã đăng nhập vào máy chủ, và nhiều hơn nữa. Hãy giải nén mã

from django.db import models # Nhập được sử dụng để xác định lớp của chúng tôi và các thuộc tính của nó

class Post(models.Model): # Định nghĩa của bản thân lớp chúng ta
    id = models.AutoField(primary_key=True) # ID của mô hình của chúng tôi, một khóa được tạo tự động sẽ cho phép chúng tôi truy vấn mô hình, giữ cho nó độc đáo và rất hữu ích khi chúng tôi cần tương tác với mô hình một khi nó đã được tạo.
    text = models.TextField(default='') # Thuộc tính các cửa hàng lớp của chúng tôi, trong trường hợp này, một số văn bản, mặc định vào một chuỗi trống.
Đóng và lưu tệp như chúng tôi đã làm trước đây để hoàn thành. Có nhiều trường và tùy chọn khác mà chúng tôi sẽ khám phá khi chúng tôi cập nhật lớp này khi ứng dụng của chúng tôi phát triển, nhưng đây là nhu cầu cơ bản của việc tạo một ứng dụng để đăng một số văn bản. Tuy nhiên, mô hình này sẽ không hoạt động một mình. Như đã mô tả trước đây, chúng tôi sẽ cần một chế độ xem tùy chỉnh và mẫu URL tùy chỉnh để làm cho mô hình này hoạt động và chúng tôi cũng sẽ cần một biểu mẫu cùng với một mẫu. Hãy khám phá hình thức đầu tiên. Để xác định một biểu mẫu, chỉnh sửa ứng dụng/forms.py với nano và thêm các dòng sau. Chúng tôi sẽ cần hai lần nhập, lớp biểu mẫu của chúng tôi, cũng như mô hình chúng tôi đã tạo (feed.models.post), một định nghĩa lớp tương tự như mô hình và một trường cùng với một lớp con có tên meta sẽ xác định mô hình mà biểu mẫu tương tác với. Biểu mẫu cũng có thể có chức năng khởi tạo đặt nó dựa trên thông tin trong yêu cầu, mô hình hoặc cách khác, chúng tôi sẽ khám phá điều này sau. Các hình thức mô hình rất hữu ích vì chúng có thể tạo một mô hình hoặc cũng chỉnh sửa mô hình,Vì vậy, chúng tôi sẽ sử dụng chúng cho cả hai. Hãy xác định một trong các dạng.

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',)
Đây là những điều cơ bản của một hình thức và mô hình trông như thế nào. Mẫu mô hình này có thể được sử dụng để khởi tạo hoặc chỉnh sửa một bài đăng, thay đổi văn bản mà nó chứa. Chúng tôi sẽ xem xét tích hợp biểu mẫu này vào chế độ xem tiếp theo. Trước tiên, hãy thực hiện các di chuyển và di chuyển cơ sở dữ liệu để mã của chúng tôi có thể tương tác với mô hình khi nó chạy. Để làm điều này, hãy chạy các lệnh sau:

python manage.py makemigrations
python manage.py migrate
Điều này sẽ mất một phút để thực hiện, nhưng một khi nó có, nó sẽ cho phép bạn truy cập mô hình trong chế độ xem, phần mềm trung gian hoặc bất kỳ nơi nào khác trong phần mềm. Hãy tiếp tục bằng cách xem xét nơi chúng ta có thể thấy mô hình của mình. Chỉnh sửa nguồn cấp/views.py và thêm mã sau, như đã lưu ý. Bạn sẽ không cần thêm bất cứ điều gì sau dấu #, mã đó là nhận xét được sử dụng để biểu thị thông tin về mã. Chúng tôi sẽ bắt đầu bằng cách nhập mô hình của chúng tôi trong các chế độ xem và thêm nó vào một bối cảnh mà chúng tôi có thể hiển thị nó trong một mẫu dưới dạng danh sách để hiển thị. Tiếp theo, chúng tôi sẽ thêm một mẫu nơi chúng tôi có thể hiển thị biểu mẫu và mô hình bằng một nút để tạo một đối tượng mới dựa trên mô hình và đăng nó lên máy chủ. Điều này nghe có vẻ phức tạp, vì vậy chúng ta hãy thực hiện từng bước một. Trước khi chúng tôi hoàn thành chế độ xem, hãy tạo một mẫu chỉ hiển thị mô hình và đảm bảo chúng tôi có thể nhìn thấy nó bằng cách tạo một bài đăng mới trong shell. Đây là cách mà quan điểm đó nên trông:

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

def feed(request):
    posts = Post.objects.all() # Truy vấn tất cả các bài đăng trong cơ sở dữ liệu cho đến nay
    return render(request, 'feed/feed.html', {
        'posts': posts,
    })
Tất cả điều này trông khá đơn giản cho đến khi chúng ta xuống đáy. Kết xuất, giá trị được trả về bởi hàm thay vì trong phản hồi HTTP như ví dụ trước, luôn luôn nhận yêu cầu làm đầu vào đầu tiên của nó, chấp nhận ngữ cảnh (trong trường hợp này là các bài đăng trong cơ sở dữ liệu), giờ đây có thể được hiển thị trong mẫu và trả về mẫu được xác định trong hàm. Mẫu sẽ là một tài liệu HTML với một chút ngôn ngữ gọi là jinja2, điều này hiển thị thông tin Python thành HTML. Để bắt đầu tạo các mẫu, hãy tạo hai thư mục trong thức ăn.

mkdir feed/templates
mkdir feed/templates/feed
Tiếp theo, chỉnh sửa một mẫu trong thư mục ở trên, nguồn cấp/mẫu/nguồn cấp dữ liệu và thêm mã cho ví dụ này. Hãy xem xét mẫu cho ví dụ này.
 
<!doctype HTML>
<html>
<body>
<legend>Feed</legend>
<hr>
{% for post in posts %}
<p>{{ post.text }}</p>
{% endfor %}
</body>
</html>
 
Đây là một mẫu rất đơn giản. Nó xác định mở và đóng thẻ HTML, thẻ loại tài liệu, thẻ cơ thể có tiêu đề huyền thoại, thẻ Break thêm một dòng nhỏ trên màn hình và một vòng lặp hiển thị mỗi bài đăng trong danh sách các bài đăng dưới dạng đoạn văn trong mẫu. Đây là tất cả những gì cần thiết để hiển thị các bài đăng, nhưng chưa có gì trong cơ sở dữ liệu. Hãy tạo một số với vỏ. Chúng ta có thể chạy shell bằng Management.py

python manage.py shell
Bây giờ, hãy nhập mô hình bài đăng của chúng tôi

from feed.models import Post
Tiếp theo, chúng tôi sẽ tạo một bài đăng đơn giản với một chuỗi và thoát vỏ. Chuỗi có thể là bất cứ điều gì, miễn là nó là văn bản hợp lệ.

Post.objects.create(text='hello world')
exit()
Cuối cùng, chúng tôi sẽ cần thêm một mẫu URL vào nguồn cấp dữ liệu của chúng tôi. Vì ứng dụng nguồn cấp dữ liệu của chúng tôi sẽ sử dụng nhiều URL và chúng tôi muốn giữ kích thước tệp nhỏ, hãy tạo một url.py cục bộ trong ứng dụng nguồn cấp dữ liệu của chúng tôi trông như thế này:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.feed, name='feed'),
]
Chúng tôi cũng sẽ cần chỉnh sửa urls.py trong ứng dụng cơ sở, bất cứ điều gì chúng tôi quyết định gọi nó, đây là thư mục đầu tiên chúng tôi tạo. Chỉnh sửa ứng dụng/app.py và thêm phần sau vào các mẫu URL

from django.urls import include # ở trên cùng

urlpatterns = [
    # ... Mã trước đây ở đây
    path('feed/', include(('feed.urls'), namespace='feed')),
]
Bây giờ, khi chúng tôi chạy máy chủ với Python Manage.py RunServer, chúng tôi sẽ thấy trang chúng tôi đã tạo vì chúng tôi có mô hình, chế độ xem và mẫu cũng như mẫu URL, cùng với các mục trong cơ sở dữ liệu. Tiếp theo, hãy thực hiện biểu mẫu chúng tôi đã tạo và bắt đầu tạo các bài viết của riêng mình. Nhưng trước khi chúng tôi viết quá nhiều mã, hãy tạo bản sao lưu bằng tập lệnh mà chúng tôi đã viết trước đó, sao lưu. Chạy tập lệnh này trong vỏ, đợi một vài khoảnh khắc và tất cả các mã sẽ được sao lưu vào kho Git của chúng tôi.

backup
Thực hiện hình thức là tương đối đơn giản. Chúng tôi sẽ nhập biểu mẫu của mình, thêm trình xử lý yêu cầu POST vào chế độ xem và lưu bài đăng trong cơ sở dữ liệu trước khi chuyển hướng đến cùng một chế độ xem. Chúng ta có thể sử dụng chức năng chuyển hướng mà chúng ta đã nhập và một chức năng khác được gọi là đảo ngược để lấy URL cho mẫu chế độ xem. Chúng tôi sẽ truy vấn điều này với chuỗi 'nguồn cấp dữ liệu: nguồn cấp' vì không gian tên của mẫu đi kèm là nguồn cấp dữ liệu và chế độ xem còn được gọi là nguồn cấp dữ liệu.

from feed.forms import PostForm

def feed(request):
    posts = Post.objects.all() # Truy vấn tất cả các bài đăng trong cơ sở dữ liệu cho đến nay
    if request.method == 'POST': # Xử lý yêu cầu bài viết
        form = PostForm(request.POST) # Tạo một thể hiện của biểu mẫu và lưu dữ liệu vào nó
        if form.is_valid(): # Xác thực biểu mẫu
            form.save() # Lưu đối tượng mới
        return redirect(reverse('feed:feed')) # Chuyển hướng đến cùng một url với yêu cầu nhận
    return render(request, 'feed/feed.html', {
        'form': PostForm(), # Hãy chắc chắn chuyển biểu mẫu vào bối cảnh để chúng tôi có thể hiển thị nó.
        'posts': posts,
    })
Bây giờ, chúng ta sẽ cần cập nhật mẫu để tính đến biểu mẫu mới. Chúng ta có thể làm điều này bằng cách sử dụng
Tag trong HTML và hiển thị biểu mẫu trong mẫu HTML bằng nút gửi. Chúng tôi cũng sẽ cần mã thông báo CSRF, mã thông báo ngăn các trang web bên ngoài đăng lên biểu mẫu mà không cần tải trang trước.
 
<!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>
 
Hãy phá vỡ điều này. Có một lớp biểu mẫu mới, mã thông báo, biểu mẫu và nút gửi. Khá đơn giản, nhưng khi chúng ta nhìn vào nó, chúng ta có thể muốn làm cho nó trông đẹp hơn. Nó hoạt động, chúng tôi có thể đăng các bài đăng mới với biểu mẫu và chúng hiện được lưu trong cơ sở dữ liệu. Có một vài điều đang diễn ra ở đây. Chúng tôi sử dụng thẻ HTML để khai báo rằng tài liệu là tài liệu HTML, chúng tôi sử dụng thẻ mẫu ({ %, %}) để hiển thị mã thông báo cho biểu mẫu và một loại khác, {{}}} để hiển thị biểu mẫu. Chúng tôi cũng có một vòng lặp để hiển thị văn bản bằng thẻ khối và thẻ mẫu. Thẻ khối thực sự quan trọng vì chúng ta có thể xác định cách các phần của mẫu được hiển thị với chúng và các thẻ mẫu là cơ sở của cách chúng ta đặt các biến vào mã của chúng ta. Bây giờ chúng ta cần làm cho ứng dụng của chúng ta trông tốt hơn, bởi vì bây giờ nó trông thực sự cơ bản. Chúng ta có thể làm điều này bằng cách sử dụng CSS, nội tuyến hoặc trong các lớp gắn liền với từng đối tượng trong tài liệu. CSS thực sự tốt đẹp vì nó cho mọi thứ nói về mọi thứ nên trông như thế nào,Và có thể làm cho nó trông thực sự tốt. Có một vài thư viện có thể làm điều này, nhưng cá nhân của tôi đi đến là bootstrap. Bootstrap có thể được tải xuống từ trang web của họ,Getbootstrap.com/. Khi đó, nhấn nút để đọc tài liệu cài đặt và sao chép mã từ phần bao gồm qua CDN. Bạn sẽ cần mã này ở đầu tài liệu HTML của bạn, trong một thẻ có tên là Head. Ngoài ra, chúng ta hãy tiếp tục và tạo một mẫu cơ sở để chúng ta không cần phải tạo lại các liên kết này trong mỗi mẫu. Tạo một thư mục mới được gọi là mẫu với các mẫu MKDIR, sau đó chỉnh sửa các mẫu/base.html. Nó sẽ trông như thế này:
 
<!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>
 
Đảm bảo sao chép các tệp CSS và JavaScript, các tệp .css và .js, bởi vì chúng tôi sẽ cần JavaScript để làm cho trang web của chúng tôi hoạt động nhiều hơn trong tương lai. Bây giờ, chúng ta hãy trở lại Bash Shell và chạy một lệnh nhanh. Hãy nhớ rằng, nếu bạn cần truy cập vào môi trường ảo, hãy nhập Nguồn VenV/Bin/Activate. Điều này sẽ cho phép bạn cài đặt các gói Python cục bộ theo cách cho phép Django truy cập chúng. Để cung cấp các biểu mẫu của chúng tôi được tạo bởi các lớp Django Bootstrap, chúng tôi sẽ sử dụng gói Python có tên là các hình thức giòn. Chúng tôi có thể tải xuống nó với lệnh sau

pip install django-crispy-forms
Khi điều này được cài đặt, hãy thêm nó vào Cài đặt.py

INSTALLED_APPS = [
    # “Mã trước đây ở đây
    'crispy_forms',
]
Bây giờ, trở lại trong mẫu thức ăn của chúng tôi, chúng tôi có thể loại bỏ một số thứ. Hãy loại bỏ phần đầu và cuối của tài liệu và thay thế nó bằng kế thừa từ mẫu cơ sở của chúng tôi, sử dụng mở rộng và định nghĩa khối. Ngoài ra, chúng tôi sẽ thêm nhập bộ lọc mẫu với tải và bộ lọc mẫu vào biểu mẫu. Cuối cùng, hãy thêm một lớp bootstrap vào nút trên biểu mẫu để làm cho nó trông giống như một nút. Điều đó trông như thế này:
 
{% 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 %}
 
Xinh đẹp! Đó là khá nhiều mã rồi. Tiếp theo, chúng ta nên kiểm tra nó và đảm bảo rằng chúng ta có thể thấy rằng mọi thứ đều đẹp, và cũng chắc chắn rằng mọi thứ đều hoạt động tốt. Chạy máy chủ theo hướng dẫn trước đó và đảm bảo trang web trông và hoạt động ổn. Công việc tuyệt vời! Bạn đã sẵn sàng để chuyển sang bước tiếp theo, trong đó chúng tôi sẽ thêm chức năng đăng nhập người dùng bằng các URL, biểu mẫu, chế độ xem và mẫu tương tự. Mẫu cơ sở rất quan trọng và chúng tôi sẽ tiếp tục sửa đổi nó và thực hiện các thay đổi khi cần thiết, nhưng bây giờ chúng ta hãy tập trung vào việc làm cho trang web của chúng tôi an toàn hơn, bằng cách cho phép người dùng đăng nhập bằng tên người dùng và mật mã và cuối cùng là thông tin quan trọng hơn Sẽ giúp bạn bảo mật ứng dụng của bạn và tài khoản của riêng bạn chỉ có thể truy cập được bởi bạn. Để làm điều này, chúng ta sẽ cần sử dụng mô hình người dùng được tích hợp vào Django. Mô hình người dùng là mô hình cơ sở dữ liệu, giống như bài đăng của chúng tôi, có thể được hiển thị để đăng nhập người dùng vào trang web. Trong tương lai, trước khi chúng tôi triển khai trang web lên Internet, chúng tôi sẽMở rộng mô hình này với các mô hình khác được quy cho nó và xây dựng các biện pháp bảo mật bổ sung cho việc đăng nhập có khả năng chống lừa đảo. Chúng tôi sẽ bắt đầu bằng cách sử dụng một số hình thức đăng nhập tích hợp mà Django cung cấp. Trước tiên, hãy tạo một ứng dụng mới mà chúng tôi sẽ sử dụng để hiển thị các mẫu và chế độ xem cho trang đăng nhập cơ bản. Chúng tôi cũng sẽ tạo các ứng dụng khác để thể hiện các thách thức đăng nhập liên tục để bảo mật ứng dụng, bao gồm pincode, nhận dạng khuôn mặt, giao tiếp trường gần, thiết bị bên ngoài, xác thực đa yếu tố và nhận dạng dấu vân tay. Chúng tôi đã nói về việc bắt đầu một ứng dụng. Từ thư mục của chúng tôi, bên trong môi trường ảo, vượt qua quản lý.

python manage.py startapp users
Bây giờ, chúng ta nên có một thư mục cho ứng dụng mới. Hãy bắt đầu bằng cách tạo chế độ xem trong thư mục đó tương ứng với đăng nhập người dùng. Django đã tích hợp các chế độ xem để đăng nhập người dùng, nhưng chúng sẽ không phù hợp với chúng tôi vì chúng tôi cần một chế độ xem tùy chỉnh, tốt nhất là được thực hiện với một định nghĩa. Theo quan điểm này, chúng tôi sẽ bắt đầu bằng cách kiểm tra yêu cầu POST, Pass Request.post to Loginform được nhập từ Django, xác thực tài khoản người dùng và đăng nhập người dùng trước khi chuyển chúng đến ứng dụng nguồn cấp dữ liệu của chúng tôi. Trong người dùng/chế độ xem.py, hãy thêm mã sau

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'] # Nhận tên người dùng và mật khẩu từ yêu cầu bài đăng
        password = request.POST['password'] # Xác thực người dùng
        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()})
Đây là tất cả những gì bạn cần cho một chế độ xem đăng nhập cơ bản. Bây giờ, hãy tạo một biểu mẫu cho chế độ xem bằng cách mở rộng mẫu cơ sở. Chúng tôi sẽ bắt đầu bằng cách tạo một thư mục mới cho các mẫu trong thư mục người dùng.

mkdir users/templates
mkdir users/templates/users
Bây giờ, chúng ta sẽ có thể chỉnh sửa người dùng/mẫu/người dùng/đăng nhập.html. Trong khi chúng tôi ở đó, chúng tôi sẽ tạo một mẫu để cho phép người dùng đăng ký.

nano users/templates/users/login.html
Bây giờ, trong mẫu,
 
{% 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 %}
 
Đây là những điều cơ bản của một mẫu đăng nhập. Nó thực sự giống như mẫu khác trong cấu trúc, nhưng nó trông hơi khác một chút khi nó được hiển thị. Chúng ta có thể sao chép mã này để xây dựng một mẫu rất giống nhau có tên là Đăng ký.html, nơi chúng ta sẽ thay đổi từ ngữ và sử dụng một biểu mẫu mới mà chúng ta xây dựng. Hãy làm mẫu trước. Chỉnh sửa người dùng/Mẫu/Người dùng/Đăng ký.html và thêm mã sau:
 
{% 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 %}
 
Bây giờ, hãy xây dựng một biểu mẫu cho đăng ký người dùng của chúng tôi và quay lại các chế độ xem trước khi chúng tôi nâng cấp đăng nhập người dùng của mình với một mô hình. Chúng tôi sẽ thực hiện hình thức cơ bản này để bắt đầu, nhưng kết hợp nhiều chi tiết và tính năng bảo mật như thỏa thuận và captcha trong tương lai. Chỉnh sửa các biểu mẫu với người dùng nano/forms.py và thêm mã sau.

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']
Vì vậy, chúng tôi có một hình thức khác ở đây, hoạt động khá đơn giản. Đó là biểu mẫu đăng ký người dùng với tên người dùng, email và mật khẩu, cũng như trường xác nhận mật khẩu. Lưu ý rằng biểu mẫu này không mở rộng lớp mẫu thông thường. Đó là một hình thức mô hình có nghĩa là nó có meta. Một trường được xác định giống nhau và lớp meta định nghĩa mô hình hình thức tương ứng với phần còn lại của thông tin sẽ được ghi vào biểu mẫu. Hầu hết điều này đã tồn tại trong Django được tích hợp trong người dùng, vì vậy chúng tôi sẽ sử dụng nó làm cơ sở cho lớp (được thông qua trong dấu ngoặc đơn). Tiếp theo, chúng tôi sẽ kiểm tra chế độ xem để đăng ký người dùng, bây giờ chúng tôi có một biểu mẫu và một mẫu. Đây là một modelform, giống như phần trong chế độ xem bài mới. Chỉnh sửa người dùng/ViewS.Py và thêm mã sau:

# Số tiền
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})
Đây là tất cả những gì chúng ta cần để có được một người dùng đã đăng ký, nhưng chúng ta nên có thêm thông tin. Chúng tôi muốn biết thời gian người dùng đã đăng ký, thời gian cuối cùng trên trang web, một số thông tin về họ, như tiểu sử, múi giờ, v.v. Mô hình và thuộc tính bài đăng cho mỗi người dùng. Để làm điều đó, chúng tôi sẽ cập nhật các mô hình.py trong cả hai ứng dụng. Hãy bắt đầu bằng cách chỉnh sửa mô hình thức ăn. Nó sẽ trông như thế này bây giờ:

from django.db import models # Số tiền
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') # Thêm vào dòng này
    text = models.TextField(default='')
Hãy chú ý đến dòng thứ hai đã được thêm vào tệp. Đây là khóa ngoại, sẽ gán cho mỗi bài đăng cho một người dùng cho mỗi bài đăng, vì vậy chúng tôi có thể đảm bảo rằng chúng tôi lưu các bài đăng trên cơ sở người dùng cho người dùng cho người dùng và không có bài đăng nào có thể được thực hiện mà không quy kết nó cho người dùng. Chúng tôi xác định khóa nước ngoài này với lớp mà nó đại diện, một đối số xóa để đảm bảo các bài đăng bị xóa với người dùng, null và các đối số trống để đảm bảo chúng tôi có thể xóa người dùng nếu cần thiết và để phù hợp với việc thiếu người dùng trên các bài đăng mà chúng tôi đã Được tạo và một tên liên quan, mà chúng ta có thể sử dụng để tham khảo các đối tượng bài mà người dùng tạo ra. Tên liên quan này, không giống như Post.Author, tác giả của bài đăng, cung cấp cho chúng tôi người dùng đã đăng bài đăng. Bây giờ chúng ta có thể nhận được các bài đăng mà người dùng tạo bằng cách chạy user.posts.all () hoặc tác giả.posts.all (). Bây giờ, chúng ta hãy làm cho đăng nhập của chúng ta trở nên kiên cường hơn. Chúng tôi đã có thể làm cho trang web của chúng tôi ít bị tổn thương hơn để lừa đảo bằng cách đơn giản là giới hạn số lần chúng tôi sẽ cho phép đăng nhập vàoTrang web, điều này là khá dễ dàng. Cũng hãy bắt đầu lưu trữ một số thông tin về từng người dùng trước khi chúng tôi tiếp tục phát triển ứng dụng của mình. Chỉnh sửa người dùng/model.py, thêm phần sau

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='')
Lưu ý rằng mô hình này khá giống với mô hình POST. Chúng tôi có một lần nhập bổ sung, timezone, cho phép chúng tôi đặt mặc định trên các trường DateTime và chúng tôi cũng có một trường ký tự và trường văn bản như bài đăng. Sử dụng tất cả các dấu thời gian này giúp chúng tôi bảo mật trang web và hiểu được việc sử dụng nó và các trường văn bản cho phép chúng tôi hiển thị thông tin về từng người dùng hoặc tác giả trên trang web. Onetoonefield nên là sự cân nhắc nhỏ duy nhất, nó hoạt động giống hệt như một foreginey nhưng chỉ có một mô hình tiếp theo. Bằng cách này, người dùng chỉ có một hồ sơ, trong khi họ có thể có nhiều bài đăng. Bây giờ, hãy cải thiện thông tin đăng nhập và đăng ký của chúng tôi để tính toán cho hồ sơ. Đầu tiên, chỉnh sửa người dùng/chế độ xem.py và tập trung vào chế độ xem đăng ký:

# Số tiền
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) # Đảm bảo thêm dòng này, để tạo một cấu hình cho người dùng
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
Điều này chỉ đơn giản là tạo một hồ sơ cho người dùng, mà không điền vào bất kỳ thông tin nào. Bây giờ, chúng tôi muốn đảm bảo tài khoản người dùng không thể đăng nhập quá thường xuyên hoặc ít nhất là mật khẩu không thể được thử quá thường xuyên, vì vậy hãy cập nhật chế độ xem đăng nhập.

# Số tiền
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(): # Lưu ý rằng bây giờ chúng tôi kiểm tra xem người dùng có thể đăng nhập không
            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: # Nếu đăng nhập không thành công,
            messages.warning(request, 'Username or password incorrect. Please try again.')
            user = User.objects.filter(username=username).first() # Đây là phần mà chúng tôi cập nhật hồ sơ người dùng
            if user: 
                profile = user.profile
                profile.can_login = timezone.now() + datetime.timedelta(seconds=15) # Vì vậy, họ không thể đăng nhập lại trong vài giây
                profile.save()
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
Đây là cơ bản cơ bản của bảo mật. Hãy chắc chắn rằng trang web không dễ bị tổn thương đối với ai đó chỉ cần thử mọi kết hợp mật khẩu có thể, hoặc thậm chí một vài trong số chúng cùng một lúc. Điều này sẽ không gây khó chịu cho người dùng thông thường, người biết mật mã của họ và chỉ đăng nhập vào một vài thiết bị, nhưng nó sẽ giữ nhiều robot lừa đảo ra khỏi ứng dụng. Lưu ý rằng chúng tôi đã thêm một câu lệnh IF với một biến, can_login, đó sẽ là thời gian trong quá khứ và cập nhật nó với mỗi đăng nhập không thành công bằng cách sử dụng cùng một tên người dùng. Bằng cách này, một người dùng độc hại sẽ không thể đoán được mật khẩu ở bất cứ đâu gần như nhanh chóng. Số giây trong datetime.timedelta () cũng có thể được cập nhật và trang web sẽ có khả năng phục hồi hơn nhưng ít có thể sử dụng được với nhiều giây hơn. Tôi đề nghị 15 để bắt đầu với. Hãy nhớ rằng, chúng tôi đã xây dựng một tập lệnh sao lưu để lưu công việc của chúng tôi, vì vậy hãy tiếp tục và sao lưu những gì chúng tôi có cho đến nay để đảm bảo rằng chúng tôi đã lưu mọi thứ. Chạy lệnh:

sudo backup
Một lần nữa, điều này sẽ tiết kiệm công việc của bạn cho đến nay. Tôi khuyên bạn nên chạy các bản sao lưu thường xuyên để lưu công việc của bạn và bạn thậm chí có thể muốn chạy một công việc sao lưu tự động. Bạn có thể làm điều này bằng cách sử dụng một tiện ích UNIX gọi là Cron. Để kích hoạt tiện ích này, hãy chạy lệnh sau và nhập mật khẩu của bạn:

sudo crontab -e
Nếu bạn chưa chọn Tùy chọn 1 cho Nano, trình soạn thảo văn bản mà bạn đã quen thuộc và cuộn xuống dưới cùng của tệp bằng các phím mũi tên. Thêm dòng sau:

0 * * * * sudo backup
Cron sử dụng định dạng phút, giờ, ngày của tháng, tháng, ngày trong tuần, trong đó A * hoặc một số đại diện khi chạy lệnh. Sử dụng 0 cho phút và * cho phần còn lại của các tùy chọn, chúng ta có thể chạy một lệnh vào phút đầu tiên của mỗi giờ vào đầu phút. Điều này cho phép chúng tôi tự động sao lưu mã. Tất cả các công việc của Cron khi được thực hiện với sudo chạy dưới dạng root, vì vậy chúng tôi sẽ không cần gõ mật khẩu mỗi giờ. Để giúp việc sao lưu mã của chúng tôi dễ dàng hơn mà không cần sử dụng mật khẩu, hãy tắt mật khẩu cho lệnh sao lưu của chúng tôi. Chúng tôi sẽ làm điều này bằng cách thực hiện lệnh sau và nhập mật khẩu:

sudo visudo
Bây giờ, hãy cuộn xuống dưới cùng của tệp và thêm một dòng khác:

ALL ALL=NOPASSWD: /bin/backup
Điều này cho phép chúng tôi chạy lệnh Sao lưu Sao lưu với bất kỳ người dùng nào mà không cần mật khẩu. Định dạng cho điều này rất dễ dàng, chỉ cần tiền tố dòng với tất cả tất cả = nopasswd:/bin/và kết thúc với lệnh, ví dụ/bin/sao lưu, tồn tại trong/usr/bin/. Bây giờ, hãy bắt đầu làm việc với email. Email thực sự quan trọng đối với các trang web, bởi vì đó là một cách để giữ cho một trang web an toàn hơn, xác minh người dùng là người thật và thậm chí là sản phẩm hoặc dịch vụ thị trường cho khách hàng. Nhiều người thường xuyên qua Internet kiểm tra email của họ hàng ngày và nhận được tất cả các loại email tiếp thị về các sản phẩm và dịch vụ mà họ quan tâm. Có một vài lựa chọn khi cho phép email trên trang web Django và bạn được chào đón để chọn Bất cứ điều gì làm việc tốt nhất cho bạn. Đầu tiên, bạn có thể trả tiền cho một dịch vụ email cho phép bạn gửi email từ tên miền của mình và yêu cầu mã tối thiểu. Có nhiều dịch vụ cung cấp điều này, chẳng hạn như không gian làm việc của Google, SendInblue, Mailgun, v.v. Nếu không, bạn đang xây dựng tốtDịch vụ email của riêng bạn trong máy chủ của bạn từ đầu. Tôi đề xuất tùy chọn này, mặc dù nó có nhiều mã hơn và có thể yêu cầu lưu trữ đặc biệt. Bạn sẽ không thể khởi động một máy chủ thư từ máy tính gia đình của mình rất có thể, vì vậy hãy tiếp tục và kiểm tra cấu hình và mã để gửi email trước khi chúng tôi khởi động một máy chủ trên đám mây và tạo máy chủ thư của riêng chúng tôi bên trong. Đầu tiên, chỉnh sửa cài đặt.py với phần sau

nano app/settings.py
Trong đó ứng dụng là tên của ứng dụng bạn đã tạo với StartApp. Thêm các dòng sau:

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)
Đảm bảo thay đổi những điều này khi bạn sẵn sàng triển khai ứng dụng của mình, chúng tôi sẽ xem lại điều này sau. Cài đặt email_address phải là email bạn muốn gửi từ đó và mật khẩu (email_host_password) sẽ được đặt thành mật khẩu bạn tạo cho máy chủ. Tôi tải mật khẩu vào từ tệp cấu hình để giữ nó ra khỏi mã bằng logic sau, trên các dòng này trong SALKS.PY:

import os
import json
with open('/etc/config.json') as config_file:
    config = json.load(config_file)
Sau đó, tôi đã thiết lập một tệp JSON với cấu hình trong /etc/config.json bằng cách sử dụng nano như sau. Để chỉnh sửa tệp:

sudo nano /etc/config.json
Thêm các dòng sau:

{
	“EMAIL_HOST_PASSWORD”: “<some password here>”
}
Chúng tôi sẽ tiếp tục chỉnh sửa tệp cấu hình và thêm tất cả các mật khẩu và khóa chúng tôi sẽ sử dụng trong ứng dụng. Hiện tại, hãy nhanh chóng kiểm tra cách gửi email bằng Python. Trước tiên, hãy tạo một mẫu cho một email xác minh mà chúng tôi có thể gửi cho người dùng của mình và đặt nó vào thư mục mẫu người dùng. Mẫu này sẽ được viết bằng 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>
 
Email này khá đơn giản. Nó có bối cảnh của người dùng, URL cơ sở cho Trang web và ID người dùng và mã thông báo được sử dụng để xác minh email của người dùng. Đảm bảo xác định URL cơ sở trong Cài đặt.Py trước khi chúng tôi viết một số mã Python để hiển thị mẫu. Hãy tiếp tục và thêm các dòng sau vào Ứng dụng/Cài đặt.py, gần đầu.

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

BASE_URL = PROTOCOL + '://' + DOMAIN
Cuối cùng, khi trang web của bạn đã sẵn sàng cho Internet và bạn triển khai nó, bạn sẽ muốn xác định tên miền của mình là tên miền bạn mua để đại diện cho trang web. Đây là tên mà bạn sẽ nhập vào thanh điều hướng để truy cập trang web của bạn. Hiện tại, bạn có thể để trống miền hoặc sử dụng trình giữ chỗ. Bạn cũng sẽ muốn thay đổi trang web_name thành một tên bạn muốn cung cấp cho trang web của bạn, về sự lựa chọn của bạn. Trước khi chúng tôi gửi email, chúng ta hãy tạo một trình tạo mã thông báo để chúng ta có thể có mã thông báo kích hoạt tài khoản không bao giờ hết hạn. Chúng tôi có thể làm điều này bằng cách xây dựng và nhập mã thông báo kích hoạt tài khoản trông giống như sau. Chỉnh sửa tệp:

nano users/tokens.py
Thêm mã sau:

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()
Trình tạo mã thông báo cơ bản này tạo mã thông báo mà chúng tôi có thể gửi người dùng trong URL và người dùng có thể sử dụng để xác minh email của họ và kích hoạt tài khoản của họ. Tiếp theo, hãy xem cách gửi email. Sử dụng nano, chỉnh sửa người dùng/email.py.

nano users/email.py
Gửi email HTML xác minh sẽ trông như thế này:

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)
Điều này khá đơn giản. Chúng tôi nhập các chức năng mà chúng tôi cần để gửi email, hiển thị email bằng các mẫu và cài đặt của chúng tôi, sau đó chúng tôi xác định email bằng tên mẫu và gửi cho người dùng bằng cách sử dụng chức năng. Bạn sẽ nhận thấy rằng chúng tôi đã không xác định chức năng để gửi thư, send_html_email, vì vậy hãy viết cái này bên dưới mã mà chúng tôi đã thêm vào người dùng/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()
Điều này phức tạp hơn một chút và chúng tôi chưa sẵn sàng để chạy tất cả mã này. Lưu ý rằng chúng tôi đang xác định một liên kết không liên kết, liên kết mà người dùng có thể sử dụng để hủy đăng ký từ email của chúng tôi. Điều này rất quan trọng, bởi vì người dùng sẽ cần có khả năng từ chối email của chúng tôi trừ khi họ muốn xem chúng bất cứ lúc nào. Chúng tôi cũng thêm một thay thế văn bản cho tin nhắn của chúng tôi, đó là thông báo HTML bị tước các thẻ HTML. Cuối cùng, chúng tôi kiểm tra xem email đã được gửi và nếu không, chúng tôi đánh dấu trong hồ sơ của người dùng rằng email của họ không hợp lệ. Chúng ta hãy quay trở lại các mô hình người dùng để chúng ta có thể làm cho tất cả hoạt động này. Chúng ta cần xác định một hàm để tạo liên kết để hủy đăng ký và xác định trường boolean để đánh dấu rằng email của người dùng không hợp lệ. Đầu tiên, thêm các bản nhập sau vào đầu người dùng/model.py

nano users/models.py

# …
from django.core.signing import TimestampSigner, BadSignature, SignatureExpired
from django.urls import reverse
Tiếp theo, hãy thêm các chức năng vào mô hình người dùng để tạo mã thông báo và kiểm tra mã thông báo được sử dụng để kích hoạt email, cũng như trường để lưu xem người dùng có nhận được thư thành công hay không. Trong người dùng/model.py một lần nữa, hãy thêm mã sau vào cuối mô hình (mã thụt lề)

# …
    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) # Có giá trị trong 30 ngày
        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,})
Điều này khá đơn giản, chúng tôi sử dụng dấu thời gian, đây là một công cụ mật mã cơ bản, để tạo mã thông báo sẽ hết hạn sau một khoảng thời gian nhất định và chúng tôi cũng sử dụng một chức năng khác để kiểm tra xem nó có hợp lệ không. Chúng tôi sử dụng các mã thông báo này hai lần, một lần để xác minh email và một lần cho một liên kết hủy đăng ký. Bây giờ chúng ta có những thứ này, công việc cuối cùng chúng ta sẽ cần làm là trong các quan điểm. Trong người dùng/ViewS.Py, hãy thêm lượt xem để xác minh địa chỉ email và để hủy đăng ký.

nano users/views.py
Đầu tiên, thêm các nhập khẩu sau. Tôi đã ném thêm một vài để chúng tôi sẽ không phải nhập thêm các mặt hàng sau này.

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 # Đảm bảo nhập chức năng gửi email xác minh
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
Bạn có thể đã có một số trong những hàng nhập khẩu này, nhưng không có gì đau khi lặp lại chúng. Bạn sẽ cần nhập chức năng gửi email xác minh, cũng như tài khoản_activation_token từ user.tokens, trong số các nhập khẩu khác. Bây giờ, ở dưới cùng của tệp, thêm mã sau:

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)):
        # Hủy đăng ký chúng
        profile = user.profile
        profile.subscribed = False
        profile.save()
        return render(request, 'users/unsubscribe.html')
    # Nếu không, chuyển hướng đến trang đăng nhập
    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 (yêu cầu, người dùng)
        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})
Đây là rất nhiều mã. Hãy phá vỡ nó. Hàm đầu tiên, sạch sẽ và đơn giản, hủy đăng ký người dùng khỏi danh sách gửi thư. Chức năng thứ hai kích hoạt email của họ và bạn sẽ nhận thấy tôi đã thêm một chức năng nhận xét, sendWelcomeemail. Bạn có thể sử dụng một mẫu email và định nghĩa chức năng để gửi email chào mừng, tôi vẫn chưa. Chức năng cuối cùng tôi ném vào là rất quan trọng, bởi vì email kích hoạt hết hạn. Do đó, chúng tôi sẽ cần phải gửi lại email kích hoạt một số thời gian. Chúng ta có thể sử dụng một biểu mẫu cơ bản cho việc này và gọi chức năng để gửi email xác minh. Trước khi chúng tôi làm điều này, hãy đảm bảo rằng nó sẽ được gửi ngay từ đầu, bằng cách thêm một cuộc gọi chức năng vào chế độ xem đăng ký. Thêm dòng này ngay trước khi chuyển hướng trong chế độ xem đăng ký, đăng ký DEF, trong người dùng/chế độ xem.py.

nano users/views.py

# Mạnh (sau) Đăng ký DEF (Yêu cầu):
            send_verification_email(user)
# … (Trước) chuyển hướng (
Bạn không cần thêm các dòng đầu tiên và cuối cùng trong đoạn mã đó, chỉ cần đảm bảo chế độ xem đăng ký gửi email xác minh cho người dùng. Nó sẽ trông như thế này:

# Nhập khẩu
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) # Hãy chắc chắn để thêm dòng này!
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
Bây giờ, chúng ta sẽ cần thêm một biểu mẫu để gửi lại email kích hoạt. Trong người dùng/forms.py, thêm biểu mẫu sau:

# … (Số tiền)
class ResendActivationEmailForm(forms.Form):
    email = forms.EmailField(required=True)
Chúng tôi cũng sẽ cần một mẫu tương ứng với biểu mẫu kích hoạt email Resend này. Hãy thêm mẫu này vào. Chỉnh sửa tệp:

nano users/templates/users/resend_activation.html
Tiếp theo, thêm mã sau vào tệp.

{% extends 'base.html' %}
{% block content %}
{% load crispy_forms_tags %}
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Resend activation email</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-secondary" type="submit">Resend activation email</button>
            </div>
        </form>
{% endblock %}
Whew, đó là rất nhiều! Bây giờ, khi chúng tôi triển khai mã đến máy chủ của mình, chúng tôi sẽ có thể gửi email HTML và kích hoạt tài khoản người dùng bằng một cú nhấp chuột trong email. Chúng tôi cũng có thể muốn gửi một email chào mừng đơn giản, vì vậy hãy xem cách làm điều đó. Quay lại người dùng/email.py, thêm mã sau:

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)
Ngoài ra, chúng tôi sẽ cần một mẫu để hiển thị tất cả các thông tin này. Trên trang web của tôi, mẫu trông giống như bên dưới, nhưng bạn có thể định dạng nó theo cách bạn thích.
 
<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>
 
Lưu ý rằng chúng tôi không có thẻ đóng hoặc thẻ HTML, bởi vì chúng tôi thêm chúng vào khi chúng tôi thêm liên kết hủy đăng ký HTML. Đây là những điều quan trọng, nhưng chúng tôi không muốn định nghĩa chúng hai lần. Vậy tiếp theo là gì? Chúng tôi đã đi một chặng đường dài. Thực sự, chúng ta nên sẵn sàng triển khai trang web đến một máy chủ. Chúng tôi có thể thêm công cụ trang trí @Login_Required và làm cho chế độ xem của chúng tôi an toàn, đăng ký người dùng, gửi email tuân thủ và thông tin bộ nhớ cache, đây là cơ sở của những gì một trang web cần làm để có liên quan. Chúng tôi sẽ thêm một vài tính năng hữu ích hơn và sau đó xây dựng cơ sở để triển khai mã của chúng tôi đến một máy chủ từ xa, thiết lập máy chủ thư, cấu hình tên miền và các bộ lọc để làm cho trang web của chúng tôi an toàn và phù hợp. Chúng tôi cũng cần một chế độ xem đặt lại mật khẩu, vì vậy hãy thêm nó thực sự nhanh chóng. Chế độ xem đặt lại mật khẩu tích hợp của Django bị phá vỡ trong một số chức năng, nhưng chúng tôi sẽ xem xét cách viết chế độ xem, mẫu email, biểu mẫu và các mẫu URL của riêng chúng tôi. Đây là xem chế độ xem trông như thế nào, trong người dùng/lượt xem.py

# ... số tiền
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)
Biểu mẫu này được tích hợp theo Django, nhưng chúng tôi sẽ cần một mẫu để xác nhận thiết lập lại mật khẩu, người dùng/mẫu/người dùng/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 %}
 
Chúng tôi cũng có một mẫu để gửi email đặt lại mật khẩu, với một biểu mẫu đơn giản, trong người dùng/mẫu/người dùng/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 %}
 
Mẫu cho chính email rất đơn giản, đây là tệp HTML cơ bản hiển thị một liên kết để đặt lại mật khẩu, trong người dùng/mẫu/người dùng/password_reset_email.html. Django sẽ tự động giải thích tập tin này.
 
<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>
 
Chúng tôi cũng cần thêm hai mẫu. Đầu tiên là xác nhận rằng email đã được gửi. Quan điểm cho những điều này đã có trong Django, vì vậy chúng ta chỉ cần giải quyết chúng trong urls.py. Mẫu này được đặt tại người dùng/mẫu/người dùng/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 %}
 
Và cuối cùng, để xác nhận rằng thiết lập lại mật khẩu đã hoàn tất, người dùng/mẫu/người dùng/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 %}
 
Bây giờ, chúng ta cần các mẫu URL cho các quan điểm này. Trong người dùng/urls.py, thêm các mẫu URL sau:

urlpatterns = [
    # ... URL trước đây ở đây
    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'),
]
Bốn mẫu, đó là rất nhiều! Nhưng bây giờ chúng tôi có thể chắc chắn có thể đặt lại mật khẩu của người dùng bất cứ khi nào chúng tôi cần, tất cả từ trình duyệt web. Tôi hiểu đây là rất nhiều mã. Nếu nó có vẻ một chút trên đầu bạn, thì không sao. Bạn sẽ cải thiện, sự hiểu biết của bạn sẽ được cải thiện và bạn sẽ sớm trở nên có năng lực hơn với mã. Nếu bạn hoàn toàn lạc lối, tôi khuyên bạn nên quay lại phần mềm này sau khi làm việc trên một khóa học tự học để viết mã trực tuyến. Đây thường là miễn phí để bắt đầu và sẽ hướng dẫn bạn mọi thứ bạn cần để thành công khi bạn quay lại dự án này. Nếu bạn cảm thấy như bạn đã sẵn sàng để tiếp tục, hãy đọc tiếp, tiếp theo, chúng tôi sẽ trình bày triển khai mã của bạn đến một máy chủ từ xa và thiết lập một máy chủ thư, cũng như tự động hóa việc triển khai của bạn bằng Bash để bạn luôn có thể thiết lập một dự án mới với Một vài lệnh đơn giản. Điều cuối cùng chúng ta cần làm trước khi triển khai đến một máy chủ từ xa là làm cho trang web của chúng tôi an toàn hơn một chút. Bạn sẽLưu ý rằng chế độ xem đăng nhập chỉ lấy tên người dùng và mật khẩu và không có xác thực nhiều yếu tố hoặc mã thời gian. Đây là một bản sửa lỗi dễ dàng và với cùng một mã, chúng tôi có thể làm cho trang web của chúng tôi gửi tin nhắn văn bản và thậm chí phản hồi các tin nhắn văn bản được gửi đến máy chủ. Để bắt đầu, chúng tôi sẽ quay lại các mô hình người dùng và thêm một trình ký dấu thời gian sẽ đại diện cho mỗi đăng nhập. Chúng tôi cũng sẽ thêm một định danh xoay, độc đáo vào mô hình người dùng sẽ được sử dụng để thêm bảo mật thêm vào đăng nhập của chúng tôi. Chỉnh sửa các mô hình người dùng, người dùng/model.py, thêm các mô hình sau

from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
# Đảm bảo nhập UUID, Trình đăng ký dấu thời gian và trình tạo URL (đảo ngược)
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='')
    # Thêm mã này vào đây
    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)

    # Và thêm chức năng này
    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) # Có giá trị trong 3 phút
        except (BadSignature, SignatureExpired):
            return False
        return True
Đảm bảo người dùng/model.py của bạn trông như thế này, bên cạnh các nhận xét (mã trên các dòng có #). Phá vỡ điều này, nó đơn giản. Chúng tôi có một vài nhập khẩu, dấu thời gian là một tiện ích mật mã có thể tạo mã an toàn và xác minh nó để đảm bảo nó hợp lệ, chỉ được sử dụng một lần và không cũ hơn một số giây nhất định. Chúng tôi cũng sử dụng UUID, một mã định danh duy nhất xác định người dùng của chúng tôi trong việc ký mã thông báo và trong URL nơi mã thông báo được gửi cho người dùng. Chúng tôi sẽ sử dụng mật mã cơ bản này để xây dựng chế độ xem xác thực hai yếu tố. Trước khi chúng tôi làm bất cứ điều gì khác, hãy chạy các di chuyển để các mô hình người dùng của chúng tôi được cập nhật. Trong thư mục với Manage.py, hãy chạy các lệnh sau để thực hiện và hoàn thành việc di chuyển.

source venv/bin/activate
python manage.py makemigrations && python manage.py migrate
Điều này rất quan trọng vì mỗi lần chúng tôi thay đổi các mô hình, chúng tôi sẽ cần tạo các bảng và cập nhật cơ sở dữ liệu với mặc định trước khi chúng tôi thực sự có thể sử dụng các mô hình. Tiếp theo, hãy ứng biến chế độ xem đăng nhập của chúng tôi để chuyển hướng đến chế độ xem xác thực thứ cấp. Trong người dùng/chế độ xem.py, hãy xóa chức năng đăng nhập và chuyển hướng đến URL mà chúng tôi vừa tạo trong các mô hình người dùng.

# Số tiền

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(): # Lưu ý rằng bây giờ chúng tôi kiểm tra xem người dùng có thể đăng nhập không
            # Xóa chức năng auth_login ở đây
            messages.success(request, 'Your password was accepted. Please continue.')
            if user.profile.mfa_enabled:
                return redirect(user.profile.create_auth_url()) # Lưu ý chúng tôi chuyển hướng đến một url mới ở đây
            else: # Nếu người dùng không sử dụng xác thực đa yếu tố, chỉ cần đăng nhập chúng.
                auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
                return redirect('feed:feed')
        else: # Nếu đăng nhập không thành công,
            messages.warning(request, 'Username or password incorrect. Please try again.')
            user = User.objects.filter(username=username).first() # Đây là phần mà chúng tôi cập nhật hồ sơ người dùng
            if user: 
                profile = user.profile
                profile.can_login = timezone.now() + datetime.timedelta(seconds=15) # Vì vậy, họ không thể đăng nhập lại trong vài giây
                profile.save()
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
Vì vậy, điều này khá đơn giản, bây giờ chúng ta có một cách để chuyển hướng đến chế độ xác thực hai yếu tố khi chúng ta tạo nó. Chúng tôi cũng có một dự phòng trong trường hợp người dùng chưa thêm số điện thoại. Chúng tôi sẽ thêm một chế độ xem cơ bản để sớm thêm số điện thoại và đăng nhập bằng tin nhắn văn bản sớm. Đầu tiên, chúng tôi cần một cách dễ dàng để gửi tin nhắn văn bản từ mã của chúng tôi. Để làm điều này, chúng ta có thể chọn từ một số API, nhưng theo ý kiến ​​của tôi là Twilio. Họ cũng cung cấp giá tốt cho các dự án nhỏ hơn, cũng như giảm giá số lượng lớn. Tạo một tài khoản trên Twilio.com, điền vào một số chi tiết về dự án của bạn, mua số điện thoại và sao chép các khóa API của bạn vào cài đặt của bạn. Sau đó, thêm mã này dưới một tệp mới, người dùng/sms.py.

nano users/sms.py

# Nhập tất cả các gói cần thiết
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

# Mã này gửi văn bản với 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())

# Một hàm trợ giúp để có được một số có rất nhiều chữ số
def get_num_length(num, length):
    n = ''
    for x in range(length):
        n = n + str(num)
    return int(n)

# Gửi văn bản để xác minh người dùng
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)))

# Gửi cho người dùng bất kỳ văn bản nào với chức năng này
def send_user_text(user, text):
    send_text(user.profile.phone_number, text)

# Xác thực mã với chức năng này
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

# Xác thực thời gian
def check_verification_time(user):
    result = user.profile.mfa_code_expires > timezone.now()
    return result
Hãy chắc chắn thay đổi cài đặt của bạn một cách thích hợp, thêm các dòng này với các khóa của bạn:

# Đảm bảo sao chép những thứ này từ bảng điều khiển Twilio của bạn
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 # Số phút trang TFA hoạt động khi khởi tạo
Đầu tiên, chúng tôi sẽ cần các biểu mẫu cho các quan điểm xác thực hai yếu tố của chúng tôi. Chỉnh sửa người dùng/forms.py, thêm mã sau.

# Nhập khẩu
from django import forms

# Một biểu mẫu để nhập số điện thoại của chúng tôi
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

# Một hình thức để xác thực
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.'
    }
Tiếp theo, hãy tạo các chế độ xem trong người dùng/lượt xem.py

# Số tiền
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})
Chúng tôi cũng sẽ cần các mẫu cho cả hai quan điểm này. Trước tiên hãy thêm mẫu MFA.

nano users/templates/users/mfa.html
Thêm mã HTML này vào mẫu
 
{% 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 %}
 
Đây là khá tự giải thích. Biểu mẫu gửi mã hoặc mã trống và bạn sẽ nhận thấy trong chế độ xem, chúng tôi gửi mã nếu chúng tôi nhận được mã trống. Sau đó, chúng tôi chỉ có hai nút gửi và bằng cách này chúng tôi có thể gửi mã bằng một trong hai nút. Tiếp theo, chúng tôi sẽ thêm một biểu mẫu đơn giản để thêm số điện thoại.

nano users/templates/users/mfa_onboarding.html
Thêm HTML sau:
 
{% 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 %}
 
Biểu mẫu này đơn giản hơn rất nhiều, nó chỉ hiển thị biểu mẫu số điện thoại chúng tôi đã tạo và cho phép người dùng thêm một số điện thoại. Điều này trông thực sự tốt! Miễn là mọi thứ được thiết lập đúng, chúng tôi sẽ có thể gửi tin nhắn và đăng nhập người dùng bằng số điện thoại của họ ngay khi chúng tôi thêm các mẫu URL. Điều cuối cùng chúng ta cần thiết lập là chế độ xem hồ sơ để chúng ta có thể đảm bảo người dùng có thể thay đổi số điện thoại của họ mà không cần đăng nhập. Ngoài ra, cuối cùng chúng ta sẽ muốn thêm một điểm dừng để thoát khỏi tùy chọn, để người dùng có thể nhắn tin Cấm dừng lại để từ chối các tin nhắn văn bản trong tương lai. Hãy thêm một chế độ xem hồ sơ vào người dùng/chế độ xem.py. Chế độ xem này sẽ cập nhật sinh học, email, tên người dùng và số điện thoại của người dùng, cũng như cho phép chúng tôi cho phép xác thực đa yếu tố. Đầu tiên, chúng tôi sẽ cần thêm hai biểu mẫu trong người dùng/forms.py

# ... số tiền
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']
Tiếp theo, chúng ta có thể tạo một chế độ xem để sử dụng cả hai hình thức này. Chỉnh sửa người dùng/ViewS.Py và thêm vào chế độ xem.

# Thêm các nhập khẩu này
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)
Chúng tôi cũng cần một mẫu cho chế độ xem này.

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 %}
 
Bạn sẽ nhận thấy đây là một hình thức khá đơn giản, nhưng có một số JavaScript trong đó tự động đăng nội dung của biểu mẫu khi chúng được cập nhật. Điều này rất hữu ích để có, vì vậy bạn có thể thực hiện các chỉnh sửa mà không cần phải nhấn gửi mỗi lần. Tiếp theo, chúng tôi cần các URL đại diện cho tất cả các chế độ xem này trong các URL của người dùng. Chỉnh sửa người dùng/urls.py và thêm mã này:

# “Mã trước, nhập khẩu
from django.urls import path
from . import views

app_name='users'

urlpatterns = [
# Các mẫu URL mà chúng tôi đã nhập trước đó, thêm ba dòng tiếp theo
    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'),
]
Bây giờ là thời điểm tốt để kiểm tra dự án của chúng tôi. Nhưng trước tiên, chúng ta hãy chạy một bản sao lưu khác.

backup
Và chạy máy chủ. Trước khi chúng tôi triển khai đến một máy chủ Linux, bạn nên cho phép xác thực hai yếu tố trên tài khoản. Chúng tôi sẽ thực hiện việc này đến URL hồ sơ của chúng tôi,/người dùng/hồ sơ/, và kiểm tra hộp để cho phép xác thực sau khi nhập số điện thoại của chúng tôi, sau đó gửi biểu mẫu.

python manage.py runserver localhost:8000
Truy cập trang web bằng cách truy cập trình duyệt web của bạn, tôi đang sử dụng Google Chrome trong ví dụ này và nhập URL https: // localhost: 8000/tài khoản/hồ sơ/hồ sơ/ Bạn sẽ có thể đăng nhập nếu cần thiết và cho phép xác thực hai yếu tố. Dự án này cần một máy chủ để chạy để nó thực sự có thể gửi thư. Nhưng trước tiên, chúng ta cần một cách để xem lỗi. Bạn sẽ nhận thấy rằng nếu bạn chạy máy chủ ở chế độ gỡ lỗi, với Settings.debug bằng đúng, máy chủ sẽ tự động hiển thị lỗi. Để hiển thị lỗi mà không sử dụng chế độ gỡ lỗi, không an toàn trên máy chủ sản xuất, chúng ta nên thêm chế độ xem cho nó. Các lỗi quan trọng nhất mà chúng ta cần có thể xử lý là: Lỗi 500 - Một vấn đề với mã của chúng tôi Lỗi 404 - Một trang không được tìm thấy (URL bị hỏng) Lỗi 403 - Lỗi bị từ chối quyền Hãy thêm một ứng dụng mới để xử lý các lỗi này, được gọi là lỗi.

python manage.py startapp errors
Thêm điều này vào cài đặt.

handler404 = 'errors.views.handler404'
handler500 = 'errors.views.handler500'
handler403 = 'errors.views.handler403'
Đây là tất cả những gì chúng ta cần ngoài các chế độ xem lỗi, mẫu và một chút phần mềm trung gian. Hãy định nghĩa những điều đó như vậy:

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

# Tạo quan điểm của bạn ở đây.
@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.'})
Tiếp theo, hãy xác định phần mềm trung gian để xử lý các lỗi này. Chúng tôi sẽ làm điều này bằng cách trước tiên thêm vào Middleware_Classes trong Cài đặt.py, với tên của phần mềm trung gian của chúng tôi.

MIDDLEWARE_CLASSES = [
    # ... Phần mềm trung gian trước
    'errors.middleware.ExceptionVerboseMiddleware,
]
Tiếp theo, hãy thêm phần mềm trung gian.

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.')
Chúng tôi thêm một chức năng để có được ngoại lệ hiện tại bằng cách sử dụng cục bộ luồng, giúp chúng tôi theo dõi mọi lỗi trong mã của chúng tôi. Về mặt các mẫu, chúng tôi chỉ cần một, bởi vì chúng tôi xác định động tiêu đề trong chế độ xem. Mẫu chỉ cần hiển thị tiêu đề và dấu vết của chúng tôi, lỗi của chúng tôi theo dõi từ ngữ cảnh.

nano errors/templates/errors/error.html
 
{% extends 'base.html' %}
{% block content %}
<h1>{{ pagetitle }}</h1>
<p>{{ trace }}</p>
{% endblock %}
 
Đây là mẫu đơn giản nhất của chúng tôi, nhưng đó là cách dễ dàng để thấy các lỗi trong dự án của chúng tôi. Tiếp theo, chúng ta hãy vô hiệu hóa gỡ lỗi trong cài đặt.

nano app/settings.py
Tìm dòng này nơi nó được đặt thành đúng và thay đổi nó thành sai

DEBUG = False
Hãy tiếp tục và sao lưu ứng dụng ngay bây giờ. Chúng tôi đã sẵn sàng để triển khai đến một máy chủ Linux từ xa và tiếp tục thêm các tính năng từ đó.

sudo backup
Trước khi chúng tôi đăng mã này lên một máy chủ, chúng tôi nên xem xét rằng có thể có một số vấn đề với mã. Tùy thuộc vào trường hợp, các trang web chấp nhận thông tin được đăng cho họ sẽ có vấn đề với thư rác được đăng và khó khăn trong việc loại bỏ thư rác. Điều này không nên xảy ra ngay lập tức, nhưng nếu điều đó xảy ra, sau đó chúng tôi sẽ kiểm tra cách tự động kiểm duyệt thư rác trên trang web và khiến các robot truy cập trang web khó khăn hơn, cùng với cách hủy kích hoạt tài khoản người dùng và xác minh danh tính của người dùng quét ID của họ hoặc quét sinh trắc học, như dấu vân tay hoặc nhận dạng khuôn mặt. Nhìn vào ví dụ xác thực đa yếu tố mà chúng tôi đã kiểm tra, trong sản xuất, mọi thứ có thể khác nhau. Lưu ý cách chúng tôi đang giới hạn tỷ lệ đăng nhập và mã thông báo hết hạn. Nếu robot đang truy cập vào một trang web, xác thực hai yếu tố có thể khó khăn hơn vì chúng có thể nhập mã cùng lúc với người dùng. Để chống lại điều này, chúng ta hãy sử dụng một mô hình trong các mô hình người dùng, khai báo cách chúng ta tương tác với trang web khi chúng taxác thực bằng cách sử dụng xác thực đa yếu tố với số điện thoại. Chúng tôi cũng sẽ thêm một tùy chọn để xác thực với email. Bắt đầu bằng cách chỉnh sửa các mô hình người dùng với

nano users/models.py
Đây là những gì mô hình chúng tôi đang thêm nên trông như thế nào. Chúng tôi không cần bất kỳ phương pháp nào, chỉ là các biến để lưu trữ ID, người dùng, dấu thời gian, hết hạn, độ dài và các nỗ lực chống lại bất kỳ xác thực đa yếu tố nào (mã như 123456 được gửi đến điện thoại hoặc email).

# Một mã thông báo cơ bản được sử dụng để đăng nhập vào trang web
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)
Cũng hãy thêm một đặc quyền cho người dùng của chúng tôi và chúng tôi sẽ đặt nó theo cách thủ công ngay bây giờ, trước khi tự động di chuyển để nhập ngũ người dùng đặc quyền. Trong các mô hình người dùng, thêm dòng này vào hồ sơ:

    vendor = models.BooleanField(default=False)
Như với bất kỳ thay đổi nào đối với cơ sở dữ liệu, chúng tôi cần thực hiện di chuyển và di chuyển cơ sở dữ liệu bất cứ khi nào chúng tôi chỉnh sửa tệp model.py trong django. Hãy nhớ rằng, để làm điều này, chúng tôi sử dụng nguồn trước (nếu nó chưa được sử dụng kể từ khi thiết bị đầu cuối được mở) và sau đó Python Management.py để thực hiện việc di chuyển và di chuyển.

cd project-directory-you-named # (nếu cần)
source venv/bin/activate
python manage.py makemigrations && python manage.py migrate
Hiện tại, bạn có thể nhập ngũ bất kỳ tài khoản nào bạn đã tạo làm nhà cung cấp bằng cách sử dụng shell.

python manage.py shell
from users.models import Profile
p = Profile.objects.get(user__username='Charlotte')
p.vendor = True
p.save()
exit()
Bây giờ, chúng ta hãy phát triển chế độ xem xác thực đa yếu tố của chúng ta để sử dụng mã thông báo này. Đầu tiên, chúng tôi cần sửa đổi các tiện ích trợ giúp MFA của chúng tôi. Sử dụng nano,

nano users/mfa.py

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

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

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

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

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

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

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

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

# Xác thực người dùng bằng email hoặc số điện thoại của họ
def mfa(request, username, usertoken):
    token = MFAToken.objects.filter(uid=username, expires__gt=timezone.now() + datetime.timedelta(seconds=30)).order_by('-timestamp').last() # Lọc mã thông báo theo giá trị được truyền trong URL (một 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)) # Nếu phiên này chưa được tạo, hãy tạo nó
    user = User.objects.filter(id=token.user.id).first() # Lấy người dùng từ mã thông báo
    if not user and request.user.is_authenticated: return redirect(reverse('feed:home')) # Nếu chúng đã được xác thực, hãy đăng nhập chúng
    if not user: raise PermissionDenied() # Từ chối nếu không có người dùng nào được tìm thấy
    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): # Kiểm tra mã thông báo auth
        auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Đăng nhập người dùng nếu họ chưa đăng nhập
        user.profile.mfa_expires = timezone.now() + datetime.timedelta(minutes=settings.LOGIN_VALID_MINUTES) # Đặt thời gian hết hạn đối với xác thực đa yếu tố của họ
        user.profile.save()
        return HttpResponseRedirect(next if next != '' else reverse('landing:landing')) # Chuyển hướng người dùng sang trang tiếp theo
    if not user.profile.mfa_enabled: # Kiểm tra xem MFA có được bật không
        if not check_verification_time(user, token): # Kiểm tra thời gian
            user.profile.mfa_enabled = False # Xóa số điện thoại
            user.profile.enable_two_factor_authentication = True # Bật MFA
            user.profile.phone_number = '+1' # Tắt số điện thoại
            user.profile.save() # Lưu hồ sơ
            auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Đăng nhập người dùng nếu MFA của họ không được bật
            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): # Nếu yêu cầu là một yêu cầu bài đăng
        form = TfaForm(request.POST) # Khởi tạo biểu mẫu
        code = str(form.data.get('code', None)) # Nhận mã
        if code and code != '' and code != None: # Hãy chắc chắn rằng nó không trống
            token_validated = user.profile.check_auth_token(usertoken) # Kiểm tra mã thông báo auth
            p = user.profile
            is_verified = check_verification_code(user, token, code) # Kiểm tra mã
            p.mfa_authenticated = is_verified
            if token_validated: # Nếu tất cả mọi thứ
                if is_verified: # Là theo thứ tự
                    user.profile.mfa_enabled = True # Bật MFA (nếu chưa được bật)
                    user.profile.save()
                    auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Đăng nhập người dùng
                    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(): # Xây dựng Truy vấnString cho tham số tiếp theo (nếu có)
                        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) # Chuyển hướng
                    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: # Nếu mã thông báo không hợp lệ
                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: # Nếu có quá nhiều nỗ lực
                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): # Gửi email (hoặc văn bản)
                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('/'))
    # Kết xuất biểu mẫu (để nhận yêu cầu)
    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'})
Khi chúng tôi đang thêm vào mã này, hãy đảm bảo nhập chức năng để gửi email. Ở đầu tệp, người dùng xem (với các lần nhập khác), thêm

from .mfa import send_verification_email as send_mfa_verification_email
Bây giờ, chúng ta cần viết chức năng đó trước khi bất kỳ điều này sẽ hoạt động. Nó sẽ mở rộng chức năng gửi email của chúng tôi và chỉ cần gửi email cho người dùng với mã xác minh.

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))
Vì vậy, tất cả điều này hoạt động rất tốt, bây giờ chúng tôi có một hệ thống xác thực đa yếu tố phụ thuộc vào số điện thoại hoặc email để đăng nhập. Nhưng chúng tôi cũng cần một cách để xóa, hoặc ít nhất là ẩn người dùng không hợp tác với các điều khoản của chúng tôi. Đây có thể là những kẻ gửi thư rác, robot hoặc bất cứ ai không có ý nghĩa tốt cho công việc của chúng tôi. Hãy xem chế độ xem tôi có để theo dõi người dùng trên trang web của mình:

# số tiền
from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import user_passes_test
from .tests import is_superuser_or_vendor # Chúng ta sẽ cần tạo bài kiểm tra này

@login_required
@user_passes_test(is_superuser_or_vendor)
def users(request):
    # Nhận danh sách người dùng
    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', { # Trả về người dùng trong một mẫu
        'title': 'All Accounts',
        'users': User.objects.all(),
        'new_today': new_today,
        'new_this_month': new_this_month,
        'subscribers': subscribers
    })
Lưu ý rằng mã này sử dụng thử nghiệm, chúng tôi sẽ cần khai báo thử nghiệm này trong tệp tests.py và nhập nó. Chỉnh sửa người dùng/tests.py, hãy tạo bài kiểm tra.

def is_superuser_or_vendor(user):
    return user.profile.vendor or user.is_superuser
Điều này kết hợp với mẫu người dùng/người dùng.html, trông giống như thế này:
 
{% 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 %}
 
Lưu ý rằng mẫu bao gồm một mẫu khác, người dùng/_user.html. Khi sử dụng một mẫu có bảng con và không sử dụng mở rộng, nên thêm một dấu gạch dưới (_) trước tên của tệp để mở rộng, để phân biệt các mẫu. Lưu ý rằng đây là rất nhiều Jinja, bạn có thể không có tất cả các biến này được xác định. Nhưng đây là những gì mã của tôi trông như thế nào.
 
{% 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>
 
Chúng tôi cũng cần một Subtemplate khác, Toggle_Active.html. Mẫu này phải là một biểu mẫu cho phép chúng tôi chuyển đổi xem người dùng có hoạt động hay không.
 
<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>
 
Chúng tôi cũng sẽ cần thêm chế độ xem để chuyển đổi hoạt động của người dùng và các mẫu URL thích hợp. Mặc dù chúng tôi đang ở đó, hãy thêm chế độ xem để xóa người dùng trong trường hợp chúng tôi cần điều đó.

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


# Số tiền
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.views.generic import DeleteView

class UserDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    model = User
    success_url = '/' # Chuyển hướng về URL thành công
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        return context

    def test_func(self): # Kiểm tra xem người dùng là Superuser và có quyền xóa
        user = self.get_object()
        if self.request.user != user and self.request.user.is_superuser:
            return True
        return False
Mặc dù điều này là thực tế khi cần thiết, việc xóa người dùng không cần thiết hầu hết thời gian, chúng tôi chỉ có thể chuyển đổi khả năng hiển thị của người dùng truy cập trang web nếu chúng tôi cần loại bỏ chúng. Các mẫu URL chúng tôi đã thêm trông như thế này. Với Nano, chỉnh sửa người dùng/urls.py và thêm các dòng sau:

nano users/urls.py
Các dòng sẽ nằm trong danh sách các đường dẫn trong chế độ xem người dùng, trước khi kết thúc]], nhưng sau khi bắt đầu [[.

# …
    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'),
# …
Bây giờ, hãy đảm bảo sao lưu trang web để bạn có thể tải xuống trên máy chủ web, chúng tôi sẽ tiếp tục làm việc. Từ dòng lệnh,

sudo backup
Bây giờ trang web của chúng tôi được sao lưu. Vì vậy, bây giờ chúng tôi có một vài tính năng hữu ích hơn. Nhưng những gì về bức tranh lớn ở đây? Mã này vẫn không thể truy cập được từ Internet, chúng tôi chưa có máy chủ thư nào và chúng tôi cần mở rộng ứng dụng của mình để bao gồm quy trình xác minh toàn diện cũng như bố cục trơn tru để giúp chúng tôi khám phá trang web, cùng với các giao thức an toàn để xác thực người dùng đặc quyền xác thực . Chúng tôi sẽ nhận được tất cả điều này. Điều quan trọng nhất bây giờ sẽ chỉ là nhận mã này trực tuyến, điều mà chúng ta có thể làm chỉ với một vài dòng bash trên máy chủ Ubuntu. Mặc dù vậy, bạn sẽ cần thuê một máy chủ cho việc này, trừ khi bạn có một máy chủ ở nhà và đăng ký Internet doanh nghiệp cho phép bạn mở các cổng. Cá nhân tôi chạy trang web của mình trên HP Z440 được cài đặt trong căn hộ của tôi, nhưng thường rẻ hơn nhiều cho các nhu cầu cơ bản để thuê máy chủ riêng ảo (VPS). Hãy nhớ rằng mã chúng ta đang chạy bây giờ tương đối mỏng, nó sẽ cần phải được duy trì và cải thiện trước khi chúng taSẵn sàng để sử dụng những gì chúng ta phải xây dựng một sản phẩm. Đảm bảo cẩn thận những gì bạn làm với Internet, hãy chắc chắn nếu bạn triển khai công khai trang web này lên web trên máy chủ Linux, bạn có kế hoạch chặn các tương tác không mong muốn với trang web của bạn. Điều này có thể sẽ không phải là một vấn đề lúc đầu, nhưng chúng tôi sẽ xem xét một loạt các giải pháp để chống lại điều này, bao gồm học máy, trí tuệ nhân tạo và tầm nhìn máy tính. Khi nó trở thành một vấn đề, hãy nhìn xa hơn trong văn bản này cho một giải pháp. Về việc thuê VPS, có rất nhiều nơi bạn có thể đến. Google Cloud có các máy chủ VPS, IonO, Kamatera, Amazon AWS và nhiều nhà cung cấp cung cấp các giải pháp máy chủ đám mây phù hợp với nhu cầu của chúng tôi. Bạn sẽ cần nhấp qua biểu mẫu của họ và chọn một kế hoạch để bắt đầu. Bạn có thể đi với một gói cơ bản với bất kỳ nhà cung cấp nào, nhưng đảm bảo nhà cung cấp cho phép bạn mở các cổng máy chủ cổng để gửi email (đây phải là cổng 587 và cổng 25), một số nhà cung cấp chặn các cổng này. Cho đến nay tôi đã cóKinh nghiệm EST với Ionos và Kamatera, cả hai sẽ cho phép tôi gửi email không giới hạn và giá của chúng khá rẻ. Bạn sẽ kết nối với máy chủ mới của mình qua một giao thức có tên SSH hoặc Secure Shell, cho phép bạn giao diện từ xa với máy chủ giống hệt máy tính cá nhân của bạn, từ máy tính cá nhân của bạn. Khi bạn thiết lập máy chủ, nhà cung cấp lưu trữ có thể sẽ yêu cầu bạn thêm khóa SSH hoặc họ sẽ cung cấp cho bạn tên người dùng và mật khẩu. Phím SSH là cách bạn sẽ đăng nhập vào máy chủ từ dòng lệnh để chỉnh sửa mã. Sử dụng các tùy chọn ssh-keygen dưới đây để tạo SSH

ssh-keygen
Lưu tệp và ghi đè lên nó nếu bạn cần, thật tốt khi xoay các khóa SSH của bạn nếu bạn chưa có. Bây giờ, bạn có thể sử dụng lệnh sau để xem khóa SSH của bạn. Bạn sẽ muốn sao chép nó vào máy chủ từ xa của bạn để bạn có thể sử dụng nó để xác thực.

cat ~/.ssh/id_rsa.pub
Nếu bạn không thể nhìn thấy khóa SSH khi nhập lệnh đó (một chuỗi dài các chữ số và chữ cái bắt đầu bằng .) Mã sau sẽ tạo khóa RSA SSH 4096 bit.

ssh-keygen -t rsa -b 4096
Tạo một VPS chạy Ubuntu, tuy nhiên bạn có kế hoạch làm điều này. Khi bạn đã tạo một VPS bằng cách nhấp qua các biểu mẫu trên trang web của nhà cung cấp (kamatera.com, ionos.com hoặc tương tự), bạn sẽ muốn đăng nhập. Để thực hiện việc này, hãy sử dụng lệnh SSH với địa chỉ IP của bạn (địa chỉ địa chỉ của bạn trông giống như xx.xx.xx.xx). Bạn cũng sẽ cần phải nhạy cảm với tên người dùng mặc định trên máy chủ mà chúng tôi đã tạo, ví dụ, Ubuntu.

ssh ubuntu@XX.XX.XX.XX
Bạn có thể được yêu cầu mật khẩu, nếu bạn được yêu cầu mật khẩu, hãy nhập nó. Chúng tôi sẽ không sử dụng tên người dùng mặc định, vì vậy hãy bắt đầu bằng cách tạo người dùng mới và thêm khóa SSH vào tài khoản của họ. Hãy bắt đầu bằng cách thêm tệp SSHD_CONFIG mới, cho máy chủ cho máy chủ sử dụng SSH.

nano sshd_config

# Đây là tệp cấu hình toàn hệ thống máy chủ SSHD.  Nhìn thấy
# SSHD_CONFIG (5) để biết thêm thông tin.

# SSHD này được biên dịch với Path =/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/game

# Chiến lược được sử dụng cho các tùy chọn trong SSHD_CONFIG mặc định được vận chuyển với
# OpenSsh là để chỉ định các tùy chọn với giá trị mặc định của chúng trong đó
# Có thể, nhưng để lại cho họ nhận xét.  Tùy chọn chưa được ghi đè
# Giá trị mặc định.

# Cổng 22
# Địa chỉ của gia đình bất kỳ
# Danh sách địa chỉ 0,0.0.0
# Nghe adress ::

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

# Mật mã và khóa
# Rekeylimit mặc định Không có

# Đăng nhập
# Syslogfacility auth
# Thông tin loglevel

# Xác thực:

# Logracetime 2m
# Permitrootlogin Cấm-Password
# StrictModes Có
# MaxAuthtries 6
# Maxessions 10

PubkeyAuthentication yes

# Dự kiến.
AuthorizedKeysFile	.ssh/authorized_keys .ssh/authorized_keys2

# Ủy quyềnPrincipalsfile Không có

# Ủy quyềnKeysCommand Không có
# Ủy quyềnKeysCommanduser không ai

# Để hoạt động này, bạn cũng sẽ cần các khóa máy chủ trong/etc/ssh/ssh_known_hosts
# HostBasingAuthentication không
# Thay đổi thành có nếu bạn không tin tưởng ~/.ssh/đã biết_hosts cho
# HostBasingAuthentication
# OnvoreUserknownHosts không
# Không đọc tệp ~/.rhosts và ~ .Shosts của người dùng
# Ignorerhosts Có

# Để vô hiệu hóa mật khẩu văn bản rõ ràng, thay đổi thành không ở đây!
PasswordAuthentication no
# PermitemptyPasswords không

# Thay đổi thành có để bật mật khẩu phản hồi thử thách (hãy cẩn thận với các vấn đề với
# Một số mô -đun và chủ đề PAM)
KbdInteractiveAuthentication no

# Tùy chọn Kerberos
# Kerberosauthentication số
# Kerberosorlocalpasswd Có
# Kerberosticketcleanup Có
# Thanh Kerberscotted số

# Tùy chọn GSSAPI
# Gssapiauthentication số
# Gssapicleanupcredentials Có
# Gssapistrictacceptorcheck Có
# GssapikeyExchange số

# Đặt cái này thành 'Có' để cho phép xác thực PAM, xử lý tài khoản,
# và xử lý phiên. Nếu điều này được bật, xác thực PAM sẽ
# được phép thông qua KBDinterActiveAuthentication và
# Mật khẩu điều kiện.  Tùy thuộc vào cấu hình PAM của bạn,
# Xác thực PAM thông qua KBDinteractiveAuthentication có thể bỏ qua
# Cài đặt của "permitrootlogin không có thông tin".
# Nếu bạn chỉ muốn tài khoản PAM và kiểm tra phiên chạy mà không cần
# Xác thực PAM, sau đó kích hoạt điều này nhưng đặt mật khẩu
# và KBDinterActiveAuthentication thành 'Không'.
UsePAM yes

# Cho phép có
# Cho phép
# Gatewayports không
X11Forwarding yes
# X11Displayoffset 10
# X11uselocalhost Có
# Permittty Có
PrintMotd no
# Printlastlog Có
# TCPKeepialive Có
# Permittuenvironment trong
# Nén bị trì hoãn
# Khoảng thời gian khách hàng 0
# ClientAlIVECOUNTMAX 3
# Đã sử dụng trong
# Pidfile /run/sshd.pid
# Maxstartups 10: 30: 100
# Pemittunl không
# Chrootdirectory Không có
# Phụ lục phiên bản Không

# Không có đường dẫn biểu ngữ mặc định
Banner /etc/banner

# Cho phép khách hàng vượt qua các biến số cục bộ
AcceptEnv LANG LC_*

# ghi đè mặc định không có hệ thống con
Subsystem	sftp	/usr/lib/openssh/sftp-server

# Ví dụ về các cài đặt ghi đè trên cơ sở mỗi người dùng
# Khớp với người dùng anoncvs
# X11forwarding không
# Cho phép không có
# Cho phép trong
# Máy chủ CVS ForceCommand
PermitRootLogin no
Hãy nhớ rằng, Ctrl+X và Y để lưu tệp. Tiếp theo, hãy viết một tập lệnh cơ bản có tên là Khởi tạo (tất cả trong thư mục nhà mặc định của người dùng của chúng tôi).

nano initialize
Thêm các dòng này vào tệp, thay thếVới khóa SSH của bạn, bạn tìm thấy bằng 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
Để hướng dẫn bạn qua tệp này, hãy bắt đầu từng dòng. Dòng đầu tiên nói với trình biên dịch rằng đây là một tập lệnh bash. Sau đó, chúng tôi đang cài đặt các phụ thuộc, sao chép SSHD_CONFIG vào thư mục chính xác, khởi động lại SSH, tạo các phím SSH cho root, thêm 'nhóm người dùng' (bạn có thể chọn tên bạn muốn cho lệnh này, sử dụng lệnh adduser với tên và mật khẩu vô hiệu hóa của họ cho Hiện nay). Chúng tôi cũng thêm nhóm vào nhóm sudo, tạo khóa SSH của họ, thêm khóa của chúng tôi vào các khóa ủy quyền và của họ và in khóa của họ. Người dùng mới này sẽ là cách chúng tôi đăng nhập vào trang web. Trong một thiết bị đầu cuối mới, hãy tiếp tục và mở máy chủ một lần nữa.

ssh team@XX.XX.XX.XX
Bạn không cần mật khẩu lần này, như bạn có khóa SSH. Chúng tôi cũng đã vô hiệu hóa đăng nhập bằng mật khẩu để giữ cho trang web an toàn hơn. Bây giờ, máy chủ này khởi động hoàn toàn trống mà không có thông tin về nó. Hãy bắt đầu bằng cách nhân bản dự án của chúng tôi từ Git để chúng tôi có thể tải xuống và chạy nó trên máy từ xa. Trên máy chủ từ xa được kết nối qua SSH, trước tiên hãy in phím SSH của bạn:

cat ~/.ssh/id_rsa.pub
Tiếp theo, dán khóa này vào cài đặt Git như chúng tôi đã làm trước đây để thiết lập kho lưu trữ Git của chúng tôi. Bây giờ chúng tôi có thể sao chép dự án của chúng tôi trực tiếp đến máy chủ. Hãy chắc chắn rằng bạn đã sao lưu dự án cục bộ trước tiên để tải xuống máy chủ Git.

git clone git://github.com/you/yourproject.git
Hoàn hảo. Bây giờ tất cả các tập tin đều ở đây. Chúng ta có thể nhìn thấy chúng với LS

ls
Bây giờ, hãy bắt đầu thiết lập máy chủ. Đầu tiên, sao chép thư mục dự án của bạn vào một cái tên đơn giản, đáng nhớ mà chúng tôi sẽ sử dụng cho dự án.

cp -r yourproject whatyoucalledit
Trong đó, Whatyoucalledit là tên mới của dự án của bạn. Tiếp theo, chúng ta sẽ cần xây dựng một tiện ích cơ bản để thiết lập máy chủ. Chúng tôi sẽ lưu tiện ích này và sử dụng nó trong tương lai. Để xây dựng tiện ích này, hãy tạo nhị phân người dùng để xác định cách chúng tôi chỉnh sửa tập lệnh. Sử dụng bash, chỉnh sửa/usr/bin/ascript

sudo nano /usr/bin/ascript
Hãy chắc chắn sử dụng sudo ở đó để bạn có quyền để chỉnh sửa tệp. Trong tệp, thêm các dòng sau:

# !
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
Hãy nhớ rằng tập lệnh này lấy một đối số, tên tập lệnh, là $ 1. Nó kiểm tra xem tệp có tồn tại hay không, hãy thêm nó, thêm dòng đầu tiên để khai báo tập lệnh là bash, thay đổi quyền của nó, chỉnh sửa nó và thêm tên của nó vào /etc /ascripts cho phép chúng tôi lưu trữ tên của các tập lệnh mà chúng tôi đang tạo ra. Nếu tệp đã tồn tại, chỉ cần thay đổi quyền và chỉnh sửa nó. Lưu tệp và tiếp theo chúng tôi sẽ thay đổi quyền của nó. Miễn là chúng tôi sử dụng tập lệnh này, chúng tôi sẽ không phải làm điều đó một lần nữa.

sudo chmod a+x /usr/bin/ascript
Hoàn hảo. Bây giờ chúng ta hãy tạo một tập lệnh gọi là thiết lập. Đầu tiên, không áp đảo bạn, nhưng hãy xem tập lệnh thiết lập của tôi trông như thế nào. Chúng tôi sẽ đi qua kịch bản này sẽ trông như thế nào trong dự án của bạn, bạn sẽ không cần mọi thứ trong kịch bản của tôi để bắt đầu.

# !/Bin/bash
SECONDS=0
PYTHON_VERSION=3.12
echo "femmebabe installer initialized."
# sudo chmod a+x script/usersetup
# ./scripts/usersetup
# SSH-Keyen
# Thư mục dự án
DIR="/home/team/femmebabe"
USER="team"
# Các lệnh nhật ký
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
# Cấu hình nano
echo "set tabsize 4" >> .nanorc
echo "set tabstospaces" >> .nanorc
# Cấu hình git
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
# Cập nhật và cài đặt
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
# Bật thuốc chống vi -rút Clamav
echo "Starting antivirus"
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Đặt tên máy chủ
echo "127.0.0.1 femmebabe" | sudo tee -a /etc/hosts
sudo hostnamectl set-hostname localhost
# Thiết lập 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;"
# Thiết lập cơ sở dữ liệu sao lưu
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 bị vô hiệu hóa
echo "Configuring firewall"
sudo iptables -P INPUT ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -F
sudo iptables-save
# Cài đặt 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
# Thiết lập 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
# Tạo 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
# Thiết lập Virtuealenv
cd $DIR
echo "Creating virtual environment"
python -m venv venv
source venv/bin/activate
# Nhận và xây dựng các phụ thuộc
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
# Đặt quy tắc tường lửa
cd $DIR
# Cài đặt phụ thuộc 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 Cài đặt OpenCV-Python == 4.5.5.64
# PIP Cài đặt 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
# Cài đặt 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
# Chạy certbot
sudo certbot --apache --non-interactive --agree-tos --domains femmebabe.com --email jasper.camber.holton@gmail.com
# Tải lại máy chủ thư
sudo systemctl restart opendkim postfix dovecot
# Sao chép Certs
# sudo cp /etc/letsencrypt/live/femmebabe.com/privkey.pem privateKey.pem
# sudo cp /etc/lettesencrypt/live/femmebabe.com/cert.pem cert.pem
# Bản vá
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"
# Đặt cài đặt người dùng
sudo gpasswd -a www-data users
# Đặt quyền
echo "Setting permissions"
sudo chown -R team:users cache/
sudo chmod a+rwx -R cache/
# Sudo Chown -r Team: người dùng/var/chạy/
# 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: người dùng 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
# Sao chép cấu hình và đặt quyền
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
# Thiết lập cơ sở dữ liệu
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"
# Tiêm cấu hình PAM và xóa cấu hình SSH bị lỗi
# sudo sed -i '' -e '$ d' /tc/pam.d/sshd
# Sudo sed -i '' -and $ d ' /etc /hồ sơ
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
# Sao chép các tập lệnh bin và đặt quyền
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
# Tải lại và bật dịch vụ
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
# Bật các mô -đun 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
# Vô hiệu hóa trang web mặc định
sudo a2dissite 000-default
sudo a2dissite 000-default-le-ssl
# Bật cho trang web
sudo a2ensite femmebabe-le-ssl
# Tải lại daemon và khởi động lại Apache, Postfix và OpenDKim
sudo systemctl daemon-reload
sudo systemctl restart apache2
sudo systemctl restart opendkim postfix
sudo systemctl start daphne
# Đặt quyền
sudo chown -R :www-data /var/www/
sudo chown -R :www-data /var/www/.deepface
# Cấu hình hoán đổi
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
# Động cơ chú thích
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
# Thiết lập 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
# Hiển thị IPv6 và OpendKim cho cấu hình miền
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}'
# Thiết lập hoàn thành
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."
Đó là rất nhiều thiết lập! Tóm lại, mã này ghi các lệnh, định cấu hình nano và git, sao chép các tệp, tải xuống và cài đặt các gói Ubuntu APT, phụ thuộc Python, định cấu hình Postfix, cấu hình PostgreSQL (máy chủ cơ sở dữ liệu) và tải cơ sở dữ liệu, cấu hình Vô hiệu hóa Iptables, tải xuống một chất chống vi -rút, tạo thư mục, phụ thuộc bản sao, cài đặt chứng chỉ và thiết lập máy chủ, cài đặt cấu hình, khởi động và cho phép SEV, phân bổ, đặt quyền, và in khóa IP, IPv6 và khóa OpenDKIM. Khá đơn giản, nhưng nó trông giống như rất nhiều mã. Chúng tôi sẽ không cần nhiều điều này vì chúng tôi không có sự phụ thuộc, chúng tôi không sử dụng cần tây, Celerybeat hoặc Daphne, nhưng dù sao chúng tôi cũng sẽ cài đặt một số trong số chúng để bắt đầu. Lưu ý rằng mã này có một miền được khai báo nhiều lần. Chúng tôi cũng sẽ cần mua một tên miền (đó là một khoản phí nhỏ hàng năm). Tôi đề nghị Squarespace để mua một tên miền, bố cục của họ làtrực quan và dễ sử dụng. Bạn có thể mua bất kỳ miền nào bạn chọn, nhưng tôi đang sử dụng tên miền femmebabe.com trong ví dụ này. Khi bạn đã mua một tên miền, hãy đến bảng cấu hình Squarespace DNS và thêm bản ghi A trỏ miền của bạn vào máy chủ theo địa chỉ IP. Nó sẽ trông như thế này: @ A xx.xx.xx.xx Với toán tử @ là máy chủ, có nghĩa là tất cả các tên miền phụ thuộc miền này và miền gốc đều sẽ chuyển hướng đến máy chủ. Có nhiều hồ sơ hơn để khai báo, nhưng chúng tôi có thể chuyển sang những hồ sơ này một khi chúng tôi đã sẵn sàng gửi thư. Hãy nhớ rằng, có thể mất vài ngày trước khi bạn có thể gửi thư thành công từ máy chủ. Các bản ghi DNS mà chúng tôi đang thiết lập sẽ mất thời gian để tuyên truyền. Dù sao, hồ sơ duy nhất chúng ta cần bắt đầu là một kỷ lục. Vì vậy, bây giờ chúng tôi có thể điền vào tập lệnh dưới đây theo dự án của chúng tôi và chạy nó. Hãy bắt đầu với một tập lệnh thiết lập nhỏ hơn để chỉ cài đặt những gì chúng ta cần cho một tiến trình cơ bản. Chúng tôi sẽ không sử dụng nhiều phụ thuộc hoặc postgreql, chúng tôi sẽ chỉLên một máy chủ HTTP cơ bản và lo lắng về việc chứng nhận nó khi hoàn thành. Hãy nhớ rằng, để có được chứng chỉ HTTPS và chạy máy chủ một cách an toàn, chúng ta sẽ cần mua một tên miền cùng với thuê máy chủ. Hiện tại, hãy thay thế nhóm nhóm của nhóm trong tập tin này bằng tên của người dùng của bạn, trực tiếp với thư mục dự án của bạn và cung cấp email và tên miền của bạn trong các thẻ <>. Ngoài ra, trước khi chúng tôi chạy mã này, chúng tôi cần thay đổi cài đặt thành tường lửa mà nhà cung cấp lưu trữ hỗ trợ, nếu có. Thông thường đây là trong tab 'Mạng' của nhà cung cấp dịch vụ lưu trữ của bạn hoặc nếu bạn tự lưu trữ, nó trong phần 'Chuyển tiếp cổng' trong bộ định tuyến của bạn. Bạn cũng sẽ muốn thiết lập IP tĩnh thông qua bộ định tuyến của bạn với địa chỉ máy chủ của bạn, nếu bạn đang sử dụng tự lưu trữ. Bạn sẽ cần mở các cổng sau để truy cập đọc/ghi. 22 (SSH) 25 (Thư) 587 (thư) 110 (ứng dụng thư) 80 (http) 443

# !
SECONDS=0
PYTHON_VERSION=3.12
echo "femmebabe installer initialized."
DIR="/home/team/<yourproject>"
USER="team"
# Các lệnh nhật ký
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
# Cấu hình nano
echo "set tabsize 4" >> .nanorc
echo "set tabstospaces" >> .nanorc
# Cấu hình git
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
# Cập nhật và cài đặt
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
# Bật thuốc chống vi -rút Clamav
echo "Starting antivirus"
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Đặt tên máy chủ
echo "127.0.0.1 femmebabe" | sudo tee -a /etc/hosts
sudo hostnamectl set-hostname femmebabe
# Thiết lập cơ sở dữ liệu sao lưu
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
# Vô hiệu hóa iptables
echo "Configuring firewall"
sudo iptables -P INPUT ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -F
sudo iptables-save
# Thiết lập Virtuealenv
cd $DIR
echo "Creating virtual environment"
python -m venv venv
source venv/bin/activate
pip3 install -r requirements.txt
# Cài đặt 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
# Chạy certbot
sudo certbot --apache --non-interactive --agree-tos --domains femmebabe.com --email <youremail>@gmail.com
# Đặt cài đặt người dùng
sudo gpasswd -a www-data users
# Đặt quyền
echo "Setting permissions"
sudo chown -R team:users cache/
sudo chmod a+rwx -R cache/
# Sudo Chown -r Team: người dùng/var/chạy/
# 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 ./
# Tải lại và bật dịch vụ
echo "Enabling services"
sudo systemctl daemon-reload
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Bật các mô -đun 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
# Tải lại daemon và khởi động lại Apache, Postfix và OpenDKim
sudo systemctl daemon-reload
sudo systemctl restart apache2
sudo systemctl restart opendkim postfix
# Hiển thị IPv6 và OpendKim cho cấu hình miền
echo "COPY the below information to domain configuration."
hostname -I
ip a | grep inet
ip -6 addr | grep "scope link"
Trước khi chạy mã này, hãy đảm bảo tên miền bạn đã mua được kết nối với máy chủ. Để thực hiện việc này, hãy mở một thiết bị đầu cuối trên máy cục bộ của bạn và chạy lệnh này bằng miền của bạn:

ping femmebabe.com # Chèn miền của bạn ở đây, sau khi ping
Nếu tất cả đều có vẻ tốt và máy chủ đang gửi phản hồi, chúng tôi đã sẵn sàng để chạy tập lệnh và cài đặt các gói cũng như khởi động, bật và chứng nhận máy chủ Apache của chúng tôi. Đây không phải là tất cả các thiết lập cần thiết để định cấu hình Postfix, chúng tôi sẽ xem xét thiết lập đó hơn sau. Hiện tại, hãy chạy mã thiết lập này và sẽ mất vài phút để cài đặt và chứng nhận máy chủ của bạn. Một lần nữa, hãy đảm bảo thay thế tên, email và tên miền trong tập lệnh theo tên bạn đã mua. Bây giờ máy chủ được cung cấp, bạn có thể truy cập URL trong bất kỳ trình duyệt web nào và kiểm tra để đảm bảo máy chủ đang chạy HTTPS. Nếu không, hãy thử chờ một chút để các bản ghi DNS bắt kịp và sau đó chạy lệnh sau để thử lại chứng nhận certbot:

sudo certbot --apache --non-interactive --agree-tos --domains <domain>.com --email <youremail>@gmail.com
Miễn là bạn đã cấu hình chính xác mọi thứ, bạn sẽ có thể truy cập trang mặc định của Apache chỉ để biết mã của bạn đang hoạt động và hiển thị trang web trực tiếp. Tiếp theo, chúng ta hãy chỉnh sửa cài đặt.py để thay đổi chế độ gỡ lỗi mặc định của chúng tôi thành sản xuất. Chúng tôi cũng sẽ định cấu hình miền trong cài đặt, cũng như IP nội bộ.

nano yourproject/settings.py
Trong cài đặt, thay đổi/thêm các dòng này.

DEBUG = False

# Cấu hình trang web
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',
]
Bây giờ, chúng ta sẽ cần cấu hình Apache2. Hãy chỉnh sửa tệp cấu hình mà chúng tôi sẽ triển khai với dòng này:

sudo nano /etc/apache2/sites-available/femmebabe-le-ssl.conf
Tệp cấu hình này sẽ có tên miền của chúng tôi trong đó và tên của người dùng và dự án. Tôi đang sử dụng tên miền femmebabe.com, nhóm người dùng và tên dự án 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>
Đảm bảo thay thế tên của dự án, thư mục và tên miền trong mã ví dụ này khi định cấu hình máy chủ của bạn. Bây giờ, chúng tôi sẽ cần vô hiệu hóa trang web mặc định. Điều này có thể được thực hiện bằng cách sử dụng bash.

sudo a2dissite 000-default-le-ssl
sudo a2dissite 000-default
sudo a2dissite default-ssl
Tiếp theo, chúng tôi có thể kích hoạt trang web mặc định và tải lại Apache2, cũng bằng cách sử dụng bash. Hãy nhớ thay thế Femmebabe bằng tên của tệp bạn đã khai báo khi chỉnh sửa trong/etc/apache2/sites-ALIRAD/.

sudo a2ensite femmebabe-le-ssl
sudo systemctl reload apache2
Quay trở lại miền của bạn trong thanh điều hướng. Bạn sẽ thấy trang web bạn được cấu hình trong trình duyệt web của bạn. Chúc mừng! Nếu bạn không nhìn thấy nó, bạn có thể cần thực hiện một số thay đổi. Xem xét cẩn thận các cài đặt trong dự án của bạn, cấu hình Apache và đảm bảo bạn không có bất kỳ lỗi nào và chạy các lệnh sau để kiểm tra dự án để biết lỗi.

cd projectname
source venv/bin/activate
python manage.py check
Nếu bạn có lỗi trong dự án Python của mình, hãy truy tìm chúng đến nơi chúng và sửa chúng. Bạn có thể không thấy tất cả các lỗi của mình tùy thuộc vào nơi chúng ở lỗi.

nano venv/lib/python3.12/site-packages/django/apps/registry.py
Cuộn đến dòng 83, trong đó lỗi thời gian chạy này được nêu ra (RAINE RUNTITINGERROR (Fop Population () không phải là reentrant,)) và thêm một bình luận trước dòng này, sau đó thêm, với cùng một thụt lề, self.app_configs = {}. Điều này trông như thế này:

            if self.loading:
                # Ngăn chặn các cuộc gọi reentrant để tránh chạy appconfig.read ()
                # Phương pháp hai lần.
# Tăng RunTimeError ("Fopulation () không phải là reentrant")
                self.app_configs = {}
            self.loading = True
Sau đó, bạn có thể kiểm tra lại dự án và phơi bày lỗi.

python manage.py check
Sau đó, bạn có thể thấy lỗi và sửa nó. Khi bạn đã sửa nó và mã biên dịch không có lỗi, hãy đảm bảo thay đổi lại tệp để có vẻ như thế này:

            if self.loading:
                # Ngăn chặn các cuộc gọi reentrant để tránh chạy appconfig.read ()
                # Phương pháp hai lần.
                raise RuntimeError("populate() isn't reentrant")
# self.app_configs = {}
            self.loading = True
Với điều kiện máy chủ trực tuyến, khi chúng tôi thực hiện bất kỳ thay đổi nào nữa, chúng tôi cần sử dụng lệnh sau để tải lại máy chủ:

sudo systemctl reload apache2
Tuyệt vời! Nhưng những gì về gửi thư? Để bắt đầu gửi email, trước tiên chúng tôi sẽ cần cập nhật cấu hình tên miền. Điều này sẽ nằm trong bảng điều khiển DNS của bạn trong Squarespace hoặc bất kỳ công ty đăng ký tên miền nào bạn đã chọn. Chúng tôi cũng sẽ cần cài đặt và thêm cấu hình và chạy một vài lệnh. Đầu tiên, chúng ta hãy lấy địa chỉ IPv6 của máy chủ. Sau đó, chúng tôi sẽ mở DNS của bạn và thêm các bản ghi. Để nhận địa chỉ IPv6 của máy chủ, hãy sử dụng lệnh này:

ip -6 addr
Bây giờ, chúng tôi có thể thêm các bản ghi sau vào cài đặt DNS. Hồ sơ của tôi trông như thế này. Tuy nhiên, đối với hồ sơ của bạn, bạn nên thay thế địa chỉ IP bằng IP của bạn (không phải 75.147.182.214, đó là của tôi). Ngoài ra, hãy thêm miền của bạn thay cho femmebabe.com, cũng như địa chỉ IPv6 của bạn được tìm thấy với lệnh trước đó (bạn không thể sử dụng của tôi, Fe80 :: 725a: FFF: FE49: 3E02). Đừng lo lắng về DomainKey bây giờ, điều này được tạo khi chúng tôi thiết lập Postfix, máy chủ thư, với OpenDkim và in khóa. Chúng tôi sẽ cấu hình cuối cùng này. @ MỘT 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 ~ Tất cả Mặc định._bimi TXT N/a v = bimi1; l = https: //femmebabe.com/media/static/femmebabe.svg _dmarc TXT N/a v = dmarc1; P = Không có sendonly._Domainkey TXT N/aBây giờ, chúng ta sẽ cần thêm một số cấu hình dai dẳng cho Postfix. Tất cả những gì chúng ta cần làm là đảm bảo chúng ta thay thế tên miền, femmebabe.com, với tên miền bạn đang sử dụng. Hãy xem xét tất cả các tệp cấu hình từng cái một và cài đặt chúng trong một thư mục gọi là config trong dự án của chúng tôi, để cài đặt vào HĐH.

nano config/etc_postfix_main.cf
Thêm văn bản này vào tệp

# Xem /usr/share/postfix/main.cf.dist cho một phiên bản nhận xét, đầy đủ hơn


# Debian cụ thể: Chỉ định tên tệp sẽ gây ra cái đầu tiên
# dòng của tập tin đó được sử dụng làm tên.  Mặc định Debian
# là /etc /mailname.
# Myorigin = /etc /mailname

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

# nối thêm .domain là công việc của MUA.
append_dot_mydomain = no

# Giải phóng dòng tiếp theo để tạo cảnh báo "thư bị trì hoãn"
# Delay_Warning_Time = 4H

readme_directory = no

# Xem http://www.postfix.org/compatilities_readme.html - mặc định là 3.6 trên
# Cài đặt mới.
compatibility_level = 3.6



# Tham số 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

# Cấu hình Milter
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
Cấu hình tiếp theo!

nano config/etc_postfix_master.cf
Thêm các dòng sau:

# 
# Tệp cấu hình quá trình chính của Postfix.  Để biết chi tiết về định dạng
# của tệp, xem trang thủ công (5) (lệnh: "người đàn ông 5 chính" hoặc
# On-line: http://www.postfix.org/master.5.html).
# 
# Đừng quên thực hiện "Postfix Reload" sau khi chỉnh sửa tệp này.
# 
# ================================================== ========================
# Loại dịch vụ Private Unrid Chroot WakeUp MaxProc Command + args
# (Có) (Có) (Không) (Không bao giờ) (100)
# ================================================== ========================
smtp      inet  n       -       y       -       -       smtpd
# SMTP Inet N - Y - 1 Postcreen
# SMTPD PASS - - Y - - SMTPD
# Dnsblog unix - - y - 0 dnsblog
# Tlsproxy unix - - y - 0 tlsproxy
# Chọn một: Chỉ cho phép gửi cho máy khách Loopback hoặc cho bất kỳ máy khách nào.
# 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/gửi
# -o smtpd_tls_security_level = mã hóa
# -o smtpd_sasl_auth_enable = Có
# -o smtpd_tls_auth_only = Có
# -O smtpd_reject_unlisted_recipient = không
# -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_authentated, từ chối
# -O milter_macro_daemon_name = nguồn gốc
# Chọn một: Chỉ bật SMTP cho máy khách LOOPBACK hoặc cho bất kỳ máy khách nào.
# 127.0.0.1:Smtps inet n - y - - smtpd
# Smtps inet n - y - - smtpd
# -O syslog_name = postfix/smtps
# -o smtpd_tls_wrappermode = Có
# -o smtpd_sasl_auth_enable = Có
# -o smtpd_reject_unlisted_recipient = không
# -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_authentated, từ chối
# -O milter_macro_daemon_name = nguồn gốc
# 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
# 
# ================================================== =================
# Giao diện với phần mềm không phải postfix. Hãy chắc chắn kiểm tra hướng dẫn sử dụng
# Các trang của phần mềm không phải bài để tìm hiểu những tùy chọn mà nó muốn.
# 
# Nhiều dịch vụ sau đây sử dụng giao hàng Postfix Pip (8)
# đại lý.  Xem trang phụ nữ (8) để biết thông tin về $ {người nhận}
# và các tùy chọn phong bì tin nhắn khác.
# ================================================== =================
# 
# Maildrop. Xem tệp postfix maildrop_readme để biết chi tiết.
# Cũng chỉ định trong main.cf: maildrop_destination_recipient_limit = 1
# 
maildrop  unix  -       n       n       -       -       pipe
  flags=DRXhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
# 
# ================================================== =================
# 
# Các phiên bản Cyrus gần đây có thể sử dụng mục nhập Master.cf "LMTP" hiện có.
# 
# Chỉ định trong cyrus.conf:
# LMTP CMD = "LMTPD -A" LUẬT = "LocalHost: LMTP" Proto = TCP4
# 
# Chỉ định trong main.cf một hoặc nhiều điều sau:
# mailbox_transport = lmtp: inet: localhost
# Virtual_transport = LMTP: Inet: LocalHost
# 
# ================================================== =================
# 
# Cyrus 2.1.5 (Amos Gouaux)
# Cũng chỉ định trong main.cf: cyrus_destination_recipient_limit = 1
# 
# Cyrus Unix - N N - - ống
# flags = drx user = cyrus arg =/cyrus/bin/deliver -e -r $ {sender} -m $ {extension} $ {user}
# 
# ================================================== =================
# Ví dụ cũ về giao hàng qua Cyrus.
# 
# Old -corus unix - n - - ống
# cờ = r user = cyrus argv =/cyrus/bin/deliver -e -e -m $ {Extension} $ {user}
# 
# ================================================== =================
# 
# Xem tệp Postfix UUCP_README để biết chi tiết cấu hình.
# 
uucp      unix  -       n       n       -       -       pipe
  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
# 
# Các phương pháp phân phối bên ngoài khác.
# 
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}
Và cấu hình opendkim. OpendKim xác định các máy chủ email có khóa miền để làm cho chúng an toàn hơn. Không có nó, thư không được ký và có thể không đến hộp thư đến.

nano config/etc_default_opendkim
Thêm các dòng sau:

# Lưu ý: Đây là một tệp cấu hình kế thừa. Nó không được sử dụng bởi opendkim
# Dịch vụ Systemd. Vui lòng sử dụng các tham số cấu hình tương ứng trong
# /etc/opendkim.conf thay thế.
# 
# Trước đây, người ta sẽ chỉnh sửa cài đặt mặc định ở đây, sau đó thực thi
# /lib/opendkim/opendkim.service.generate để tạo các tệp ghi đè systemd đến
# /etc/systemd/system/opendkim.service.d/override.conf và
# /etc/tmpfiles.d/opendkim.conf. Mặc dù điều này vẫn có thể, nhưng bây giờ nó là
# Được đề xuất để điều chỉnh các cài đặt trực tiếp trong /etc/opendkim.conf.
# 
# Daemon_opts = ""
# Thay đổi thành/var/spool/postfix/chạy/opendkim để sử dụng ổ cắm unix với
# Postfix trong một chroot:
# Vòng tròn =/var/spool/postfix/chạy/opendkim
RUNDIR=/run/opendkim
# 
# Unmomment để chỉ định một ổ cắm thay thế
# Lưu ý rằng cài đặt này sẽ ghi đè bất kỳ giá trị ổ cắm nào trong opendkim.conf
# mặc định:
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
# Nghe trên tất cả các giao diện trên cổng 54321:
# Ổ cắm = Inet: 54321
# Nghe trên Loopback trên cổng 12345:
# Ổ cắm = inet: 12345@localhost
# Nghe là 192.0.2.1 là cổng 12345:
# Ổ cắm = Inet: 12345@192.0.2.1
USER=opendkim
GROUP=opendkim
PIDFILE=$RUNDIR/$NAME.pid
EXTRAAFTER=

nano config/etc_dovecot_conf.d_10-master.conf
Thêm các dòng sau:

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

# Giới hạn VSZ (Kích thước bộ nhớ ảo) mặc định cho các quy trình dịch vụ. Điều này chủ yếu là
# dự định bắt và tiêu diệt các quá trình rò rỉ bộ nhớ trước khi chúng ăn hết
# mọi thứ.
# Default_vsz_limit = 256m

# Người dùng đăng nhập được sử dụng nội bộ bởi các quy trình đăng nhập. Đây là điều không đáng tin cậy nhất
# Người dùng trong hệ thống Dovecot. Nó không nên có quyền truy cập vào bất cứ điều gì cả.
# Default_login_user = Dovenull

# Người dùng nội bộ được sử dụng bởi các quy trình không có đặc quyền. Nó nên tách biệt với
# Người dùng đăng nhập, để các quy trình đăng nhập không thể làm phiền các quy trình khác.
# Default_Internal_user = Dovecot

service imap-login {
  inet_listener imap {
    # Cổng = 143
  }
  inet_listener imaps {
    # Cổng = 993
    # SSL = Có
  }

  # Số lượng kết nối để xử lý trước khi bắt đầu một quy trình mới. Tiêu biểu
  # Các giá trị hữu ích duy nhất là 0 (không giới hạn) hoặc 1. 1 an toàn hơn, nhưng 0
  # nhanh hơn. <doc/wiki/loginProcess.txt>
  # Service_Count = 1

  # Số lượng các quy trình để luôn luôn chờ đợi nhiều kết nối hơn.
  # Process_min_avail = 0

  # Nếu bạn đặt dịch vụ_count = 0, có lẽ bạn cần phát triển cái này.
  # Vsz_limi = $ default_vsz_limit
}

service pop3-login {
  inet_listener pop3 {
    # Cổng = 110
  }
  inet_listener pop3s {
    # Cổng = 995
    # SSL = Có
  }
}

service submission-login {
  inet_listener submission {
    # Cổng = 587
  }
}

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

  # Chỉ tạo người nghe Inet nếu bạn không thể sử dụng ổ cắm UNIX ở trên
  # inet_lister lmtp {
    # Tránh hiển thị LMTP cho toàn bộ internet
    # Địa chỉ =
    # cổng =
  # }
}

service imap {
  # Hầu hết các bộ nhớ đi đến các tệp mmap () ing. Bạn có thể cần phải tăng điều này
  # Giới hạn nếu bạn có hộp thư lớn.
  # vsz_limit = $ default_vsz_limit

  # Tối đa. Số lượng quy trình IMAP (kết nối)
  # Process_limit = 1024
}

service pop3 {
  # Tối đa. Số lượng quy trình POP3 (kết nối)
  # Process_limit = 1024
}

service submission {
  # Tối đa. Số lượng quy trình gửi SMTP (kết nối)
  # Process_limit = 1024
}

service auth {
  # Auth_Socket_Path trỏ đến ổ cắm người dùng này theo mặc định. Nó thường là
  # được sử dụng bởi dovecot-lda, doveadm, có thể là quy trình IMAP, v.v.
  # Quyền đầy đủ cho ổ cắm này có thể nhận được danh sách tất cả các tên người dùng và
  # Nhận kết quả tra cứu người dùng của mọi người.
  # 
  # Chế độ 0666 mặc định cho phép mọi người kết nối với ổ cắm, nhưng
  # Tra cứu người dùng sẽ chỉ thành công nếu người dùng trả về trường "uid"
  # khớp với UID của quy trình người gọi. Ngoài ra nếu uid hoặc GID của người gọi phù hợp với
  # UID của Socket hoặc Gid Tra cứu thành công. Bất cứ điều gì khác gây ra một thất bại.
  # 
  # Để cấp cho người gọi đầy đủ quyền để tra cứu tất cả người dùng, hãy đặt chế độ thành
  # một cái gì đó khác hơn 0666 và Dovecot cho phép hạt nhân thực thi
  # Quyền (ví dụ: 0777 cho phép mọi người có quyền đầy đủ).
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix
  }
}

service auth-worker {
  # Quy trình công nhân Auth được chạy làm root theo mặc định, để nó có thể truy cập
  # /vv/bóng. Nếu điều này không cần thiết, người dùng nên được thay đổi thành
  # $ default_interal_user.
  # user = root
}

service dict {
  # Nếu proxy dict được sử dụng, các quy trình thư sẽ có quyền truy cập vào ổ cắm của nó.
  # Ví dụ: mode = 0660, nhóm = vmail và toàn cầu mail_access_groups = vmail
  unix_listener dict {
    # Chế độ = 0600
    # Người dùng =
    # Nhóm =
  }
}
Một lần nữa, hãy đảm bảo thay thế miền trong tất cả các tệp này, femmebabe.com, với tên miền bạn đã chọn. Chỉnh sửa tệp tiếp theo, cấu hình của dovecot,

nano config/etc_dovecot_dovecot
Và thêm những dòng này

## Tệp cấu hình OVECOT

# Nếu bạn đang vội, hãy xem http://wiki2.dovecot.org/quickconfiguration

# Lệnh "Doveconf -n" cung cấp đầu ra sạch của các cài đặt đã thay đổi. Sử dụng nó
# Thay vì sao chép và dán tệp khi đăng vào danh sách gửi thư của Dovecot.

# '# 'Nhân vật và mọi thứ sau khi nó được coi là bình luận. Thêm không gian
# và các tab bị bỏ qua. Nếu bạn muốn sử dụng một trong hai điều này một cách rõ ràng, hãy đặt
# value inside quotes, eg.: key = "# Char và Trailing Whitespace "

# Hầu hết (nhưng không phải tất cả) cài đặt có thể được ghi đè bởi các giao thức khác nhau và/hoặc
# IP nguồn/đích bằng cách đặt các cài đặt bên trong các phần, ví dụ:
# Giao thức IMAP {}, cục bộ 127.0.0.1 {}, từ xa 10.0.0.0/8 {}

# Các giá trị mặc định được hiển thị cho mỗi cài đặt, không bắt buộc phải giải phóng
# những thứ kia. Đây là những ngoại lệ cho điều này mặc dù: không có phần nào (ví dụ: không gian tên {})
# hoặc cài đặt plugin được thêm theo mặc định, chúng chỉ được liệt kê dưới dạng ví dụ.
# Các đường dẫn cũng chỉ là các ví dụ với mặc định thực sự dựa trên cấu hình
# tùy chọn. Các đường dẫn được liệt kê ở đây là để cấu hình - -prefix =/usr
# --sysconfdir =/etc-localstatedir =/var

# Bật các giao thức được cài đặt
!include_try /usr/share/dovecot/protocols.d/*.protocol

# Một danh sách phân tách bằng dấu phẩy của IPS hoặc máy chủ nơi lắng nghe để kết nối.
# "*" Listens trong tất cả các giao diện IPv4 ", ::" Lắng nghe trong tất cả các giao diện IPv6.
# Nếu bạn muốn chỉ định các cổng không mặc định hoặc bất cứ điều gì phức tạp hơn,
# Chỉnh sửa conf.d/master.conf.
# Nghe = *, ::

# Thư mục cơ sở nơi lưu trữ dữ liệu thời gian chạy.
# Base_dir =/var/run/dovecot/

# Tên của trường hợp này. Trong thiết lập đa trường hợp doveadm và các lệnh khác
# có thể sử dụng -i <stance_name> để chọn phiên bản nào được sử dụng (một giải pháp thay thế
# đến -c <config_path>). Tên thể hiện cũng được thêm vào các quy trình dovecot
# Trong đầu ra PS.
# Instance_name = Dovecot

# Thông điệp chào hỏi cho khách hàng.
# login_greeting = dovecot sẵn sàng.

# Danh sách phân tách không gian của các phạm vi mạng đáng tin cậy. Kết nối từ những điều này
# IP được phép ghi đè địa chỉ IP và cổng của họ (để ghi nhật ký và
# để kiểm tra xác thực). vô hiệu hóa_plaintext_auth cũng bị bỏ qua
# Những mạng này. Thông thường, bạn sẽ chỉ định các máy chủ proxy IMAP của mình ở đây.
# login_trusted_networks =

# Danh sách phân tách không gian của các ổ cắm kiểm tra truy cập đăng nhập (ví dụ: TCPWRAP)
# login_access_sockets =

# Với proxy_maybe = Có nếu đích proxy khớp với bất kỳ IP nào trong số này, đừng làm
# ủy quyền. Điều này không cần thiết bình thường, nhưng có thể hữu ích nếu đích đến
# IP là ví dụ: IP cân bằng tải.
# Auth_Proxy_Self =

# Hiển thị thêm tiêu đề quy trình dài dòng (trong PS). Hiện tại hiển thị tên người dùng và
# Địa chỉ IP. Hữu ích khi xem ai đang thực sự sử dụng các quy trình IMAP
# (ví dụ: hộp thư được chia sẻ hoặc nếu cùng UID được sử dụng cho nhiều tài khoản).
# verbose_proctitle = không

# Nên tất cả các quy trình bị giết khi quá trình chính của Dovecot tắt.
# Đặt điều này thành "Không" có nghĩa là dovecot có thể được nâng cấp mà không cần
# buộc các kết nối khách hàng hiện tại phải đóng (mặc dù điều đó cũng có thể
# Một vấn đề nếu việc nâng cấp là, ví dụ: vì một bản sửa lỗi bảo mật).
# Shutdown_Clents = Có

# Nếu không phải là không, hãy chạy các lệnh thư qua nhiều kết nối này đến máy chủ Doveadm,
# Thay vì chạy chúng trực tiếp trong cùng một quy trình.
# doveadm_worker_count = 0
# Unix Ổ cắm hoặc máy chủ: Cổng được sử dụng để kết nối với máy chủ Doveadm
# doveadm_socket_path = doveadm-server

# Danh sách không gian phân tách các biến môi trường được bảo tồn trên Dovecot
# Khởi nghiệp và truyền lại cho tất cả các quá trình con của nó. Bạn cũng có thể cho
# khóa = các cặp giá trị để luôn đặt cài đặt cụ thể.
# Nhập khẩu_Envirment = tz

## 
## Cài đặt máy chủ từ điển
## 

# Từ điển có thể được sử dụng để lưu trữ khóa = danh sách giá trị. Điều này được sử dụng bởi một số
# plugin. Từ điển có thể được truy cập trực tiếp hoặc mặc dù
# Máy chủ từ điển. Tên Dict Block bản đồ tên từ điển đến URI
# Khi máy chủ được sử dụng. Chúng sau đó có thể được tham chiếu bằng URI ở định dạng
# "Proxy :: <Tên>".

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

# Hầu hết các cấu hình thực tế được bao gồm dưới đây. Tên tệp là
# Đầu tiên được sắp xếp theo giá trị ASCII của họ và phân tích cú pháp theo thứ tự đó. 00-prefixes
# Trong tên tệp nhằm mục đích giúp việc hiểu đặt hàng dễ dàng hơn.
!include conf.d/*.conf

# Một tệp cấu hình cũng có thể được cố gắng được đưa vào mà không gây ra lỗi nếu
# Nó không được tìm thấy:
!include_try local.conf

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

protocols = imap pop3

# Cho phép Dovecot nghe tất cả các kết nối đầu vào (IPv4 / IPv6)

listen = *, ::
Thêm mật khẩu cho người dùng DoveCot:

nano config/etc_dovecot_passwd
Phần đầu tiên của tập tin, trước đại tràng, là tên người dùng. Phần cuối cùng, bạn của bạn, biểu thị mật khẩu bạn muốn cung cấp cho máy chủ thư của bạn.

team:{plain}yourpassword
Tiếp theo, cấu hình opendkim

nano config/etc_opendkim.conf
Và thêm các dòng sau:

# Đây là một cấu hình cơ bản để ký và xác minh. Nó có thể dễ dàng
# thích nghi để phù hợp với một cài đặt cơ bản. Xem opendkim.conf (5) và
# /usr/share/doc/opendkim/examples/opendkim.conf.sample để hoàn thành
# Tài liệu của các tham số cấu hình có sẵn.

Syslog			yes
SyslogSuccess		yes
# Logwhy không

# Thông số ký và xác minh phổ biến. Trong Debian, tiêu đề "từ" là
# được ký hợp đồng, bởi vì nó thường là khóa danh tính được sử dụng bởi các hệ thống danh tiếng
# Và do đó có phần bảo mật nhạy cảm.
Canonicalization	relaxed/simple
Mode			s
SubDomains		no
OversignHeaders		From

# Ký tên miền, bộ chọn và khóa (bắt buộc). Ví dụ: thực hiện ký kết
# Đối với tên miền "example.com" với bộ chọn "2020" (2020._domainkey.example.com),
# Sử dụng khóa riêng được lưu trữ trong /etc/dkimkeys/example.private. Nhiều hạt hơn
# Tùy chọn thiết lập có thể được tìm thấy trong /usr/share/doc/opendkim/readme.opendkim.
# Ví dụ tên miền.com
# Bộ chọn 2020
# Keyfile /etc/dkimkeys/example.private

# Trong Debian, OpendKim chạy với tư cách là người dùng "OpendKim". Một UMASK của 007 là bắt buộc khi
# Sử dụng ổ cắm cục bộ với các MTA truy cập vào ổ cắm như một người không đặc quyền
# người dùng (ví dụ: Postfix). Bạn có thể cần thêm người dùng "postfix" vào nhóm
# "Opendkim" trong trường hợp đó.
UserID			opendkim
UMask			007

# Ổ cắm cho kết nối MTA (bắt buộc). Nếu MTA ở trong nhà tù chroot,
# Nó phải được đảm bảo rằng ổ cắm có thể truy cập được. Trong Debian, Postfix chạy trong
# một chroot in/var/spool/postfix, do đó một ổ cắm unix sẽ phải
# Được cấu hình như hiển thị trên dòng cuối cùng dưới đây.
# Ổ cắm cục bộ: /run/opendkim/opendkim.sock
# Ổ cắm inet: 8891@localhost
# Ổ cắm Inet: 8891
Socket			local:/var/spool/postfix/opendkim/opendkim.sock

PidFile			/run/opendkim/opendkim.pid

# Máy chủ để ký thay vì xác minh, mặc định là 127.0.0.1. Xem
# Phần hoạt động của OpendKim (8) để biết thêm thông tin.
# InteralHosts 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12

# Neo Trust cho phép DNSSEC. Trong Debian, tệp neo ủy thác được cung cấp
# bởi gói DNS-Root-Data.
TrustAnchorFile		/usr/share/dns/root.key
# Máy chủ tên 127.0.0.1

# Bản đồ miền từ địa chỉ đến các khóa được sử dụng để ký tin nhắn
KeyTable           refile:/etc/opendkim/key.table
SigningTable       refile:/etc/opendkim/signing.table

# Một bộ máy chủ nội bộ có thư phải được ký
InternalHosts       /etc/opendkim/trusted.hosts

nano config/etc_default_opendkim
Và thêm những dòng này

# Lưu ý: Đây là một tệp cấu hình kế thừa. Nó không được sử dụng bởi opendkim
# Dịch vụ Systemd. Vui lòng sử dụng các tham số cấu hình tương ứng trong
# /etc/opendkim.conf thay thế.
# 
# Trước đây, người ta sẽ chỉnh sửa cài đặt mặc định ở đây, sau đó thực thi
# /lib/opendkim/opendkim.service.generate để tạo các tệp ghi đè systemd đến
# /etc/systemd/system/opendkim.service.d/override.conf và
# /etc/tmpfiles.d/opendkim.conf. Mặc dù điều này vẫn có thể, nhưng bây giờ nó là
# Được đề xuất để điều chỉnh các cài đặt trực tiếp trong /etc/opendkim.conf.
# 
# Daemon_opts = ""
# Thay đổi thành/var/spool/postfix/chạy/opendkim để sử dụng ổ cắm unix với
# Postfix trong một chroot:
# Vòng tròn =/var/spool/postfix/chạy/opendkim
RUNDIR=/run/opendkim
# 
# Unmomment để chỉ định một ổ cắm thay thế
# Lưu ý rằng cài đặt này sẽ ghi đè bất kỳ giá trị ổ cắm nào trong opendkim.conf
# mặc định:
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
# Nghe trên tất cả các giao diện trên cổng 54321:
# Ổ cắm = Inet: 54321
# Nghe trên Loopback trên cổng 12345:
# Ổ cắm = inet: 12345@localhost
# Nghe là 192.0.2.1 là cổng 12345:
# Ổ cắm = Inet: 12345@192.0.2.1
USER=opendkim
GROUP=opendkim
PIDFILE=$RUNDIR/$NAME.pid
EXTRAAFTER=
Khi chúng tôi sẵn sàng thiết lập máy chủ Postfix của mình, chúng tôi sẽ chạy mã dưới đây, với tên miền thích hợp được nhúng. Bắt đầu bằng cách tạo tập lệnh

touch scripts/postfixsetup
sudo chmod a+x scripts/postfixsetup
nano scripts/postfixsetup
Bây giờ, trong Nano, trình soạn thảo văn bản, chỉnh sửa tệp này để nó bao gồm tên miền của bạn thay vì femmebabe.com.

# !
# Thiết lập 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}'
Bây giờ, chạy tập lệnh đã hoàn thành để định cấu hình Postfix, OpendKim và Dovecot.

./scripts/postfixsetup
Khi tập lệnh này đã chạy, hãy sao chép dòng cuối cùng mà nó in và dán nó vào cấu hình DNS của bạn làm giá trị cho sendonly._domainkey. Đây là khóa OpenDkim được sử dụng để xác định tên miền của bạn khi gửi thư an toàn. Tuyệt vời! Trong vài ngày, bạn sẽ có thể gửi thư từ máy chủ với điều kiện mọi thứ đều được cấu hình chính xác. Nếu bạn chỉ định cấu hình DNS cho máy chủ thư của mình, sẽ mất ít hơn 72 giờ để các bản ghi cập nhật. Nó thường nhanh hơn nhiều. Bạn có thể kiểm tra xem máy chủ của bạn có hoạt động bằng cách sử dụng lệnh này không, đã cung cấp email của bạn:

echo “test” | mail -s “Test Email” youremail@gmail.com
Nếu mọi thứ dường như hoạt động chính xác, bạn sẽ có thể gửi email với máy chủ của mình. Nếu nó không hoạt động, hãy thử nhìn vào nhật ký để xem lỗi có thể là gì.

tail –lines 150 /var/log/mail.log
Điều này sẽ cung cấp thông tin dài dòng về thư được gửi bởi máy chủ và liệu nó có hoạt động tốt không. Bạn cũng có thể xem email trong hộp thư đến của mình, nếu không có ở đó, hãy kiểm tra thư mục thư rác của bạn. Bạn cũng sẽ cần định cấu hình cài đặt của mình trong cài đặt của mình. Thêm hoặc thay thế các dòng này trong cài đặt của bạn

EMAIL_HOST = DOMAIN
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_ADDRESS = 'team@femmebabe.com'
EMAIL_HOST_USER = 'team' # 'Love@mamasheen.com'
EMAIL_HOST_PASSWORD = config['EMAIL_HOST_PASSWORD']
DEFAULT_FROM_EMAIL = '{} <{}>'.format(SITE_NAME, EMAIL_HOST_USER)
Lưu ý rằng chúng tôi đang sử dụng tệp cấu hình để lấy mật khẩu. Hãy tải tệp này trong các cài đặt như vậy, ở đầu tệp .:

import os
import json

# Mở và tải cấu hình
with open('/etc/config.json') as config_file:
    config = json.load(config_file)
Hãy tạo tệp này và thêm một khóa bí mật cho nó, cũng như mật khẩu thư. Để tạo khóa bí mật, hãy sử dụng lệnh này, với bất kỳ độ dài nào bạn thích ở cuối:

openssl rand -base64 64
Bây giờ, hãy sao chép văn bản mà OpenSSL đã tạo và chỉnh sửa /etc/config.json

sudo nano /etc/config.json
Thêm các dòng sau vào tệp của bạn, với khóa OpenSSL được tạo dưới dạng khóa bí mật.

{
	"SECRET_KEY": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX-generated-using-openssl)",
	"EMAIL_HOST_PASSWORD": "yourpassword"
}
Định dạng JSON rất đơn giản và dễ sử dụng, chúng tôi có thể khai báo các khóa khác mà chúng tôi muốn sử dụng trong dự án của mình theo cách này và giữ chúng tách biệt với thư mục dự án của chúng tôi để người dùng khác không thể viết cho chúng và vì vậy chúng không thể đọc được từ thư mục dự án của chúng tôi một mình. Điều này được khuyến nghị thực hành cho các khóa API, trong đó chúng tôi sẽ sử dụng nhiều hơn một số ở đây. Bạn cũng sẽ muốn sao lưu dự án của mình để đảm bảo mọi thứ được lưu và bạn sẽ có thể phục hồi công việc của mình sau này ngay cả khi bạn không còn muốn thuê máy chủ.

sudo backup
Bây giờ, hãy thử gửi email HTML từ máy chủ web, cung cấp gửi một từ dòng lệnh đang hoạt động. Truy vấn phiên bản người dùng của bạn trong shell và gửi email HTML cho người dùng đó thông qua Django. Thay đổi tên của tôi trong mã, Charlotte, thành tên người dùng của bạn.

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()
Nếu lệnh đầu tiên không hoạt động, hãy đảm bảo sử dụng

source venv/bin/activate
Với điều kiện mọi thứ được thiết lập chính xác, bây giờ bạn sẽ nhận được một email chào mừng trong hộp thư của bạn được gửi bởi ứng dụng web của bạn. Làm tốt lắm! Bạn đã đi một chặng đường dài. Tôi muốn thêm, nếu bạn đang phải vật lộn với bất kỳ lỗi nào trong khi làm việc trong một dự án như thế này, đừng ngần ngại tìm kiếm câu trả lời và yêu cầu giúp đỡ. Google, trong số các công cụ tìm kiếm khác, là những nguồn lực tuyệt vời để tìm kiếm trợ giúp lập trình. Chỉ cần tìm kiếm lỗi bạn đang nhận được và bạn sẽ có thể thấy cách người khác giải quyết vấn đề. Ngoài ra, bạn được chào đón liên hệ với tôi, các nhà giáo dục của bạn (giáo viên, giáo sư, gia sư), bất kỳ đồng nghiệp nào trên internet có sẵn để trợ giúp lập trình hoặc tham khảo lại cuốn sách này hoặc các tài nguyên khác để tìm giải pháp cho các vấn đề bạn đang gặp phải. Tôi hiểu điều này không dễ dàng, nhưng ngay cả khi bạn đã đọc điều này và không viết bất kỳ mã nào, bạn đang học rất nhiều về việc xây dựng một ứng dụng web từ đầu. Vỗ nhẹ vào lưng, bạn đang làm rất tốtcông việc. Cảm ơn bạn đã dành thời gian để đọc Hướng dẫn phát triển web phiên bản thứ ba này. Trong các phiên bản trong tương lai, tôi sẽ bao gồm nhiều ví dụ quan trọng được thảo luận khi bắt đầu tài liệu và chúng tôi sẽ đi sâu hơn nhiều vào thế giới phát triển phần mềm và phần cứng. Hãy theo dõi những gì sắp tới và tôi mong muốn dạy bạn cách xây dựng phần mềm đáng kinh ngạc. Hẹn gặp lại các bạn






Đóng
Trang 1
Nhảy
Xem toàn bộ bài viết
Tiếp tục đọc

Mua | Mua bằng tiền điện tử



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


(Click hoặc tap để tải hình ảnh)
Các dịch vụ giải trí, hình ảnh, video, âm thanh, phát trực tiếp và trò chơi thông thường chuyên nghiệp, cũng như các dịch vụ quét ID, phát triển web và mang thai hộ.

Hãy để lại cho tôi một mẹo về Bitcoin bằng địa chỉ này: 3KhDWoSve2N627RiW8grj6XrsoPT7d6qyE

© Glam Girl X 2025

Điều khoản dịch vụ