1. Preface
By default, the login interface of django only has the user name and password input box, without additional security protection. If it is used directly without login verification code in the production environment, it is very dangerous, because attackers can constantly try to log in with specific programs until they get the correct login password. Therefore, login verification code must be added to increase the cost of website attack.
2. Customize the login page
2.1 creating django project
Create Django project with pychart. The project structure is as follows:
After creation, remember to run in the directory where manage.py is located:
python manage.py migrate
2.2 downloading plug-ins
First download the verify.js front-end login verification plug-in:
Extract the following directory structure:
two point three Copy djano login page template
Create the admin directory in templates (under the manage.py peer directory):
View the django package location using the following command:
python -c "import django; print(django.__path__)
Then find contrib\admin\templates\admin\login.html in this directory and copy it to templates/admin.
2.4 introducing verification plug-ins
First, create a static/admin folder under the manage.py peer directory to save the global static files related to management, and then create three directories under this folder: js, css and image.
Find verify.css in the extracted plug-in folder and copy it to the static/admin/css you just created. Then copy all js files in the plugin folder js folder to static/admin/js. Copy the two sample pictures to static/admin/image:
Modify the static file settings in settings:
STATICFILES_DIRS = [ BASE_DIR / "static", "static/admin" ]
In this way, the plug-in can be introduced in the following ways:
<link rel="stylesheet" href="{% static "css/verify.css"%}"> <script type="text/javascript" src="{% static "js/jquery-1.11.0.min.js"%}"></script> <script type="text/javascript" src="{% static "js/verify.js" %}"></script>
3. Custom login template
In order to flexibly use different verification codes, Django's template inheritance is used here (see Template inheritance ), define a login skeleton template and abstract the verification code into a block, so as to realize flexible replacement.
3.1 define login skeleton template
Open the previously copied login.html, find the location as shown in the figure, and add a verify_code block:
Then override the extrahead block of the basic admin template and introduce the Verify.js plug-in:
Then change the name of the template to login_base.html as the login skeleton template:
3.2 add verification code
Create a new login.html template in the templates/admin directory as the real page login template:
Overwrite the verify we defined earlier in this template_ Code block:
login.html
{#Inherit basic login template#} {% extends "admin/login_base.html" %} {% load i18n static %} {#Overwrite the verification code block in the basic login template verify_code#} {% block verify_code %} <div class="form-row"> <label class="required">Verification Code:</label> <div id="mpanel2"></div> </div> <script type="text/javascript"> $('#mpanel2').codeVerify({ //1 is the ordinary character verification code and 2 is the arithmetic verification code type: 1, fontSize: '30px', codeLength: 6, btnId: 'check-btn', ready: function () { }, success: function () { alert('Verify match!'); }, error: function () { alert('Verification code mismatch!'); } }); </script> {% endblock %}
effect
If you find any confusion in the interface style, modify and open verify.js, and find:
Modify the width in the default parameter to 99%. Find again
Modify the variable panelHtml to
var panelHtml = '<div class="cerify-code-panel"><div class="verify-code"></div><div class="verify-code-area"><input type="text" class="varify-input-code" /><a class="verify-change-code">Change one</a></div></div>';
Open verify.css and find
Change it to
.cerify-code-panel { height: 100%; overflow: hidden; } .verify-code-area { width: 100%; justify-items: stretch; } .varify-input-code { width: 80%; height: 25px; } .verify-change-code { width: 20%; color: #337AB7; cursor: pointer; margin-left: 10px; text-align: center; }
Modified effect
be careful
When debugging a web page, close the network cache first, otherwise the previously cached css file will always be displayed when refreshing the page, resulting in debugging difficulties. chrome closes the network cache and checks disable cache under the network Tab of the debugging window, So does Edge. Remember to close it after debugging, otherwise it will cost a lot of traffic.
4. Add verification code interference
4.1 security issues
The common verification code of verify.js is very clear and easy to be recognized by OCR, and the content of the verification code can be read through html tags, so it is still very unsafe. Therefore, it is best to change the verification code to draw with canvas:
4.2 modify the verify.js source code
(1) Modify constructor
(2) Modify loadDom
const panelHtml = '<div class="vertify-code-panel">' + '<div class="verify-code-area">' + '<canvas class="verify-code" width="200" height="60" id="verify-code"></canvas>' + '<a class="verify-change-code">Change one</a>' + '</div>' + '<input type="text" class="varify-input-code" />' + '</div>'; ......
(3) Add drawing function
Add randNum, randColor, drawbg, drawLine, drawCircle and drawExpression methods to the Code class:
//Method of defining Code Code.prototype = { init: function () { ...... }, //Load page loadDom: function () { ...... }, /** * Generate a random number * @param min minimum value * @param max Maximum * @returns {*} */ ranNum: function (min, max) { return Math.random() * (max - min) + min; }, /** * Returns a random color to set the color range * @param {number} min [Lower color limit] * @param {number} max [Upper color limit] * @return {string} [Random color] */ ranColor: function (min, max) { const r = this.ranNum(min, max); const g = this.ranNum(min, max); const b = this.ranNum(min, max); return `rgb(${r},${g},${b})`; }, //Draw background drawBg: function (min, max) { // Draw canvas background this.ctx.fillStyle = this.ranColor(min, max); // fill color this.ctx.fillRect(0, 0, this.ctxW, this.ctxH); }, /** * Draw interference dots * @param {number} num [Number of drawings] * @param {number} r [Dot radius] * @param {number} min [Lower limit] * @param {number} max [Online] */ drawCircle: function (num, r, min, max) { for (let i = 0; i < num; i++) { // Start drawing (pick up the pen) this.ctx.beginPath(); // context.arc(x,y,r,sAngle,eAngle,counterclockwise); (draw) // The x coordinate of the center of the x circle. // The y coordinate of the center of the y circle. // r is the radius of the circle. // sAngle starting angle, in radians. (the three o'clock position of the circle of the arc is 0 degrees). // Eagle end angle in radians. // Counter clockwise optional. Specifies whether the drawing should be counterclockwise or clockwise. False = clockwise, true = counterclockwise. this.ctx.arc(this.ranNum(0, this.ctxW), this.ranNum(0, this.ctxH), r, 0, 2 * Math.PI); // fill color this.ctx.fillStyle = this.ranColor(min, max); // fill this.ctx.fill(); // Close draw (release pen) this.ctx.closePath(); } }, /** * Draw interference line segment * @param {number} num [Number of drawings] * @param {number} min [Lower limit] * @param {number} max [Online] */ drawLine: function (num, min, max) { for (let i = 0; i < num; i++) { // Start drawing (pick up the pen) this.ctx.beginPath(); // Draw start point this.ctx.moveTo(this.ranNum(0, this.ctxW), this.ranNum(0, this.ctxH)); // Draw end point this.ctx.lineTo(this.ranNum(0, this.ctxW), this.ranNum(0, this.ctxH)); this.ctx.strokeStyle = this.ranColor(min, max); this.ctx.stroke(); this.ctx.closePath(); } }, //Draw an arithmetic expression drawExpression: function (expression) { const fs = this.randNum(20, 50); this.ctx.font = fs + "px Verdana"; this.ctx.fillStyle = this.randColor(0, 100); // X value added to the horizontal coordinate (x) // Y value added to the vertical coordinate (y) // deviation for (let i = 0; i < expression.length; i++) { const fs = this.randNum(20, 50); this.ctx.font = fs + "px Verdana"; this.ctx.fillStyle = this.randColor(0, 100); // Save the state of the drawing this.ctx.save(); // X value added to the horizontal coordinate (x) // Y value added to the vertical coordinate (y) // deviation this.ctx.translate(this.ctxW / expression.length * i + this.ctxW / 20, 0); // Change angle this.ctx.rotate(this.randNum(-30, 30,) * Math.PI / 180); // Textspecifies the text to output on the canvas. // x the x coordinate position (relative to the canvas) where the text begins to be drawn. // y is the y coordinate position (relative to the canvas) where the text begins to be drawn. // maxWidth is optional. The maximum text width allowed, in pixels. this.ctx.fillText(expression[i], 0, (this.ctxH + fs) / 2.5, this.ctxW / expression.length); // Returns previously saved path States and properties this.ctx.restore(); } //Set verification code setCode: function () { ....... }, ...... };
(4) Modify the verification code generation method setCode
//Set verification code setCode: function () { // Empty canvas this.ctx.clearRect(0, 0, this.ctxW, this.ctxH); //Draw background this.drawBg(200, 255); //Draw interference lines this.drawLine(20, 0, 255); //Draw interference dots this.drawCircle(20, 5, 200, 255); const color1Num = Math.floor(Math.random() * 3); const color2Num = Math.floor(Math.random() * 5); this.htmlDoms.code.css({'background-color': _code_color1[color1Num], 'color': _code_color2[color2Num]}); this.htmlDoms.code_input.val(''); this.code_chose = ''; if (this.options.type === 1) { //Add common verification code character for (let i = 0; i < this.options.codeLength; i++) { //Select a character at random const charNum = Math.floor(Math.random() * 52); let char = _code_chars[charNum] const fs = this.randNum(20, 50); this.ctx.font = fs + "px Verdana"; this.ctx.fillStyle = this.randColor(0, 100); // Save the state of the drawing this.ctx.save(); // X value added to the horizontal coordinate (x) // Y value added to the vertical coordinate (y) // deviation this.ctx.translate(this.ctxW / this.options.codeLength * i + this.ctxW / 20, 0); // Change angle this.ctx.rotate(this.randNum(-30, 30,) * Math.PI / 180); // Textspecifies the text to output on the canvas. // x the x coordinate position (relative to the canvas) where the text begins to be drawn. // y is the y coordinate position (relative to the canvas) where the text begins to be drawn. // maxWidth is optional. The maximum text width allowed, in pixels. this.ctx.fillText(char, 0, (this.ctxH + fs) / 2.5, this.ctxW / this.options.codeLength); // Returns previously saved path States and properties this.ctx.restore(); //Add to the selected verification code this.code_chose += _code_chars[charNum]; } } else { //Algorithm verification code let num1 = Math.floor(Math.random() * this.options.figure); let num2 = Math.floor(Math.random() * this.options.figure); //Choose an arithmetic at random if (this.options.arith === 0) { var tmparith = Math.floor(Math.random() * 3); } //Sequence to draw let code = [] switch (tmparith) { case 1 : //addition this.code_chose = parseInt(String(num1)) + parseInt(String(num2)); code.push(String(num1)) code.push("+") code.push(String(num2)) code.push("=") code.push('?') this.drawExpression(code) break; case 2 : //Subtract to make sure there are no negative numbers in the subtraction if (parseInt(String(num1)) < parseInt(String(num2))) { var tmpnum = num1; num1 = num2; num2 = tmpnum; } this.code_chose = parseInt(String(num1)) - parseInt(String(num2)); code.push(String(num1)) code.push("-") code.push(String(num2)) code.push("=") code.push('?') this.drawExpression(code) break; default : //multiplication this.code_chose = parseInt(String(num1)) * parseInt(String(num2)); code.push(String(num1)) code.push("×") code.push(String(num2)) code.push("=") code.push('?') this.drawExpression(code) break; } } },
(5) Modify verify.css
/*General verification code*/ .verify-code { text-align: center; cursor: pointer; border: 1px solid #ddd; } .verify-code-panel { height: 100%; overflow: hidden; } .verify-code-area { width: 100%; display: flex; justify-items: stretch; justify-content: flex-start; align-items: center; flex-direction: row; margin-bottom: 5px; } .varify-input-code { width: 100%; height: 25px; } .verify-change-code { width: 20%; color: #337AB7; cursor: pointer; margin-left: 10px; text-align: center; } ......