vue+springboot實(shí)現(xiàn)圖形驗(yàn)證碼Kaptcha的示例
1、前端
form使用了element-ui的組件,主要還是看img標(biāo)簽,src綁定了form.imgCodeUrl數(shù)據(jù),點(diǎn)擊圖片時(shí)觸發(fā)refreshCode更新圖片驗(yàn)證碼。
<el-form-item prop="verificationCode" label="驗(yàn)證碼" style="text-align: left;"> <el-input v-model="form.verificationCode" placeholder="請(qǐng)輸入驗(yàn)證碼" style="width: 120px;vertical-align: top;"></el-input> <img id="img" alt="驗(yàn)證碼" @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更新圖片驗(yàn)證碼的原理,其實(shí)就是在原網(wǎng)址后添加隨機(jī)的參數(shù)來(lái)改變form.imgCodeUrl網(wǎng)址,實(shí)現(xiàn)img標(biāo)簽自動(dòng)刷新請(qǐng)求。
- this.$verificationCodeUrl是請(qǐng)求的網(wǎng)址,這里設(shè)置成全局常量寫(xiě)在了main.js中
//驗(yàn)證碼地址 Vue.prototype.$verificationCodeUrl="http://127.0.0.1/api/createImageCode";
2、后端實(shí)現(xiàn)生成createImageCode驗(yàn)證碼圖片
使用kaptcha生成圖片驗(yàn)證碼,添加如下依賴(lài)
<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");
// 驗(yàn)證碼長(zhǎng)度
properties.setProperty("kaptcha.textproducer.char.length", "4");
// 字體
properties.setProperty("kaptcha.textproducer.font.names", "宋體,楷體,微軟雅黑");
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
}
生成驗(yàn)證碼的圖片通過(guò)response.getOutputStream流發(fā)送到前端,而驗(yàn)證碼保存到session域中,等待用戶(hù)登錄表單提交時(shí)進(jìn)行校驗(yàn)匹對(duì)
...
@Autowired
private DefaultKaptcha defaultKaptcha;
...
//生成圖片驗(yàn)證碼
@GetMapping("/createImageCode")
public void createImageCode(HttpServletRequest request,HttpServletResponse response) {
response.setHeader("Cache-Control", "no-store, no-cache");
response.setContentType("image/jpeg");
// 生成文字驗(yàn)證碼
String text = defaultKaptcha.createText();
// 生成圖片驗(yàn)證碼
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、前端提交表單
代碼有點(diǎn)長(zhǎng),其實(shí)是嵌套了三層,第一層if (valid)判斷表單校驗(yàn)(填入的數(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 " 提交驗(yàn)證碼判斷驗(yàn)證碼是否正確,第三層 t h i s . http.get("/verifyImageCode"提交驗(yàn)證碼判斷驗(yàn)證碼是否正確,第三層this. http.get("/verifyImageCode"提交驗(yàn)證碼判斷驗(yàn)證碼是否正確,第三層this.http.post("/user/login"最后判斷用戶(hù)名和密碼是否正確,三層邏輯都通過(guò)才保存用戶(hù)登錄信息。
submitForm() {
this.$refs.form.validate(valid => {
//表單校驗(yàn)通過(guò)
if (valid) {
//先判斷圖形驗(yàn)證碼
this.$http.get("/verifyImageCode",{params:{verificationCode:this.form.verificationCode}})
.then((response)=>{
//圖形驗(yàn)證碼成功
if(response.data.code === 0){
//判斷用戶(hù)名和密碼
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));//保存用戶(hù)信息
this.$router.push("/");
}
else{
this.$message.error("用戶(hù)名或密碼錯(cuò)誤,請(qǐng)重試?。。?);
}
})
.catch((error)=>{
//未接受到response的網(wǎng)絡(luò)傳輸?shù)儒e(cuò)誤
console.log(error);
});
}else{//圖形驗(yàn)證碼錯(cuò)誤
this.$message.error(response.data.data.message);
return;
}
})
.catch((error)=>{
//未接受到response的網(wǎng)絡(luò)傳輸?shù)儒e(cuò)誤
console.log(error);
return;
});
} else {
this.$message.error('表單填寫(xiě)錯(cuò)誤,請(qǐng)檢查');
return false;
}
});
},
4、后端/verifyImageCode驗(yàn)證碼匹對(duì)
CommonResult是自定義的返回?cái)?shù)據(jù)結(jié)果類(lèi),可以搜我以前文章。前端傳來(lái)的驗(yàn)證碼與session域中的匹對(duì)。
//匹對(duì)圖片驗(yàn)證碼
@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
測(cè)試時(shí),驗(yàn)證碼圖片能夠生成顯示,并能刷新。但提交表單時(shí),對(duì)/verifyImageCode的請(qǐng)求返回錯(cuò)誤碼500。
首先打印發(fā)現(xiàn)session域的值為null。了解到原來(lái)session會(huì)話(huà)是有唯一的session id。打印session id,發(fā)現(xiàn)每次請(qǐng)求session id的不一樣。session id其實(shí)是存在在cookie里的。
所以前端發(fā)送請(qǐng)求時(shí)要攜帶cookie證書(shū),vue配置
//攜帶證書(shū) session id axios.defaults.withCredentials = true
后端的跨域配置也要允許證書(shū)通行
//配置跨域過(guò)濾器CorsFilter
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
//允許證書(shū)
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;
}
}
還沒(méi)完,請(qǐng)求還是返回500。瀏覽器調(diào)試器顯示如下

請(qǐng)求頭中已經(jīng)帶cookie,然而響應(yīng)頭又set-cookie了,也就是cookie里的session id又被重置,為什么這樣子?可能是感嘆號(hào)報(bào)錯(cuò)的原因:set-cookie默認(rèn)屬性是"SameSite=Lax,"。參考網(wǎng)上文章,我們修改后端配置application.properties:
#獲取同一個(gè)session id的cookie設(shè)置 server.servlet.session.cookie.secure=true server.servlet.session.cookie.same-site=none
再運(yùn)行起來(lái),set-cookie和感動(dòng)號(hào)消失,調(diào)試通過(guò)。
參考文章:vue+springboot實(shí)現(xiàn)登錄驗(yàn)證碼
到此這篇關(guān)于vue+springboot實(shí)現(xiàn)圖形驗(yàn)證碼Kaptcha的示例的文章就介紹到這了,更多相關(guān)vue+springboot 圖形驗(yàn)證碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
elementUI select組件默認(rèn)選中效果實(shí)現(xiàn)的方法
這篇文章主要介紹了elementUI select組件默認(rèn)選中效果實(shí)現(xiàn)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03
使用Vue3進(jìn)行數(shù)據(jù)綁定及顯示列表數(shù)據(jù)
這篇文章主要介紹了使用Vue3進(jìn)行數(shù)據(jù)綁定及顯示列表數(shù)據(jù),整篇文章圍繞Vue3進(jìn)行數(shù)據(jù)綁定及顯示列表數(shù)據(jù)的想換自來(lái)哦展開(kāi)內(nèi)容,需要的小伙伴可以參考一下2021-10-10
vue中使用vue-pdf組件實(shí)現(xiàn)文件預(yù)覽及相應(yīng)報(bào)錯(cuò)解決
在需求中,經(jīng)常遇見(jiàn)pdf的在線(xiàn)預(yù)覽效果,很多pdf插件不支持vue3,或者是沒(méi)有集成翻頁(yè)放大縮小功能,比如vue-pdf,下面這篇文章主要給大家介紹了關(guān)于vue中使用vue-pdf組件實(shí)現(xiàn)文件預(yù)覽及相應(yīng)報(bào)錯(cuò)解決的相關(guān)資料,需要的朋友可以參考下2022-09-09
vue2.0實(shí)現(xiàn)移動(dòng)端的輸入框?qū)崟r(shí)檢索更新列表功能
最近小編在做vue2.0的項(xiàng)目,遇到移動(dòng)端實(shí)時(shí)檢索搜索更新列表的效果,下面腳本之家小編給大家?guī)?lái)了vue2.0 移動(dòng)端的輸入框?qū)崟r(shí)檢索更新列表功能的實(shí)例代碼,感興趣的朋友參考下吧2018-05-05
基于vue-cli vue-router搭建底部導(dǎo)航欄移動(dòng)前端項(xiàng)目
這篇文章主要介紹了基于vue-cli vue-router搭建底部導(dǎo)航欄移動(dòng)前端項(xiàng)目,項(xiàng)目中主要用了Flex布局,以及viewport相關(guān)知識(shí),已達(dá)到適應(yīng)各終端屏幕的目的。需要的朋友可以參考下2018-02-02

