vue+springboot實現(xiàn)圖形驗證碼Kaptcha的示例
1、前端
form使用了element-ui的組件,主要還是看img標簽,src綁定了form.imgCodeUrl數(shù)據(jù),點擊圖片時觸發(fā)refreshCode更新圖片驗證碼。
<el-form-item prop="verificationCode" label="驗證碼" style="text-align: left;"> <el-input v-model="form.verificationCode" placeholder="請輸入驗證碼" style="width: 120px;vertical-align: top;"></el-input> <img id="img" alt="驗證碼" @click="refreshCode" :src="form.imgCodeUrl" style="padding-left: 12px;"/> </el-form-item>
data() { return { form: { username: '', password: '', verificationCode:'', imgCodeUrl:this.$verificationCodeUrl, }, ... ... refreshCode(){ this.form.imgCodeUrl=this.$verificationCodeUrl+"?d="+new Date().getTime(); }
上面refreshCode更新圖片驗證碼的原理,其實就是在原網(wǎng)址后添加隨機的參數(shù)來改變form.imgCodeUrl網(wǎng)址,實現(xiàn)img標簽自動刷新請求。
- this.$verificationCodeUrl是請求的網(wǎng)址,這里設(shè)置成全局常量寫在了main.js中
//驗證碼地址 Vue.prototype.$verificationCodeUrl="http://127.0.0.1/api/createImageCode";
2、后端實現(xiàn)生成createImageCode驗證碼圖片
使用kaptcha生成圖片驗證碼,添加如下依賴
<dependency> <groupId>com.github.penggle</groupId> <artifactId>kaptcha</artifactId> <version>2.3.2</version> </dependency>
配置kaptcha圖片生成規(guī)則
... import java.util.Properties; @Configuration public class KaptchaConfig { @Bean public DefaultKaptcha getDefaultKaptcha() { DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); Properties properties = new Properties(); // 圖片寬 properties.setProperty("kaptcha.image.width", "130"); // 圖片高 properties.setProperty("kaptcha.image.height", "50"); // 圖片邊框 properties.setProperty("kaptcha.border", "yes"); // 邊框顏色 properties.setProperty("kaptcha.border.color", "105,179,90"); // 字體顏色 properties.setProperty("kaptcha.textproducer.font.color", "blue"); // 字體大小 properties.setProperty("kaptcha.textproducer.font.size", "40"); // session key properties.setProperty("kaptcha.session.key", "imageCode"); // 驗證碼長度 properties.setProperty("kaptcha.textproducer.char.length", "4"); // 字體 properties.setProperty("kaptcha.textproducer.font.names", "宋體,楷體,微軟雅黑"); Config config = new Config(properties); defaultKaptcha.setConfig(config); return defaultKaptcha; } }
生成驗證碼的圖片通過response.getOutputStream流發(fā)送到前端,而驗證碼保存到session域中,等待用戶登錄表單提交時進行校驗匹對
... @Autowired private DefaultKaptcha defaultKaptcha; ... //生成圖片驗證碼 @GetMapping("/createImageCode") public void createImageCode(HttpServletRequest request,HttpServletResponse response) { response.setHeader("Cache-Control", "no-store, no-cache"); response.setContentType("image/jpeg"); // 生成文字驗證碼 String text = defaultKaptcha.createText(); // 生成圖片驗證碼 BufferedImage image = defaultKaptcha.createImage(text); //保存到session域 HttpSession session = request.getSession(); session.setAttribute("imageCode",text); ServletOutputStream out = null; try { //響應(yīng)輸出圖片流 out = response.getOutputStream(); ImageIO.write(image, "jpg", out); } catch (IOException e) { e.printStackTrace(); } finally { try { out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); } } }
3、前端提交表單
代碼有點長,其實是嵌套了三層,第一層if (valid)判斷表單校驗(填入的數(shù)據(jù)是否符合規(guī)則),第二層this. h t t p . g e t ( " / v e r i f y I m a g e C o d e " 提交驗證碼判斷驗證碼是否正確,第三層 t h i s . http.get("/verifyImageCode"提交驗證碼判斷驗證碼是否正確,第三層this. http.get("/verifyImageCode"提交驗證碼判斷驗證碼是否正確,第三層this.http.post("/user/login"最后判斷用戶名和密碼是否正確,三層邏輯都通過才保存用戶登錄信息。
submitForm() { this.$refs.form.validate(valid => { //表單校驗通過 if (valid) { //先判斷圖形驗證碼 this.$http.get("/verifyImageCode",{params:{verificationCode:this.form.verificationCode}}) .then((response)=>{ //圖形驗證碼成功 if(response.data.code === 0){ //判斷用戶名和密碼 this.$http.post("/user/login",{ username:this.form.username, password:this.form.password }) .then((response)=>{ if(response.data.code === 0){//登錄成功 this.$message({ message: '登錄成功', type: 'success', }); localStorage.setItem("user",JSON.stringify(response.data.data));//保存用戶信息 this.$router.push("/"); } else{ this.$message.error("用戶名或密碼錯誤,請重試?。?!"); } }) .catch((error)=>{ //未接受到response的網(wǎng)絡(luò)傳輸?shù)儒e誤 console.log(error); }); }else{//圖形驗證碼錯誤 this.$message.error(response.data.data.message); return; } }) .catch((error)=>{ //未接受到response的網(wǎng)絡(luò)傳輸?shù)儒e誤 console.log(error); return; }); } else { this.$message.error('表單填寫錯誤,請檢查'); return false; } }); },
4、后端/verifyImageCode驗證碼匹對
CommonResult是自定義的返回數(shù)據(jù)結(jié)果類,可以搜我以前文章。前端傳來的驗證碼與session域中的匹對。
//匹對圖片驗證碼 @GetMapping("/verifyImageCode") public CommonResult<Object> verifyImageCode(String verificationCode,HttpServletRequest request) { HttpSession session = request.getSession(); if(session.getAttribute("imageCode").equals(verificationCode)) { return CommonResult.success(); }else { return CommonResult.failed(ErrorCode.IMG_CODE_VERIFY_ERROR.getCode(), Message.createMessage(ErrorCode.IMG_CODE_VERIFY_ERROR.getMessage())); } }
5、bug
測試時,驗證碼圖片能夠生成顯示,并能刷新。但提交表單時,對/verifyImageCode的請求返回錯誤碼500。
首先打印發(fā)現(xiàn)session域的值為null。了解到原來session會話是有唯一的session id。打印session id,發(fā)現(xiàn)每次請求session id的不一樣。session id其實是存在在cookie里的。
所以前端發(fā)送請求時要攜帶cookie證書,vue配置
//攜帶證書 session id axios.defaults.withCredentials = true
后端的跨域配置也要允許證書通行
//配置跨域過濾器CorsFilter @Configuration public class CorsConfig { @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); //允許證書 CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.setAllowCredentials(true); List<String> list = Arrays.asList("*"); corsConfiguration.setAllowedHeaders(list); corsConfiguration.setAllowedMethods(list); corsConfiguration.setAllowedOriginPatterns(list); source.registerCorsConfiguration("/**", corsConfiguration); CorsFilter corsFilter = new CorsFilter(source); return corsFilter; } }
還沒完,請求還是返回500。瀏覽器調(diào)試器顯示如下
請求頭中已經(jīng)帶cookie,然而響應(yīng)頭又set-cookie了,也就是cookie里的session id又被重置,為什么這樣子?可能是感嘆號報錯的原因:set-cookie默認屬性是"SameSite=Lax,"。參考網(wǎng)上文章,我們修改后端配置application.properties:
#獲取同一個session id的cookie設(shè)置 server.servlet.session.cookie.secure=true server.servlet.session.cookie.same-site=none
再運行起來,set-cookie和感動號消失,調(diào)試通過。
參考文章:vue+springboot實現(xiàn)登錄驗證碼
到此這篇關(guān)于vue+springboot實現(xiàn)圖形驗證碼Kaptcha的示例的文章就介紹到這了,更多相關(guān)vue+springboot 圖形驗證碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
elementUI select組件默認選中效果實現(xiàn)的方法
這篇文章主要介紹了elementUI select組件默認選中效果實現(xiàn)的方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03使用Vue3進行數(shù)據(jù)綁定及顯示列表數(shù)據(jù)
這篇文章主要介紹了使用Vue3進行數(shù)據(jù)綁定及顯示列表數(shù)據(jù),整篇文章圍繞Vue3進行數(shù)據(jù)綁定及顯示列表數(shù)據(jù)的想換自來哦展開內(nèi)容,需要的小伙伴可以參考一下2021-10-10vue中使用vue-pdf組件實現(xiàn)文件預(yù)覽及相應(yīng)報錯解決
在需求中,經(jīng)常遇見pdf的在線預(yù)覽效果,很多pdf插件不支持vue3,或者是沒有集成翻頁放大縮小功能,比如vue-pdf,下面這篇文章主要給大家介紹了關(guān)于vue中使用vue-pdf組件實現(xiàn)文件預(yù)覽及相應(yīng)報錯解決的相關(guān)資料,需要的朋友可以參考下2022-09-09vue2.0實現(xiàn)移動端的輸入框?qū)崟r檢索更新列表功能
最近小編在做vue2.0的項目,遇到移動端實時檢索搜索更新列表的效果,下面腳本之家小編給大家?guī)砹藇ue2.0 移動端的輸入框?qū)崟r檢索更新列表功能的實例代碼,感興趣的朋友參考下吧2018-05-05基于vue-cli vue-router搭建底部導(dǎo)航欄移動前端項目
這篇文章主要介紹了基于vue-cli vue-router搭建底部導(dǎo)航欄移動前端項目,項目中主要用了Flex布局,以及viewport相關(guān)知識,已達到適應(yīng)各終端屏幕的目的。需要的朋友可以參考下2018-02-02