<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ashrafZolkopli</title>
    <description>The latest articles on DEV Community by ashrafZolkopli (@ashraf_zolkopli).</description>
    <link>https://dev.to/ashraf_zolkopli</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F340907%2F478019f5-eb4b-4ed6-a1f3-73a9ec34f3d8.png</url>
      <title>DEV Community: ashrafZolkopli</title>
      <link>https://dev.to/ashraf_zolkopli</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ashraf_zolkopli"/>
    <language>en</language>
    <item>
      <title>10 Steps to GitHub Pages Greatness</title>
      <dc:creator>ashrafZolkopli</dc:creator>
      <pubDate>Tue, 17 May 2022 18:34:35 +0000</pubDate>
      <link>https://dev.to/ashraf_zolkopli/10-steps-to-github-pages-greatness-4jd6</link>
      <guid>https://dev.to/ashraf_zolkopli/10-steps-to-github-pages-greatness-4jd6</guid>
      <description>&lt;p&gt;I honestly feel that Dev.to is perfect for blogging, however I do find it hard to share the various web project that I want to share to the public. Sure I can cut and paste all my project code and share the screen shot, but I can't exactly let reader go for a test run on my blog.&lt;/p&gt;

&lt;p&gt;Facing with this dilemma, I could either start a new server ( cost money ) or I could use the various free static side offered to the public such as GitHub Pages, Netlify and etc.. &lt;/p&gt;

&lt;p&gt;Since I am using GitHub as my code repo, I think this is the perfect time to use GitHub Pages. Single build process, just by committing to GitHub Repo and it just work... well technically the pages update after roughly a few minutes. &lt;/p&gt;

&lt;p&gt;To make this web page free, I just use the free tier by GitHub.&lt;/p&gt;

&lt;p&gt;The following are the steps taken to start my own blog using GitHub Pages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Start your new repo.
&lt;/h2&gt;

&lt;p&gt;you may start by going to your GitHub account page and located the green button with the text New&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mdRE7NC0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dabvmxgzb19pmi81leq9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mdRE7NC0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dabvmxgzb19pmi81leq9.png" alt="Create New Repo" width="335" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;now pressing this button will redirect you to &lt;a href="https://github.com/new"&gt;Create a new repository&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--80s2p4G1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rfgoox1le1r4ppokrjvc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--80s2p4G1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rfgoox1le1r4ppokrjvc.png" alt="Create a new repository" width="729" height="845"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Name your repo.
&lt;/h2&gt;

&lt;p&gt;What we are looking to do right now is what GitHub call &lt;strong&gt;user site&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;the naming convention for the user site is as follow :&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;username with all lowercase&amp;gt;.github.io&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;for example, my GitHub username is ashrafZolkopli&lt;br&gt;
so my repo name should be &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ashrafzolkopli.github.io&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uKC4Cu9q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1b4wzfwbzrkttcrerg9s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uKC4Cu9q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1b4wzfwbzrkttcrerg9s.png" alt="Naming The repo" width="745" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Setting the repo to public.
&lt;/h2&gt;

&lt;p&gt;Since we are using the free tier, we need to make sure that our repo is public and accessible. If you are using the paid tier, you may set the repo to private.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kwLQKfQ8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wvldb649z6weorz7q13s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kwLQKfQ8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wvldb649z6weorz7q13s.png" alt="Setting Repo to Public" width="702" height="119"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Create repo.
&lt;/h2&gt;

&lt;p&gt;You may now click on create repo button located at the bottom of the page&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ooQp65FJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mvzymfh8clnnz2dixk0f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ooQp65FJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mvzymfh8clnnz2dixk0f.png" alt="Create Repo Button" width="584" height="112"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Clone Repo to Localhost.
&lt;/h2&gt;

&lt;p&gt;After you click on Create Repository button, GitHub will divert you to a new page &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---_Tq3fOt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2p2h1cce923rlhubywjm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---_Tq3fOt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2p2h1cce923rlhubywjm.png" alt="Repo Page" width="880" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You may call me lazy, but I been using GitHub Desktop like forever. &lt;/p&gt;

&lt;p&gt;Just a matter of a few click and you are done cloning.&lt;/p&gt;

&lt;p&gt;Click on the set up in desktop button &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ubq8TRTR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/96fbiox5kjnr3r5vw6qk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ubq8TRTR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/96fbiox5kjnr3r5vw6qk.png" alt="Set up in dekstop" width="880" height="107"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;on GitHub Desktop:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ceoxfk3Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uy84bhxblr6zx73ie4pi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ceoxfk3Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uy84bhxblr6zx73ie4pi.png" alt="GitHub Desktop Preview" width="880" height="607"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click the Clone button&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IxcYWFFj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uwa5n9rypgsjw9iz59sc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IxcYWFFj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uwa5n9rypgsjw9iz59sc.png" alt="Clone Button" width="493" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub Desktop now will show us a new page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PZjFfjc5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6buyj2o1ciwkqofvrynt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PZjFfjc5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6buyj2o1ciwkqofvrynt.png" alt="Current Repo Page" width="880" height="610"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now again I am lazy, I just click on open in Visual Studio Code button &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jxyB1BVJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m8qarpv55c85cla78ms7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jxyB1BVJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m8qarpv55c85cla78ms7.png" alt="Open In visual Studio code button" width="598" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And my Visual Studio Code &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rq5MsX7X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/casm3i1hu2amfelul6en.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rq5MsX7X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/casm3i1hu2amfelul6en.png" alt="Visual Studio Code" width="880" height="665"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now your Repo have been clone in your localhost.&lt;/p&gt;

&lt;p&gt;Step 6: Create index.html file&lt;/p&gt;

&lt;p&gt;You now can choose either to use GitHub Jekyll for your build process and use index.md file with build in Github template or do it like me what uses pure html, css, js file.&lt;/p&gt;

&lt;p&gt;For purpose of this tutorial, I would now use a Start Bootstrap admin page template,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://startbootstrap.com/template/sb-admin"&gt;SB Admin&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--43nNf0LX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iaeiov3ihdxh0t3dac47.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--43nNf0LX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iaeiov3ihdxh0t3dac47.png" alt="Admin Page" width="880" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;you can download the app zip file from its Github repo, &lt;/p&gt;

&lt;p&gt;Again for the purpose of this tutorial, I am using only the index.html, css, js and assets file only&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P-goZ4ze--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p3zxz6nr2vidi0mifleq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P-goZ4ze--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p3zxz6nr2vidi0mifleq.png" alt="Files for Commit to git" width="356" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can verify that it works&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uBHG2-ml--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tj8xe6ubqz9ya6vwbjbb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uBHG2-ml--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tj8xe6ubqz9ya6vwbjbb.png" alt="The Page works!!!!!" width="880" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Commit to GitHub
&lt;/h2&gt;

&lt;p&gt;if you notice on the side bar, there are 9 changes had been made to the localhost that have not been commit to our local git.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mIj95nic--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9mlc2ghnffmm3x4tif2m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mIj95nic--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9mlc2ghnffmm3x4tif2m.png" alt="VS Code side bar" width="51" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open your source control bar, &lt;/p&gt;

&lt;p&gt;find and click the "+" button beside the 9 in circle, that says "Stage All Changes"&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--utcMzvwB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/947c1lxleqvt91mdpq31.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--utcMzvwB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/947c1lxleqvt91mdpq31.png" alt="Stage All Changes" width="479" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;now your Changes become Stage Changes&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fIxUaisl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wgkhd5tkeu6c2yhizn85.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fIxUaisl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wgkhd5tkeu6c2yhizn85.png" alt="Stage Changes" width="401" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In your message bar, you can name the changes into what ever you one, I would name this as my Initial Commit&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0K39TQdw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cg76ghni2j6gjh59w318.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0K39TQdw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cg76ghni2j6gjh59w318.png" alt="Initial Commit" width="403" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;while your cursor is still in the message bar, Click "ctrl" + "enter" on windows, This will commit your changes on localhost git&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wVsi4AAb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qzrqgx5wsauwbeyv8ume.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wVsi4AAb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qzrqgx5wsauwbeyv8ume.png" alt="Commit to localhost git" width="406" height="136"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;look for the "..." button highlighted in green &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hIyOiSU---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vu16k40cz2ls506608j4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hIyOiSU---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vu16k40cz2ls506608j4.png" alt="More action" width="417" height="149"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;now choose push&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--H2B4ss1g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/en5e9ltxl33240phc5ix.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--H2B4ss1g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/en5e9ltxl33240phc5ix.png" alt="Choose push" width="558" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Allow some time for the push to your GitHub Account.&lt;/p&gt;

&lt;p&gt;Now go to your GitHub account repo and verify the push is successful&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uAaeyZFq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ottr1wky6ltsctqwtcis.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uAaeyZFq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ottr1wky6ltsctqwtcis.png" alt="Push Successful" width="880" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 8: Set up GitHub Pages
&lt;/h2&gt;

&lt;p&gt;On your GitHub repo, click on Settings&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_li2KG5r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lf5bk5jrlnbmo2uu1mio.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_li2KG5r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lf5bk5jrlnbmo2uu1mio.png" alt="GitHub settings button" width="880" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;once Setting page is loaded, find the Pages button highlighted in green &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jQsoQMO2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8nodvo2mogdf0hc9afzc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jQsoQMO2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8nodvo2mogdf0hc9afzc.png" alt="Pages button" width="880" height="589"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since I am publishing from main branch I do not have to change any configuration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o4A8zbKM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ois1ggj9pl04rx5ch5z5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o4A8zbKM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ois1ggj9pl04rx5ch5z5.png" alt="Pages config" width="880" height="592"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;you may need to change the branch if you want to publish from a different branch&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 10: Admire your Now Static Website,
&lt;/h2&gt;

&lt;p&gt;now you can go to your page to admire your New Static Website&lt;/p&gt;

&lt;p&gt;my URL : &lt;a href="https://ashrafzolkopli.github.io/"&gt;ashrafzolkopli.github.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;if you click on this page later, I may change the layout and such for my own project, I included the screen shot for reference.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XPwxykYv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/51pyjjtld8nco8qi7ddu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XPwxykYv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/51pyjjtld8nco8qi7ddu.png" alt="Website screen shot" width="880" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope this step by step tutorial help you in deploying your own static website on GitHub Pages.&lt;/p&gt;

&lt;p&gt;Please feel free to comment or like if you read till this far...&lt;br&gt;
Comments are welcome and if you have any issue please feel free to comment here or contact me via &lt;a href="https://wa.link/9u4ibx"&gt;WhatsApp&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>github</category>
      <category>pages</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Django: Allauth</title>
      <dc:creator>ashrafZolkopli</dc:creator>
      <pubDate>Tue, 15 Jun 2021 10:29:23 +0000</pubDate>
      <link>https://dev.to/ashraf_zolkopli/django-allauth-1lc6</link>
      <guid>https://dev.to/ashraf_zolkopli/django-allauth-1lc6</guid>
      <description>&lt;p&gt;Up until now we haven't created any registration/login form. We could or should roll our own for a very special business requirement or we could use a ready made and famous authentication packages call &lt;a href="https://django-allauth.readthedocs.io/en/latest/installation.html"&gt;django-allauth&lt;/a&gt;. Django allauth will handle all your login/registration need, and include plugins for login using 3rd party Oauth such as google, facebook, twitter, github to  name a few. For more 3rd party authentication that Allauth support please refer &lt;a href="https://django-allauth.readthedocs.io/en/latest/providers.html"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Lets start will installation of Allauth&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Django-Allauth
&lt;/h2&gt;

&lt;p&gt;Installing django Allauth with the following command in your terminal&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipenv install django-allauth
pipenv lock -r &amp;gt; requirement.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;after the installation is done, We need to register django-allauth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Settings Django-Allauth
&lt;/h2&gt;

&lt;p&gt;Django-Allauth require a significant change to your settings.py file, Lets first check each part one by one ...&lt;/p&gt;

&lt;p&gt;open your settings.py file, and first check your INSTALLED_APP, and include the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;#...
&lt;/span&gt;    &lt;span class="c1"&gt;# Make sure the following 3 is installed
&lt;/span&gt;    &lt;span class="s"&gt;'django.contrib.auth'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'django.contrib.messages'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'django.contrib.sites'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="c1"&gt;# Django-allauth
&lt;/span&gt;    &lt;span class="s"&gt;'allauth'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'allauth.account'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'allauth.socialaccount'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;#...
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then add the following in your settings.py file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AUTHENTICATION_BACKENDS = [
    # Needed to login by username in Django admin, regardless of `allauth`
    'django.contrib.auth.backends.ModelBackend',

    # Django-allauth
    # `allauth` specific authentication methods, such as login by e-mail
    # https://django-allauth.readthedocs.io/en/latest/installation.html
    'allauth.account.auth_backends.AuthenticationBackend',
]

SITE_ID = 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;once done, we should now update the urls.py file&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring urls.py
&lt;/h2&gt;

&lt;p&gt;lets now open urls.py file and add the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;#...
&lt;/span&gt;    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'account/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'allauth.urls'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="c1"&gt;#...
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Optional Configuration
&lt;/h2&gt;

&lt;p&gt;The following would be optional configuration that you could add to change the behavior of django_allauth, first open your settings.py file and add the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Common Django Settings
&lt;/span&gt;&lt;span class="n"&gt;LOGIN_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"account/login"&lt;/span&gt;
&lt;span class="n"&gt;LOGIN_REDIRECT_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/"&lt;/span&gt;
&lt;span class="n"&gt;LOGOUT_REDIRECT_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/"&lt;/span&gt;


&lt;span class="c1"&gt;# Django-allauth
# https://django-allauth.readthedocs.io/en/latest/configuration.html
&lt;/span&gt;&lt;span class="n"&gt;ACCOUNT_AUTHENTICATION_METHOD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"username_email"&lt;/span&gt;
&lt;span class="n"&gt;ACCOUNT_EMAIL_REQUIRED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="n"&gt;ACCOUNT_EMAIL_VERIFICATION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"mandatory"&lt;/span&gt;
&lt;span class="n"&gt;ACCOUNT_SIGNUP_EMAIL_ENTER_TWICE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="n"&gt;ACCOUNT_SIGNUP_PASSWORD_ENTER_TWICE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;since we also added email verification mandatory, we need djnago to have an email backend&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Django Email Backend
&lt;/h2&gt;

&lt;p&gt;for testing purposes, its often better to use the console backend like so&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;EMAIL_BACKEND&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'django.core.mail.backends.console.EmailBackend'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but for me, I prefer to use the file backend as it will create a proper html file for our emails&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;EMAIL_BACKEND&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'django.core.mail.backends.filebased.EmailBackend'&lt;/span&gt;
&lt;span class="n"&gt;EMAIL_FILE_PATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BASE_DIR&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;joinpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'test'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;joinpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and create a folder directory like so &lt;/p&gt;

&lt;p&gt;test/email/&lt;/p&gt;

&lt;h2&gt;
  
  
  Migrate your database
&lt;/h2&gt;

&lt;p&gt;Django allauth require that you migrate its files with the command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you could now go to &lt;/p&gt;

&lt;p&gt;&lt;a href="http://127.0.0.1:8000/account/signup/"&gt;register page&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wXWjRvdB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/onwllm857nxuw44kuvib.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wXWjRvdB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/onwllm857nxuw44kuvib.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  End
&lt;/h1&gt;

&lt;p&gt;Congratulation, now your are able to register, and login your user using django-allauth&lt;/p&gt;

</description>
      <category>django</category>
      <category>github</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Django : ReCaptha Everywhere</title>
      <dc:creator>ashrafZolkopli</dc:creator>
      <pubDate>Tue, 15 Jun 2021 04:42:15 +0000</pubDate>
      <link>https://dev.to/ashraf_zolkopli/django-recaptha-everywhere-1474</link>
      <guid>https://dev.to/ashraf_zolkopli/django-recaptha-everywhere-1474</guid>
      <description>&lt;p&gt;In the previous post in this series, I talk about how we can use django-recaptcha to make sure our forms are protected from bot spam submission, however it can be tedious to add them to each form and also does not make it hard to add the recaptcha field if the form are generated by a django package that you had installed previously.&lt;/p&gt;

&lt;p&gt;Using the django-honeypot middleware method and knowledge on how django-recaptcha work, I had manage to roll my own middleware that inject the Google Recaptcha field into every page that have a form in a Django weebsite.&lt;/p&gt;

&lt;h2&gt;
  
  
  1) Start a new django app
&lt;/h2&gt;

&lt;p&gt;We Can first start an django app called G_Recaptha, the name of the app can be anything you want but I'm going with this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py startapp G_Recaptha
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2) G_Recaptha middleware
&lt;/h2&gt;

&lt;p&gt;We now should add a middleware.py file in G_Recaptha.&lt;/p&gt;

&lt;p&gt;in this file, insert the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.utils.safestring&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mark_safe&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.template.loader&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;render_to_string&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.conf&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.utils.encoding&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;force_str&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.helpers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;verify_recaptcha&lt;/span&gt;

&lt;span class="n"&gt;_POST_FORM_RE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;(&amp;lt;form\W[^&amp;gt;]*\bmethod\s*=\s*(\'|&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;|)POST(\'|&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;|)\b[^&amp;gt;]*&amp;gt;)&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IGNORECASE&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;_HTML_TYPES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text/html&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/xhtml+xml&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BaseRecapthaMiddleware&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;get_response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_response&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RecaptchaRequestMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseRecapthaMiddleware&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;callback_args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;callback_kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_ajax&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;verify_recaptcha&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RecaptchaResponseMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseRecapthaMiddleware&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;content_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="nf"&gt;except &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;KeyError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;AttributeError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;content_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;content_type&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;_HTML_TYPES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

            &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_recaptcha_field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;mark_safe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;render_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;G_Recaptcha/RecaptchaV3.html&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;recaptcha_site_key&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RECAPTCHA_PUBLIC_KEY&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_POST_FORM_RE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;add_recaptcha_field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;force_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RecaptchaMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;RecaptchaRequestMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;RecaptchaResponseMiddleware&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;this middleware file is almost the exact copy of django-honeypot that have been customize to insert google recaptcha field into and pages in our website that have a form field in the HTML.&lt;/p&gt;

&lt;h2&gt;
  
  
  3) G_Recaptha helpers.py
&lt;/h2&gt;

&lt;p&gt;In the middleware.py file on line 6 we call for verify_recaptcha from helpers.py file.&lt;/p&gt;

&lt;p&gt;Lets now create a file called helpers.py file and insert the following lines into the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.conf&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.http&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;HttpResponseBadRequest&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.template.loader&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;render_to_string&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;verify_recaptcha&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;recaptcha_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;g-recaptcha-response&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;secret&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RECAPTCHA_PRIVATE_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;response&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;recaptcha_response&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://www.google.com/recaptcha/api/siteverify&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; \
                &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RECAPTCHA_REQUIRED_SCORE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

        &lt;span class="n"&gt;respond&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;render_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;G_Recaptcha/ReCaptcha_error.html&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;HttpResponseBadRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;respond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4) G_Recaptha templates
&lt;/h2&gt;

&lt;p&gt;In middleware.py file, we force insert a html string into all the pages at line 47. This template is located at &lt;/p&gt;

&lt;p&gt;G_Recaptcha/templates/G_Recaptcha/RecaptchaV3.html.&lt;/p&gt;

&lt;p&gt;the html for the template are&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;'https://www.google.com/recaptcha/api.js?render=&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;recaptcha_site_key&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;//global grecaptcha&lt;/span&gt;
    &lt;span class="nx"&gt;grecaptcha&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;grecaptcha&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;recaptcha_site_key&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;form&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;g-recaptcha-response&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"g-recaptcha-response"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"g-recaptcha-response"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In helpers.py file we also have a template that responds if the user failed the Google Recaptha test with the template name Recaptcha_error.html located at &lt;/p&gt;

&lt;p&gt;G_Recaptcha/templates/G_Recaptcha/Recaptcha_error.html&lt;/p&gt;

&lt;p&gt;the template in its barebone is as follow,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;H1&amp;gt;&lt;/span&gt;Google ReCaptha Error &lt;span class="nt"&gt;&amp;lt;/H1&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you may want to change the design as required.&lt;/p&gt;

&lt;h2&gt;
  
  
  5) G_Recaptcha Settings configurations.
&lt;/h2&gt;

&lt;p&gt;lets now open settings.py file and make the following changes as follows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;#...
&lt;/span&gt;    &lt;span class="c1"&gt;# Custom Google ReCaptcha
&lt;/span&gt;    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;G_Recaptcha&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;#...
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;MIDDLEWARE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;#...
&lt;/span&gt;    &lt;span class="c1"&gt;# Custom Google ReCaptcha
&lt;/span&gt;    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;G_Recaptcha.middleware.RecaptchaMiddleware&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;#...
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Custom Google Recaptcha
&lt;/span&gt;&lt;span class="n"&gt;RECAPTCHA_PUBLIC_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;RECAPTCHA_PUBLIC_KEY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;RECAPTCHA_PRIVATE_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;RECAPTCHA_PRIVATE_KEY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;RECAPTCHA_REQUIRED_SCORE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;RECAPTCHA_REQUIRED_SCORE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cast&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6)Update .env files
&lt;/h2&gt;

&lt;p&gt;Since we are using python-decouple, we should now update the .env file with the following fields&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RECAPTCHA_PUBLIC_KEY = '&amp;lt;site_key&amp;gt;'
RECAPTCHA_PRIVATE_KEY = '&amp;lt;public_key&amp;gt;'
RECAPTCHA_REQUIRED_SCORE = &amp;lt;value between 0.00 to 1.00&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7) Testing
&lt;/h2&gt;

&lt;p&gt;the easiest place to test is the admin login page&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcbmhi5qckmbww81j2svv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcbmhi5qckmbww81j2svv.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;as you can see, the google recaptcha had been displayed located at the bottom of such form&lt;/p&gt;

&lt;p&gt;now we should test if we failed the google recaptcha by setting the &lt;code&gt;RECAPTCHA_REQUIRED_SCORE = 1.00&lt;/code&gt; in the .env file&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa4xz1hw6d1rjyl8ji6yg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa4xz1hw6d1rjyl8ji6yg.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;as you can see I had failed the recaptcha test.&lt;/p&gt;

&lt;p&gt;now lower the  &lt;code&gt;RECAPTCHA_REQUIRED_SCORE = 1.00&lt;/code&gt; to the value you are comfortable with such as 0.85&lt;/p&gt;

&lt;p&gt;you should now be able to login as normal.&lt;/p&gt;

&lt;h2&gt;
  
  
  End
&lt;/h2&gt;

&lt;p&gt;We now able to protect all the form in our project with google ReCaptcha. Hopefully this will slowdown or stop any attempt to attack our django webpage.&lt;/p&gt;

</description>
      <category>django</category>
      <category>github</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Django Defense Against Bot</title>
      <dc:creator>ashrafZolkopli</dc:creator>
      <pubDate>Mon, 14 Jun 2021 05:05:44 +0000</pubDate>
      <link>https://dev.to/ashraf_zolkopli/django-defense-against-bot-42ib</link>
      <guid>https://dev.to/ashraf_zolkopli/django-defense-against-bot-42ib</guid>
      <description>&lt;p&gt;In the previous post, I talked about how we could implement a simple trick to stop bot from continuing to submit a form in our web app. However like I told you, this might not be enough to keep all the bot from doing harm to our website. How to make it better? well another simple way is to implement a ReCaptcha. ReCaptcha is a relatively simple tool to identify if a web form in our site is being submitted by a human being or a robot. For this implementation ReCaptcha, a package called &lt;a href="https://github.com/praekelt/django-recaptcha" rel="noopener noreferrer"&gt;django-recaptcha&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Google ReCaptcha API keys
&lt;/h2&gt;

&lt;p&gt;Before we can start using google ReCaptcha Api, first we need to register our application with google. I would propose to use Google ReCaptcha V3.&lt;/p&gt;

&lt;p&gt;click on this link &lt;a href="https://www.google.com/recaptcha/admin/create" rel="noopener noreferrer"&gt;Google ReCaptcha Admin&lt;/a&gt;, and fill in the required information&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ts9p5b7bu27v5qx7hlq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ts9p5b7bu27v5qx7hlq.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;click the submit button and copy your public and private api key&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjzx3ihp8tfqvx1vv4a45.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjzx3ihp8tfqvx1vv4a45.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing django-recaptcha
&lt;/h2&gt;

&lt;p&gt;You can start installing django-recaptcha with the following command in the terminal&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipenv install django-recaptcha
pipenv lock -r &amp;gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Registering django-recaptcha into your INSTALLED_APP
&lt;/h2&gt;

&lt;p&gt;Open your settings.py and located the INSTALLED_APP list and register django-recaptcha like so&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;#...
&lt;/span&gt;    &lt;span class="c1"&gt;# Django-recaptcha
&lt;/span&gt;    &lt;span class="c1"&gt;# https://github.com/praekelt/django-recaptcha
&lt;/span&gt;    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;captcha&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;#...
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  django-recaptcha configuration
&lt;/h2&gt;

&lt;p&gt;In the settings.py file, add the following setting config anywhere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Django-recaptcha
# https://github.com/praekelt/django-recaptcha
&lt;/span&gt;&lt;span class="n"&gt;RECAPTCHA_PUBLIC_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;site_key&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;RECAPTCHA_PRIVATE_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;public_key&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;RECAPTCHA_REQUIRED_SCORE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.75&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;replace site_key and public_key from the api key you copied from google recaptcha.&lt;/p&gt;

&lt;p&gt;if you are using python-decouple, the config would be&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Django-recaptcha
# https://github.com/praekelt/django-recaptcha
&lt;/span&gt;&lt;span class="n"&gt;RECAPTCHA_PUBLIC_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;RECAPTCHA_PUBLIC_KEY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;RECAPTCHA_PRIVATE_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;RECAPTCHA_PRIVATE_KEY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;RECAPTCHA_REQUIRED_SCORE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;RECAPTCHA_REQUIRED_SCORE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cast&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and in your .env file you should add the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RECAPTCHA_PUBLIC_KEY = '&amp;lt;site_key&amp;gt;'
RECAPTCHA_PRIVATE_KEY = '&amp;lt;public_key&amp;gt;'
RECAPTCHA_REQUIRED_SCORE = &amp;lt;value between 0.00 to 1.00&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to use django-recaptcha
&lt;/h2&gt;

&lt;p&gt;If you want to use a ReCaptcha field inside your form, in your forms.py&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;forms&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;captcha.fields&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ReCaptchaField&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;captcha.widgets&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ReCaptchaV3&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FormWithCaptcha&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;forms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;captcha&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ReCaptchaField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;ReCaptchaV3&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  End
&lt;/h2&gt;

&lt;p&gt;Now we are able to block user that fail the ReCaptcha test. This will stop most automated bot attack.&lt;/p&gt;

</description>
      <category>django</category>
      <category>github</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Django-Honeypot</title>
      <dc:creator>ashrafZolkopli</dc:creator>
      <pubDate>Sun, 13 Jun 2021 10:40:07 +0000</pubDate>
      <link>https://dev.to/ashraf_zolkopli/django-honeypot-3p93</link>
      <guid>https://dev.to/ashraf_zolkopli/django-honeypot-3p93</guid>
      <description>&lt;p&gt;We made it so we can catch bad guys that try to access our Admin site, but not how about we make so that all of our site form able to catch the bad guy? Sound like a cool proposal right.&lt;/p&gt;

&lt;p&gt;Usually, attacker will use a bot to try and crack our web app. One solution is to also include a honeypot everywhere there is a form. This will not deter all of the bot but adding that extra layer of security will not hurt right. Honestly, so far we made it so that we have incremental security measure in place. &lt;/p&gt;

&lt;p&gt;I think this is where I should say that, in security terms, there is nothing that is truly secure but we need to just slowdown the attack as much as we can to the point it doesn't make any sense for the attacker to continue. &lt;/p&gt;

&lt;h2&gt;
  
  
  Installing django-honeypot
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipenv install django-honeypot
pipenv lock -r &amp;gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuring django-honeypot
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;#...
&lt;/span&gt;
    &lt;span class="c1"&gt;# django-honeypot
&lt;/span&gt;    &lt;span class="s"&gt;'honeypot'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;#...
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;if you want to activate the honeypot web app wide, the easiest way was to use a middleware provided by django-honeypot&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MIDDLEWARE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;#...
&lt;/span&gt;
    &lt;span class="c1"&gt;# Django-honeypot
&lt;/span&gt;    &lt;span class="c1"&gt;# https://pypi.org/project/django-honeypot/
&lt;/span&gt;    &lt;span class="s"&gt;'honeypot.middleware.HoneypotMiddleware'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="c1"&gt;#...
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;lastly add this variable to your settings.py file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Django-honeypot
# https://pypi.org/project/django-honeypot/
&lt;/span&gt;&lt;span class="n"&gt;HONEYPOT_FIELD_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"secret_key"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  End
&lt;/h2&gt;

&lt;p&gt;As of right now I feel that we made our web app a bit safer. I'm not gonna say that our code is safe from any bot attack but at least the normal to medium type bot.&lt;/p&gt;

</description>
      <category>django</category>
      <category>github</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Django Admin Honeypot</title>
      <dc:creator>ashrafZolkopli</dc:creator>
      <pubDate>Sun, 13 Jun 2021 06:35:34 +0000</pubDate>
      <link>https://dev.to/ashraf_zolkopli/django-admin-honeypot-5g7f</link>
      <guid>https://dev.to/ashraf_zolkopli/django-admin-honeypot-5g7f</guid>
      <description>&lt;p&gt;When talking about Web Application security, I think one of the main page we need to defend at all cost is the webpage admin page. Once a hacker is able to gain access to the admin page, the fear would be the hacker is able to exfiltrate all our user Personal Information (PI). &lt;/p&gt;

&lt;p&gt;There are many propose solution to keep the web app admin pages safe. The propose solutions are:&lt;br&gt;
1) Only allow Admin to access the admin site through Local network or VPN.&lt;br&gt;
2) Separating the domain between normal user and admin user.&lt;/p&gt;

&lt;p&gt;But you know what, no matter how you handle securing the web app admin site. There will always be someone who will try to gain access to your website. Why not have a little fun and set up a honeypot for them. What a honeypot you may ask? A simple way of explaining it in layman terms is that its a lure for our hacker to try and attack us.&lt;/p&gt;

&lt;p&gt;One package we can use as a honeypot is called &lt;a href="https://pypi.org/project/django-admin-honeypot/"&gt;django-admin-honeypot&lt;/a&gt;. Its a simple package that will replace the real admin page with a face one and register all IP that try to access the page.&lt;/p&gt;
&lt;h2&gt;
  
  
  Installing django-admin-honeypot
&lt;/h2&gt;

&lt;p&gt;Installing django-admin-honeypot is just a simple as :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipenv install django-admin-honeypot
pipenv lock -r &amp;gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuring the django-admin-honeypot
&lt;/h2&gt;

&lt;p&gt;add &lt;code&gt;admin_honeypot&lt;/code&gt; in INSTALLED_APP located in settings.py&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;#...
&lt;/span&gt;
    &lt;span class="c1"&gt;# Django-admin-honeypot
&lt;/span&gt;    &lt;span class="s"&gt;'admin_honeypot'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;#...
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Update Urls for django-admin-honeypot
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'admin/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'admin_honeypot.urls'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'admin_honeypot'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'secret/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="c1"&gt;#       ^-- Change this to anything you like eg:secret
&lt;/span&gt;    &lt;span class="c1"&gt;#...
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  End
&lt;/h2&gt;

&lt;p&gt;With just 3 simple steps we are able to better protect our webapp. But this is not a fool proof method of protecting our app... It is one of the step to better secure our webapp.&lt;/p&gt;

</description>
      <category>django</category>
      <category>github</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>User Control Django  Session</title>
      <dc:creator>ashrafZolkopli</dc:creator>
      <pubDate>Sun, 13 Jun 2021 01:22:55 +0000</pubDate>
      <link>https://dev.to/ashraf_zolkopli/user-control-django-session-4241</link>
      <guid>https://dev.to/ashraf_zolkopli/user-control-django-session-4241</guid>
      <description>&lt;h1&gt;
  
  
  Preface
&lt;/h1&gt;

&lt;p&gt;In the last part of the Series, We made its so that our staff user can only have one user session at one time, however in the last series I decided not implement the session control towards normal user. For normal user I would prefer to display a list of all the session each user had, so that they can manually kill their session.&lt;/p&gt;

&lt;p&gt;Going with this idea, I would now use a library called &lt;a href="https://github.com/jazzband/django-user-sessions" rel="noopener noreferrer"&gt;django-user-sessions&lt;/a&gt;. This library will display the list of user active session have the ability to kill all his/her session.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdg32mf9qqpasbm59mbzj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdg32mf9qqpasbm59mbzj.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
[courtesy of django-user-session]&lt;/p&gt;
&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Among all the post that I have been writing previously, most library are quick and easy in terms of installing and usage. However django-user-sessions package depends on GeoIP library. GeoIP library require a huge databased provided from &lt;a href="https://dev.maxmind.com/" rel="noopener noreferrer"&gt;Maxmind&lt;/a&gt;. You would need to navigate to a &lt;a href="https://dev.maxmind.com/geoip/geolite2-free-geolocation-data" rel="noopener noreferrer"&gt;geolite2 page&lt;/a&gt;, register and download 2 files name GeoLite2-Country.mmdb.gz and GeoLite2-City.mmdb.gz as per instruction&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fpr3v2lj5nnoha1zyj9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fpr3v2lj5nnoha1zyj9.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once your have the files, unzip the folder, copy and paste in your working environment like so &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F38i5y3p1z6o1dtp0mcj8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F38i5y3p1z6o1dtp0mcj8.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;now lets install the GeoIP library and set the path directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipenv install geoip2
pipenv lock -r &amp;gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and in your settings add this line&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# GeoIP2 settings
# https://docs.djangoproject.com/en/3.2/ref/contrib/gis/geoip2/
&lt;/span&gt;&lt;span class="n"&gt;GEOIP_PATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BASE_DIR&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;joinpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GeoIP&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you should be able to use any package that require translation between IP to Geolocation&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing django-user-session
&lt;/h2&gt;

&lt;p&gt;lets now first install the library&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipenv install django-user-sessions
pipenv lock -r &amp;gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;now for something a bit controversial:&lt;/p&gt;

&lt;p&gt;1) Replacing  &lt;code&gt;'django.contrib.sessions'&lt;/code&gt; with &lt;code&gt;'user_sessions'&lt;/code&gt; in your INSTALLED_APP in your settings.py file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;# ...
&lt;/span&gt;    &lt;span class="c1"&gt;# 'django.contrib.sessions',
&lt;/span&gt;
    &lt;span class="c1"&gt;# Django-user-sessions
&lt;/span&gt;    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user_sessions&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="c1"&gt;# ...
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2) Replacing your &lt;code&gt;'django.contrib.sessions.middleware.SessionMiddleware'&lt;/code&gt; with &lt;code&gt;'user_sessions.middleware.SessionMiddleware'&lt;/code&gt; in your MIDDLEWARE in your settings.py file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MIDDLEWARE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;# ...
&lt;/span&gt;    &lt;span class="c1"&gt;# 'django.contrib.sessions.middleware.SessionMiddleware',
&lt;/span&gt;
    &lt;span class="c1"&gt;# Django-user-sessions
&lt;/span&gt;    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user_sessions.middleware.SessionMiddleware&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;# ...
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3) Add UserSession url in your urls.py file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.contrib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;admin&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.urls&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;

&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;admin/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user_sessions.urls&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user_sessions&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4) Setting the LOGOUT_REDIRECT_URL in settings.py file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Common Django Settings
&lt;/span&gt;&lt;span class="n"&gt;LOGOUT_REDIRECT_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;5) we can now do a make migrations and also migrate with the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py makemirgations 
python manage.py migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;6) If step 5 cause you some issue such as migrations conflict add the following line in your settings.py&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;SILENCED_SYSTEM_CHECKS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;admin.E410&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;7) This step is optional if you are working from behind a reverse proxy such as Nginx,&lt;/p&gt;

&lt;p&gt;a) install &lt;a href="https://github.com/allo-/django-xforwardedfor-middleware" rel="noopener noreferrer"&gt;django-xforwardedfor-middleware&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipenv install django-xforwardedfor-middleware==2.0
pipenv lock -r &amp;gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2) In your settings.py file, in your MIDDLEWARE add the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MIDDLEWARE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;# ...
&lt;/span&gt;    &lt;span class="c1"&gt;# django-xforwardedfor-middleware
&lt;/span&gt;    &lt;span class="c1"&gt;# https://github.com/allo-/django-xforwardedfor-middleware
&lt;/span&gt;    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;x_forwarded_for.middleware.XForwardedForMiddleware&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;# ...
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  End
&lt;/h1&gt;

&lt;p&gt;By completing the steps listed here, the user of your web app can now maintain on their own from which platform his/her have active session and kill the session if needed.&lt;/p&gt;

</description>
      <category>django</category>
      <category>github</category>
      <category>template</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Preventing Multiple Login for a Single Django User </title>
      <dc:creator>ashrafZolkopli</dc:creator>
      <pubDate>Sat, 12 Jun 2021 02:37:22 +0000</pubDate>
      <link>https://dev.to/ashraf_zolkopli/preventing-multiple-login-for-a-single-django-user-bg</link>
      <guid>https://dev.to/ashraf_zolkopli/preventing-multiple-login-for-a-single-django-user-bg</guid>
      <description>&lt;p&gt;Sometime website or a simple app implement a one login at a time function, like snapchat, or whatapp ( I'm not sure how long the whatapp example will hold true since there are hints that whatapp might be able to use on 4 concurrent device at a time). Anyway it might be a business logic requirement or even from a security stand point. &lt;/p&gt;

&lt;p&gt;I used to thing maybe it would be hard to implement such a behaviour until I found a package called &lt;a href="https://github.com/pcraston/django-preventconcurrentlogins"&gt;django-preventconcurrentlogins&lt;/a&gt;. Yes the name is that long but you know what, it does its job so well that sometime while testing, Me and my colleague who are using the same ID kinda wonder why we kept having to login... &lt;/p&gt;

&lt;p&gt;One thing to note about this application, this applies to all authenticated user to your site whether its just a normal user or staff. So in this post I will go through how I would implement the logic for all Authenticated User using the django-preventconcurrentlogins and also using the technique in the package that apply only for user with a staff status.&lt;/p&gt;

&lt;h1&gt;
  
  
  Installing django-preventconcurrentlogins
&lt;/h1&gt;

&lt;p&gt;the library is simple enough that its only need this command :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipenv install django-preventconcurrentlogins
pipenv lock -r &amp;gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Configure Setting.py for django-preventconcurrentlogins
&lt;/h1&gt;

&lt;p&gt;open your settings.py file and add the following into the parts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;        
    &lt;span class="c1"&gt;#...
&lt;/span&gt;    &lt;span class="s"&gt;'preventconcurrentlogins'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;#...
&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MIDDLEWARE_CLASSES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;        
    &lt;span class="c1"&gt;#...
&lt;/span&gt;    &lt;span class="s"&gt;'preentconcurrentlogins.middleware.PreventConcurrentLoginsMiddleware'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;#...
&lt;/span&gt;   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;this time you need to add a migrate since django-preventconcurrentlogins have some modal that needed to be migrated to your db&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py makemigrations
python manage.py migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And your done.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rolling our own library
&lt;/h2&gt;

&lt;p&gt;The way I see it, I want my staff user to only have Session at a time due to the nature of their work and let the Customer ( normal user ) to have as many user session as they want without killing their previous session. I know it might not look like it sound good but honestly... I would rather have my staff which have a higher chance of messing things up to be bothered with this security implementation when letting things get mess up.&lt;/p&gt;

&lt;p&gt;I'm not sure if I should work getting this become a package since I am gonna be using this a lot... maybe I would then... but for now lets just work on having this located in our User app.&lt;/p&gt;

&lt;h1&gt;
  
  
  Models.py
&lt;/h1&gt;

&lt;p&gt;Lets start will our models.py in the User app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.db&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.utils.translation&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;gettext_lazy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StaffLogin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;staff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;verbose_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Staff"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;on_delete&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CASCADE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;related_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'user_stafflogin'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;limit_choices_to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'is_staff'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;session_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;verbose_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Session Key"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;now lets create a middleware.py file in User app&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StaffLogin&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;importlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;import_module&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.conf&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;

&lt;span class="n"&gt;SessionStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;import_module&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SESSION_ENGINE&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;SessionStore&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PreventConcurrentStaffLogin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;get_response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_response&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_staff&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;staff_session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_key&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'staff_stafflogin'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;StaffLogin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;staff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;session_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;staff_session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;staff_db_session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;staff_stafflogin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_key&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;staff_session&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;staff_db_session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;SessionStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;staff_db_session&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;staff_stafflogin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;staff_session&lt;/span&gt;
            &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;staff_stafflogin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we update our middleware in our settings.py file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MIDDLEWARE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;#... must be after 
&lt;/span&gt;    &lt;span class="c1"&gt;# django.contrib.auth.middleware.AuthenticationMiddleware
&lt;/span&gt;
    &lt;span class="c1"&gt;#Custom Middleware Prevent Concurrent Staff Login
&lt;/span&gt;    &lt;span class="s"&gt;'User.middleware.PreventConcurrentStaffLogin'&lt;/span&gt;
    &lt;span class="c1"&gt;#...
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;now we should make a make mirgations and migrate since we now have a new model that we need to register in our db.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py makemigrations
python manage.py migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our web app should by now be able to make sure all our staff can only have one login session active at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  End
&lt;/h2&gt;

&lt;p&gt;In simple terms, now we are able to keep our user from having a concurrent login while using our app. Hopefully this will make our user much more safe, in a sense if someone else had login into our user, our user just have to login again so that the old session ( someone else that log into our user account ) will be deleted.&lt;/p&gt;

</description>
      <category>django</category>
      <category>github</category>
      <category>template</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Django Securing User Session</title>
      <dc:creator>ashrafZolkopli</dc:creator>
      <pubDate>Fri, 11 Jun 2021 22:52:48 +0000</pubDate>
      <link>https://dev.to/ashraf_zolkopli/django-securing-user-session-5e81</link>
      <guid>https://dev.to/ashraf_zolkopli/django-securing-user-session-5e81</guid>
      <description>&lt;h1&gt;
  
  
  Preface
&lt;/h1&gt;

&lt;p&gt;One of the common attack vector for Web App is called Session Hijacking. Session Hijacking means that an authenticated user session was able to be obtain by a hacker. This usually due to Man In The Middle (MITM) attack such as when user is using a public Wi-Fi/LAN that had been compromise by the hacker. &lt;/p&gt;

&lt;p&gt;Using HTTPS connection will encrypt the all communication between browser and server and setting a HTTP Strict Transport Security (HSTS) will make sure that all communication subsequence to the first connection between the browser and server will using HTTPS connection only. The first communication is usually cause the browser will request to a HTTP site then got redirected to a HTTPS site. HSTS also specify something called a Secure HSTS duration. This means that after x second from first contact between browser and server that set the HSTS policy will expire. &lt;/p&gt;

&lt;p&gt;In the small chance that, your user is logged in to your website, close the window and continue to not do anything with it for the duration of x second ( HSTS second relapse ), link to the internet through a ( compromise ) public Wi-Fi, go to google and connect to your website on a HTTP page which the "hacker" is able to sniff your user session cookie and later imitate the user as an authorize use on our site. &lt;/p&gt;

&lt;p&gt;Like I said there, there is a small chance but you never know maybe its that time of the year where all 8 planets in the solar system align just right with the wind blown from the far east with a wind speed of 100km/h hitting a small butterfly with so much force that it cause a ripple effect that will basically bring down your entire website for a month and causing a massive 100 million lawsuit. Well what I'm trying to say here is, Its better be safe then sorry. &lt;/p&gt;

&lt;p&gt;To further reduce this attack vector, I recommend using a Django package called &lt;a href="https://django-restricted-sessions.readthedocs.io/en/latest/"&gt;django-restricted-sessions&lt;/a&gt;. Its not a one all be all solution to our problem however, in my opinion its better to add such a package, it is so simple to implement and well you know what, you will thanks yourself one day that you implement it  and if any minute chance that one day you have to stand in front of a Information Security committee, stating that you had taken all the precaution possible to secure your web app this might be one of those you need to win the case.&lt;/p&gt;

&lt;p&gt;Anyway django-restricted-sessions isn't a bullet proof, even in its documentation state that it not perfect but it does deter the wannabe hacker from getting in so easily...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xOIuHNro--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t7h9i7q2c6rhyribjtaz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xOIuHNro--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t7h9i7q2c6rhyribjtaz.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I guess I been talking so much about this package that we should just install and configure it...&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing django-restrict-sessions
&lt;/h2&gt;

&lt;p&gt;Just 2 line of command in your terminal is what you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipenv install django-restricted-sessions
pipenv lock -r &amp;gt; requirement.txt

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting your middleware
&lt;/h2&gt;

&lt;p&gt;Open the setting.py file and add a simple line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="s"&gt;'restrictedsessions.middleware.RestrictedSessionsMiddleware'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;make sure the middleware is located after both&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="s"&gt;'django.contrib.sessions.middleware.SessionMiddleware'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="s"&gt;'django.contrib.auth.middleware.AuthenticationMiddleware'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;like so :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MIDDLEWARE_CLASSES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;....&lt;/span&gt;
    &lt;span class="s"&gt;'django.contrib.sessions.middleware.SessionMiddleware'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'django.contrib.auth.middleware.AuthenticationMiddleware'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'restrictedsessions.middleware.RestrictedSessionsMiddleware'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;....&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  End
&lt;/h2&gt;

&lt;p&gt;Thats it, simple as that, now your can feel a bit better about the fact that your webapp is a bit safer in the case of Session Hijacking.&lt;/p&gt;

</description>
      <category>django</category>
      <category>github</category>
      <category>template</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Django Password Helper</title>
      <dc:creator>ashrafZolkopli</dc:creator>
      <pubDate>Fri, 11 Jun 2021 18:55:05 +0000</pubDate>
      <link>https://dev.to/ashraf_zolkopli/django-password-helper-1946</link>
      <guid>https://dev.to/ashraf_zolkopli/django-password-helper-1946</guid>
      <description>&lt;h1&gt;
  
  
  Preface
&lt;/h1&gt;

&lt;p&gt;In the previous post, we had implement a password validator system with some proper way to make sure our use a hard password to check in the user point of view. However, many would just reuse their own old password everywhere on the internet.. This poses a huge problem if lets say one say the user password was leaked from another website and open up his/her door to our website too?&lt;/p&gt;

&lt;p&gt;A few years back, Dropbox introduce a &lt;a href="https://dropbox.tech/security/zxcvbn-realistic-password-strength-estimation"&gt;zxcvbn&lt;/a&gt;, Its basically a quantitative way of measuring how strong the user password is. While I was working with Django, I came across this library call &lt;a href="https://pypi.org/project/django-zxcvbn-password/"&gt;django-zxcvbn-password&lt;/a&gt;. Just to share, the name of zxcvbn came from.. and its not abbreviation of something with a deeper meaning. Well if you look at your normal keyboard, you could see that the name came from the letter located on the bottom row of your keyboard... &lt;/p&gt;

&lt;p&gt;Why is it important for us as the developer to include such package in our library? well to be honest we don't, however why not we give the user a method that will share with the how strong is the password they are using and how hard the password is to be cracked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation of django-zxcvbn-password
&lt;/h2&gt;

&lt;p&gt;The command for installing django-zxcvbn-password are as follows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipenv install django-zxcvbn-password
pipenv lock -r &amp;gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configure django-zxcvbn-password
&lt;/h2&gt;

&lt;p&gt;in the setting.py file add&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;#.... what ever you had registered 
&lt;/span&gt;    &lt;span class="c1"&gt;# Django-zxcvbn-password
&lt;/span&gt;    &lt;span class="s"&gt;'zxcvbn_password'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;#.... 
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;AUTH_PASSWORD_VALIDATORS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;#... anything that have been registered before
&lt;/span&gt;    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;'NAME'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'zxcvbn_password.ZXCVBNValidator'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'OPTIONS'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;'min_score'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;'user_attributes'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'username'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'first_name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'last_name'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to use django-zxcvbn-password
&lt;/h2&gt;

&lt;p&gt;The power of using django-zxcvbn-password come into play in 2 forms, one is the registration form and the other is the password change form.&lt;/p&gt;

&lt;p&gt;a sample that is provided by django-zxcvbn-password as follows for the forms.py&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;forms&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;zxcvbn_password.fields&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PasswordField&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PasswordConfirmationField&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RegisterForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;forms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;password1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PasswordField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;password2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PasswordConfirmationField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;confirm_with&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="n"&gt;password1&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and inside the html for the form&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"form"&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"my_url"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="nv"&gt;csrf_token&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
  &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;form&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;

&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;block&lt;/span&gt; &lt;span class="nv"&gt;js&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
  &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;block.super&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
  &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;form.media&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endblock&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the important part is the &lt;code&gt;{{ form.media }}&lt;/code&gt;, if using bootstrap4, the progress bar can work out of the box, because the JS for this app is using jQuery.&lt;/p&gt;

&lt;h2&gt;
  
  
  End
&lt;/h2&gt;

&lt;p&gt;This package help our web app user create a password with some level of complexity that would be hard to crack by any standard. This and using Argon2 hash will make sure if ever our web app got compromise, at the very lease, our user information is not leaked due to fault in the password.&lt;/p&gt;

</description>
      <category>django</category>
      <category>github</category>
      <category>template</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Django Enhance Password Policy</title>
      <dc:creator>ashrafZolkopli</dc:creator>
      <pubDate>Fri, 11 Jun 2021 11:38:10 +0000</pubDate>
      <link>https://dev.to/ashraf_zolkopli/django-enhance-password-policy-36f7</link>
      <guid>https://dev.to/ashraf_zolkopli/django-enhance-password-policy-36f7</guid>
      <description>&lt;h1&gt;
  
  
  Preface
&lt;/h1&gt;

&lt;p&gt;Django build in password policy are by itself provide a great basis toward making sure the password that the user choose is relatively strong enough that its hard to guess. &lt;/p&gt;

&lt;p&gt;Build in &lt;a href="https://docs.djangoproject.com/en/3.2/topics/auth/passwords/#enabling-password-validation"&gt;Password Validators&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FVzqoSBW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3v4sxde4jv6osdk22iw9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FVzqoSBW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3v4sxde4jv6osdk22iw9.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;however usually in a business setting, almost all company will have its own set of password policy that need fine grain control of what is acceptable and what is not.&lt;/p&gt;

&lt;p&gt;Things like password require 1 uppercase, 1 lowercase, 1 digit, and 1 special character or thing such as no repeated password for the last x number password change require a special kinda of password validator so that we can make it better. My go to password validator would be &lt;a href="https://github.com/fizista/django-password-validators"&gt;django-password-validators&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Django Password Validator
&lt;/h2&gt;

&lt;p&gt;Installing django-password-validators with the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipenv install django-password-validators
pipenv lock -r &amp;gt;requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuring the settings
&lt;/h2&gt;

&lt;p&gt;If you want to have only the password strength check, just use the  following in your settings.py file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt; &lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
     &lt;span class="p"&gt;...&lt;/span&gt;
     &lt;span class="s"&gt;'django_password_validators'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="p"&gt;...&lt;/span&gt;
 &lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;AUTH_PASSWORD_VALIDATORS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;'NAME'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'django_password_validators.password_character_requirements.password_validation.PasswordCharacterValidator'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'OPTIONS'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
             &lt;span class="s"&gt;'min_length_digit'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="s"&gt;'min_length_alpha'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="s"&gt;'min_length_special'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="s"&gt;'min_length_lower'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="s"&gt;'min_length_upper'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="s"&gt;'special_characters'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"~!@#$%^&amp;amp;*()_+{}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;:;'[]"&lt;/span&gt;
         &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;however if you need validator to check with the historical password&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt; &lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
     &lt;span class="p"&gt;...&lt;/span&gt;
     &lt;span class="s"&gt;'django_password_validators'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="s"&gt;'django_password_validators.password_history'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="p"&gt;...&lt;/span&gt;
 &lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;AUTH_PASSWORD_VALIDATORS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;'NAME'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'django_password_validators.password_history.password_validation.UniquePasswordsValidator'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'OPTIONS'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
             &lt;span class="c1"&gt;# How many recently entered passwords matter.
&lt;/span&gt;             &lt;span class="c1"&gt;# Passwords out of range are deleted.
&lt;/span&gt;             &lt;span class="c1"&gt;# Default: 0 - All passwords entered by the user. All password hashes are stored.
&lt;/span&gt;            &lt;span class="s"&gt;'last_passwords'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="c1"&gt;# Only the last 5 passwords entered by the user
&lt;/span&gt;        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# If you want, you can change the default hasher for the password history.
&lt;/span&gt;&lt;span class="n"&gt;DPV_DEFAULT_HISTORY_HASHER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'django_password_validators.password_history.hashers.HistoryHasher'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  End
&lt;/h2&gt;

&lt;p&gt;I think with django-password-validators package, we are now able to make sure that the user would atleast have a much harder password to crack.&lt;/p&gt;

</description>
      <category>django</category>
      <category>github</category>
      <category>template</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Better Django Hasher</title>
      <dc:creator>ashrafZolkopli</dc:creator>
      <pubDate>Fri, 11 Jun 2021 03:34:23 +0000</pubDate>
      <link>https://dev.to/ashraf_zolkopli/better-django-hasher-4418</link>
      <guid>https://dev.to/ashraf_zolkopli/better-django-hasher-4418</guid>
      <description>&lt;p&gt;Django support multiple password hash algorithm, however two hash that it support but not come out of the box are Argon2 and Bcrypt. This post will show how we can make for a better Django Password hasher our project. &lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Argon2 Library
&lt;/h2&gt;

&lt;p&gt;We can install the Argon2 library as follow&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipenv install django[argon2]
pipenv lock -r &amp;gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Update Settings
&lt;/h2&gt;

&lt;p&gt;in your settings.py just add the following line&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;PASSWORD_HASHERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s"&gt;'django.contrib.auth.hashers.Argon2PasswordHasher'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'django.contrib.auth.hashers.PBKDF2PasswordHasher'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'django.contrib.auth.hashers.BCryptSHA256PasswordHasher'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it and now your password is being hash with a much better password hasher.&lt;/p&gt;

&lt;h2&gt;
  
  
  End
&lt;/h2&gt;

&lt;p&gt;With just 2 simple steps, your user password is being hash with a better password hasher. Why not just implement this in your project, as you got nothing to loose and so many to gain.&lt;/p&gt;

</description>
      <category>django</category>
      <category>github</category>
      <category>template</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
