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