Talk part
Today we are going to talk about how to make a more reasonable login verification code in actual project operations. First, let’s talk about the following issues:
1. Is verification code verification necessary when logging in?
The answer is of course necessary, because user login behavior will directly affect the database. If there are no certain preventive measures and a malicious user violently cracks the password, it will be very serious. Verification code verification is a way to prevent the interface from being swiped. , which can greatly reduce the frequency of interface requests.
There are also some systems that add password verification. When the number of incorrect passwords exceeds n times, the user will be locked and will not be allowed to log in within a specified period of time.
In addition, user interface current limiting is also a solution. Friends can try it by themselves.
2. Is verification code verification a front-end behavior or a server-side behavior?
Both methods are possible, the differences are as follows
Front-end behavior: It can only guarantee the verification effect when operating the front-end page, but cannot guarantee the security of the interface. Users can skip the page and directly access the server interface, which is not recommended.
Server behavior: It can ensure the security of the login interface, limit the frequency of user login, and can cooperate with measures such as user IP traffic limit and password error prevention, etc. It is recommended
3. After the verification code is generated, where should the server be stored? What problems will there be?
When learning jsp + servlet, user information is usually stored in the session on the server side, and the verification code can also be stored in the session, but it is feasible for a single instance. If there are multiple instances, session sharing or the rules of ip_hash need to be implemented.
It can be stored in a distributed cache, without the problem of multiple instances or the need to solve the problem of session sharing.
4. How to implement distributed verification code verification to ensure login security?
First, the server provides an interface for obtaining the verification code. The output parameters include key and code (code is the actual verification code, key is the key stored in Redis). Before returning the verification code, the verification code is stored in redis.
After the front-end receives the verification code, it uses canvas to draw the verification code. After the user manually enters the verification code, the user name, password, verification code, and key are passed to the server to log in.
After receiving the login request, the server queries redis, compares it with the verification code entered by the user, and logs in after passing the comparison.
Back to business
Verification code verification is the first barrier for user login. If the verification is not passed, no login will be performed and the database will not be contacted.
1. Import verification code dependencies, and add other dependencies by yourself, requiring redis and hutool-all.
<dependency> <groupId>com.github.penggle</groupId> <artifactId>kaptcha</artifactId> <version>2.3.2</version> </dependency>
2. Configure kaptcha
/* * @Project:cxs-currency-sys-server * @Author:cxs * @Motto: Let go of distracting thoughts, just to welcome a better self tomorrow * */ @Configuration public class KaptchaConfig {<!-- --> private static final String CHAR_STR = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; private static final String CHAR_LENGTH = "4"; @Bean public Producer captcha() {<!-- --> //Configure the basic parameters of the graphic verification code Properties properties = new Properties(); // character set properties.setProperty("kaptcha.textproducer.char.string", CHAR_STR); //Character length properties.setProperty("kaptcha.textproducer.char.length", CHAR_LENGTH); Config config = new Config(properties); DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); defaultKaptcha.setConfig(config); return defaultKaptcha; } }
3. Generate verification code core code
public void getValidateCode(BaseResult result) {<!-- --> long startTime = System.currentTimeMillis(); try {<!-- --> //Create verification code text ValidateCodeVO vo = new ValidateCodeVO(); String key = IdUtil.simpleUUID(); String code = captchaProducer.createText(); redisUtil.set(redisUtil.getCacheKey(CachePrefixContent.VALIDATE_CODE_PREFIX, key), code, commonConfig.getCodePeriod(), TimeUnit.SECONDS); vo.setKey(key); vo.setCode(code); result.setData(vo); } catch (Exception e) {<!-- --> log.error("Failed to generate verification code,{}", e); result.setCode(CurrencyErrorEnum.OPERA_ERROR.getCode()); result.setMsg(CurrencyErrorEnum.OPERA_ERROR.getMsg()); } finally {<!-- --> long endTime = System.currentTimeMillis(); log.info("[{}][Generate verification code interface][{}ms] \\ Input parameters:{}\\ Output parameters:{}", "Generate verification code", endTime - startTime, null, result); } }
4. Interface parameter preview
{<!-- --> "code": 200, "data": {<!-- --> "code": "2972", "key": "a23030e821384684a47912fac215cfb1" }, "msg": "Operation successful" }
5. Front-end implementation of the main code (note: part of the code of the login box)
<el-form-item prop="code"> <el-row :gutter="20"> <el-col :span="12"> <el-input ref="code" type="text" prefix-icon="el-icon-key" v-model="userInfo.code" placeholder="Verification Code" name="code" tabindex="2" autocomplete="on" @keyup.enter.native="loginHandle"/> </el-col> <el-col :span="6" :offset="3"> <canvas ref="canvas" :width="codeInfo.codeWidth" :height="codeInfo.codeHeight" @click="reloadCode"></canvas> </el-col> </el-row> </el-form-item>
6. Required functions
//Create verification code async createdCode() {<!-- --> //Call the above interface to generate const res = await getValidateCode() const {<!-- -->code, data, msg} = res this.userInfo.codeKey = data.key const identifyCode = data.code const codeList = identifyCode.split(""); const canvas = this.$refs.canvas;//Get the canvas element const ctx = canvas.getContext('2d'); ctx.textBaseline = 'bottom'; if (this.backgroundColor != '' & amp; & amp; this.backgroundColor != null) {<!-- -->// Draw the canvas background color ctx.fillStyle = this.backgroundColor; } else {<!-- --> ctx.fillStyle = this.randomColor(255, 255); } ctx.fillRect(0, 0, this.contentWidth, this.contentHeight); codeList.forEach((code, i) => {<!-- -->// Draw verification code characters this.drawText(ctx, code, i + 1, identifyCode.length); }) this.drawLine(ctx);//Draw interference line this.drawDot(ctx);//Draw interference points }, randomNum(min, max) {<!-- -->// Generate a random integer within the specified range return Math.floor(Math.random() * (max - min) + min); }, randomColor(min, max) {<!-- -->// Generate random colors within the specified range const r = this.randomNum(min, max); const g = this.randomNum(min, max); const b = this.randomNum(min, max); return `rgb(${<!-- -->r},${<!-- -->g},${<!-- -->b})`; }, drawText(ctx, txt, i, len) {<!-- -->// Draw verification code characters ctx.fillStyle = this.randomColor(0, 160); ctx.font = `${<!-- -->this.randomNum(25, 30)}px SimHei`; const x = (i / (len + 1)) * 120; const y = this.randomNum(30, 35); const deg = this.randomNum(-45, 45); ctx.translate(x, y); ctx.rotate((deg * Math.PI) / 180); ctx.fillText(txt, 0, 0); ctx.rotate((-deg * Math.PI) / 180); ctx.translate(-x, -y); }, drawLine(ctx) {<!-- -->// Draw interference lines for (let i = 0; i < 5; i + + ) {<!-- --> ctx.strokeStyle = this.randomColor(100, 255); ctx.beginPath(); ctx.moveTo(this.randomNum(0, 120), this.randomNum(0, 40)); ctx.lineTo(this.randomNum(0, 120), this.randomNum(0, 40)); ctx.stroke(); } }, drawDot(ctx) {<!-- -->// Draw interference points for (let i = 0; i < 80; i + + ) {<!-- --> ctx.fillStyle = this.randomColor(0, 255); ctx.beginPath(); ctx.arc(this.randomNum(0, 120), this.randomNum(0, 40), 1, 0, 2 * Math.PI); ctx.fill(); } }, reloadCode() {<!-- -->//Clear the canvas and regenerate the verification code when the button is clicked const canvas = this.$refs.canvas const ctx = canvas.getContext('2d') ctx.clearRect(0, 0, canvas.width, canvas.height) this.createdCode() },
7. Effect display
Conclusion
1. The verification code function has been implemented, go and arrange your projects!
2. It’s not easy to make. Just click three times and then go. Your support will always be my biggest motivation!