附近做app的公司重慶seo論壇
目錄
前言
1、驗(yàn)證碼
1.1、引入pom
1.2、前端核心代碼
1.3、后端核心代碼
2、賬戶凍結(jié)
2.1、思路:?
2.2、核心代碼示例:
3、密碼加密——加鹽算法
3.1、思路:
3.2、代碼實(shí)現(xiàn)示例:
4、小結(jié):展示我的項(xiàng)目
4.1、后端代碼:
4.2、效果展示:
前言
? ? ? ? ?前端代碼,我只展示核心代碼,其他的代碼需要小伙伴們自行編寫哦~
? ? ? ? 項(xiàng)目是Spring項(xiàng)目,需要小伙伴們有一點(diǎn)點(diǎn)Spring基礎(chǔ)~
? ? ? ? 我這些實(shí)現(xiàn)方式,只是一個(gè)參考,并不是最優(yōu)解~
1、驗(yàn)證碼
? ? ? ? 驗(yàn)證碼這里,我們使用的是easy-captcha,對(duì)他感興趣的伙伴,可以自行查一下資料,下面,我只實(shí)現(xiàn)4位驗(yàn)證碼,有字母和數(shù)字組成的這種~
1.1、引入pom
<!-- 驗(yàn)證碼 --><dependency><groupId>com.github.whvcse</groupId><artifactId>easy-captcha</artifactId><version>1.6.2</version></dependency>
1.2、前端核心代碼
準(zhǔn)備一個(gè)html:?
<div class="row"><input type="text" id="authCode" class="form-control" name="verifyCode" placeholder="請(qǐng)輸入驗(yàn)證碼" required="true"><img class="imgCode" alt="點(diǎn)擊圖片刷新!" src="/common/kaptcha" onclick="this.src='/common/kaptcha?d='+new Date()*1">
</div>
說明:
- 就是準(zhǔn)備了一個(gè)input輸入框,供我們輸入驗(yàn)證碼;準(zhǔn)備一個(gè)圖片,顯示我們的驗(yàn)證碼
- 重點(diǎn)要說的就是照片img標(biāo)簽中,src的路徑是一個(gè)URL,也就是說,這張照片的來源就是從這個(gè)URL來的;點(diǎn)擊照片時(shí),會(huì)觸發(fā)onclick事件,這個(gè)事件會(huì)改變?cè)搱D片src的屬性,新的src為:'/common/kaptcha?d='new Date()*1,這個(gè)表達(dá)式會(huì)生成一個(gè)新的日期時(shí)間戳,并將其附加到圖片的URL后面,從而獲取一個(gè)新的圖片~ 【src中的URL由后端實(shí)現(xiàn)~】
1.3、后端核心代碼
準(zhǔn)備一個(gè)controller類:?
package com.example.demo.controller;import com.wf.captcha.SpecCaptcha;
import com.wf.captcha.base.Captcha;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@Controller
@RequestMapping("/common")
public class commonCotroller {@GetMapping("/kaptcha")public void defaultKaptcha(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {httpServletResponse.setHeader("Cache-Control", "no-store");httpServletResponse.setHeader("Pragma", "no-cache");httpServletResponse.setDateHeader("Expires", 0);httpServletResponse.setContentType("image/gif");// 三個(gè)參數(shù)分別為寬、高、位數(shù)SpecCaptcha captcha = new SpecCaptcha(150, 30, 4);// 設(shè)置字體captcha.setCharType(Captcha.FONT_9);// 驗(yàn)證碼存入sessionhttpServletRequest.getSession().setAttribute("authCode", captcha.text().toLowerCase());// 輸出圖片流captcha.out(httpServletResponse.getOutputStream());}
}
?說明:
? ? ? ? 到這里,驗(yàn)證碼的模塊就實(shí)現(xiàn)完成了,具體,在登錄時(shí)如何操作的,下面第四點(diǎn)中會(huì)舉例說明~?
2、賬戶凍結(jié)
2.1、思路:?
? ? ? ? 關(guān)于賬戶凍結(jié),我是在數(shù)據(jù)庫(kù)設(shè)計(jì)中,給用戶表添加了兩個(gè)字段:狀態(tài)state和冷卻時(shí)間lTime。默認(rèn)的state值為1,默認(rèn)的lTime為0。當(dāng)用戶每登錄錯(cuò)誤一次時(shí),給該用戶的state加一;當(dāng)state大于3時(shí),表示該用戶已經(jīng)連續(xù)錯(cuò)誤登錄三次了,該賬戶將被凍結(jié);凍結(jié)時(shí)間設(shè)置:獲取現(xiàn)在的時(shí)間戳加上30000,換算成秒就是,給當(dāng)前時(shí)間加上30s;在登錄前,先驗(yàn)證給賬戶是否被凍結(jié)了,也就是查看當(dāng)前時(shí)間戳是否小于該用戶數(shù)據(jù)庫(kù)中存儲(chǔ)的凍結(jié)時(shí)間戳~
2.2、核心代碼示例:
@RequestMapping("/login")public AjaxResult login(HttpServletRequest request, String username, String password,String authCode) {//0.參數(shù)校驗(yàn)if(!StringUtils.hasLength(username) || username.length() > 50) {return AjaxResult.fail("用戶名輸入違法,請(qǐng)重新輸入!");}if(!StringUtils.hasLength(password) ||password.length() > 10) {return AjaxResult.fail("密碼輸入違法,請(qǐng)重新輸入!");}if(!StringUtils.hasLength(authCode)) {return AjaxResult.fail("驗(yàn)證碼不能為空!");}//1、校驗(yàn)驗(yàn)證碼是否正確相關(guān)操作// ...//2、驗(yàn)證該用戶的登錄功能是否被凍結(jié)//2.1、先根據(jù)用戶名查詢出數(shù)據(jù)中的username的信息Userinfo userinfo = userService.getUserExist(username);if(userinfo == null) {return AjaxResult.fail("用戶名或密碼錯(cuò)誤,請(qǐng)重新輸入~");}//2.2、查看該用戶的登錄功能是否被凍結(jié)了if(userinfo.getState() > 3 && userinfo.getLTime() > System.currentTimeMillis()) {return AjaxResult.fail("登錄已鎖定,請(qǐng)等待" + (userinfo.getLTime() - System.currentTimeMillis())/1000 + "秒后重試");} else if(userinfo.getState() > 3 && userinfo.getLTime() < System.currentTimeMillis()) {//放置state為1--時(shí)間過了,解除凍結(jié)userinfo.setState(1);userService.stateOne(userinfo);}//3、對(duì)比密碼是否正確相關(guān)操作// ...//3.3、可以正確登錄,將之間的state標(biāo)記恢復(fù)原狀userinfo.setState(1);userService.stateOne(userinfo);//4、可以正確登錄,后續(xù)操作// ....return AjaxResult.success("登陸成功");}
? ? ? ? ?上述代碼還是很好理解的,我就不做過多解釋了~
3、密碼加密——加鹽算法
? ? ? ? 我們準(zhǔn)備一個(gè)類,這個(gè)類主要就是處理密碼的加密和驗(yàn)證密碼操作。
3.1、思路:
- 1:我們使用UUID生成一個(gè)隨機(jī)鹽值;
- 2:密碼加工1:把密碼和鹽值加起來,然后使用MD5哈希算法進(jìn)行加密
- 3:密碼加工2:為了后續(xù)可以取出鹽值,從而來驗(yàn)證密碼是否正確,所以最終的密碼:鹽值 + "$"?+? 密碼加工1 【這里是以字符串的形式拼接的】
- 4:密碼驗(yàn)證:先通過$符,取出鹽值,再通過相同的加密方式加密,驗(yàn)證新密碼加密后的值是否與數(shù)據(jù)庫(kù)中的值相等~
3.2、代碼實(shí)現(xiàn)示例:
public class PasswordUtils {//密碼加鹽:public static String encrypt(String password) {//1、生成一個(gè)32位的鹽值String salt = UUID.randomUUID().toString().replace("-","");//2、生成加鹽后的密碼,并將鹽值和加鹽后的密碼并在一起return splicing(password,salt);}//驗(yàn)證密碼是否正確public static boolean check(String inputPassword,String finPassword) {//1、獲取saltString salt = finPassword.split("\\$")[0];//2、使用一樣的鹽值,加密String inputFinPassword = splicing(inputPassword,salt);if(inputFinPassword.equals(finPassword)) {return true;}return false;}//密碼加鹽的輔助方法private static String splicing(String password, String salt) {//1、使用md5生成加鹽后的密碼1String finpassword = DigestUtils.md5DigestAsHex((salt + password).getBytes());//2、返回最終密碼【鹽值 $ 密碼1】return (salt + "$" +finpassword);}
}
4、小結(jié):展示我的項(xiàng)目
????????上述重復(fù)的代碼,我就不展示了,展示一下,我的UserController類的實(shí)現(xiàn)吧~
4.1、后端代碼:
@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@RequestMapping("/login")public AjaxResult login(HttpServletRequest request, String username, String password,String authCode) {//0.參數(shù)校驗(yàn)if(!StringUtils.hasLength(username) || username.length() > 50) {return AjaxResult.fail("用戶名輸入違法,請(qǐng)重新輸入!");}if(!StringUtils.hasLength(password) ||password.length() > 10) {return AjaxResult.fail("密碼輸入違法,請(qǐng)重新輸入!");}if(!StringUtils.hasLength(authCode)) {return AjaxResult.fail("驗(yàn)證碼不能為空!");}//1、校驗(yàn)驗(yàn)證碼是否正確HttpSession session = request.getSession();//默認(rèn)為true,有則獲取,無則會(huì)先新建再獲取String trueAuthCode = (String) session.getAttribute("authCode");if(!trueAuthCode.equalsIgnoreCase(authCode)) {return AjaxResult.fail("驗(yàn)證碼輸入錯(cuò)誤!");}//2、驗(yàn)證該用戶的登錄功能是否被凍結(jié)//2.1、先根據(jù)用戶名查詢出數(shù)據(jù)中的username的信息Userinfo userinfo = userService.getUserExist(username);if(userinfo == null) {return AjaxResult.fail("用戶名或密碼錯(cuò)誤,請(qǐng)重新輸入~");}//2.2、查看該用戶的登錄功能是否被凍結(jié)了if(userinfo.getState() > 3 && userinfo.getLTime() > System.currentTimeMillis()) {return AjaxResult.fail("登錄已鎖定,請(qǐng)等待" + (userinfo.getLTime() - System.currentTimeMillis())/1000 + "秒后重試");} else if(userinfo.getState() > 3 && userinfo.getLTime() < System.currentTimeMillis()) {//放置state為1--時(shí)間過了,解除凍結(jié)userinfo.setState(1);userService.stateOne(userinfo);}//3、對(duì)比密碼是否正確if(!PasswordUtils.check(password,userinfo.getPassword())) {//3.1、如果密碼錯(cuò)誤,則數(shù)據(jù)庫(kù)中標(biāo)記+1userinfo.setState(userinfo.getState() + 1);//給數(shù)據(jù)庫(kù)中的state+1userService.stateOne(userinfo);//3.2、錯(cuò)誤次數(shù)達(dá)標(biāo),設(shè)置冷卻時(shí)間if(userinfo.getState() > 3) {userinfo.setLTime(System.currentTimeMillis() + 30000);userService.setLTime(userinfo);}return AjaxResult.fail("用戶名或密碼錯(cuò)誤,請(qǐng)重新輸入~");}//3.3、可以正確登錄,將之間的標(biāo)記恢復(fù)原狀userinfo.setState(1);userService.stateOne(userinfo);//4、可以正確登錄,給session中存儲(chǔ)給用戶的信息-放置session信息session.setAttribute(AppVariable.USER_SESSION_KEY,userinfo);//5、返回登陸成功return AjaxResult.success("登陸成功");}
}
? ? ? ? 前端代碼,我就不展示了~ 大家自行發(fā)揮~~~
4.2、效果展示:
?
????????好啦,本期就到這里咯,對(duì)效果展示中的彈窗感興趣的伙伴,可以看看持續(xù)關(guān)注我后續(xù)的動(dòng)態(tài),會(huì)出一個(gè)簡(jiǎn)單的教程?