【项目】springboot中使用kaptcha生成验证码,登录时密码加盐处理
生活随笔
收集整理的這篇文章主要介紹了
【项目】springboot中使用kaptcha生成验证码,登录时密码加盐处理
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
記錄使用kaptcha的過程
為前后端分離項目,前端vue框架
文章目錄
- 0.下載jar包
- 1.添加依賴
- 2.添加KaptchaConfig配置
- 3.后端用于登錄的封裝類編寫
- 4.修改controller層代碼與前端交互
- 后端:
- 前端:
- 5.密碼加鹽和token相關的代碼
- 6.測試
0.下載jar包
在maven的網(wǎng)站https://mvnrepository.com/search?q=com.github.penggle
搜索下載jar
導入到工程中
1.添加依賴
<dependency><groupId>com.github.penggle</groupId><artifactId>kaptcha</artifactId><version>2.3.2</version></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-config</artifactId><version>5.4.1</version></dependency><dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId><version>2.3.1</version></dependency><dependency><groupId>com.sun.xml.bind</groupId><artifactId>jaxb-impl</artifactId><version>2.1</version></dependency><dependency><groupId>com.sun.xml.bind</groupId><artifactId>jaxb-core</artifactId><version>2.1.14</version></dependency><dependency><groupId>javax.activation</groupId><artifactId>activation</artifactId><version>1.1.1</version></dependency>后面的依賴是因為測試的時候有報錯添加的,以防萬一可以添加一下
2.添加KaptchaConfig配置
package com.louis.mango.config;import java.util.Properties;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;import com.google.code.kaptcha.impl.DefaultKaptcha; import com.google.code.kaptcha.util.Config;@Configuration public class KaptchaConfig {@Beanpublic DefaultKaptcha producer() {Properties properties = new Properties();properties.put("kaptcha.border", "no");properties.put("kaptcha.textproducer.font.color", "black");properties.put("kaptcha.textproducer.char.space", "5");Config config = new Config(properties);DefaultKaptcha defaultKaptcha = new DefaultKaptcha();defaultKaptcha.setConfig(config);return defaultKaptcha;} }注意注解 @Bean,不添加這個注解的話后面注入時會報無法注入。
3.后端用于登錄的封裝類編寫
LoginBean:
public class LoginBean {private String account;private String password;private String captcha;public String getAccount() {return account;}public void setAccount(String account) {this.account = account;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getCaptcha() {return captcha;}public void setCaptcha(String captcha) {this.captcha = captcha;}}4.修改controller層代碼與前端交互
后端:
@RestController public class SysLoginController {@Autowiredprivate Producer producer;@Autowiredprivate SysUserService sysUserService;@Autowiredprivate AuthenticationManager authenticationManager;@GetMapping("captcha.jpg")public void captcha(HttpServletResponse response, HttpServletRequest request) throws ServletException, IOException {response.setHeader("Cache-Control", "no-store, no-cache");response.setContentType("image/jpeg");// 生成文字驗證碼String text = producer.createText();// 生成圖片驗證碼BufferedImage image = producer.createImage(text);// 保存到驗證碼到 sessionrequest.getSession().setAttribute(Constants.KAPTCHA_SESSION_KEY, text);ServletOutputStream out = response.getOutputStream();ImageIO.write(image, "jpg", out); IOUtils.closeQuietly(out);}/*** 登錄接口*/@PostMapping(value = "/login")//public HttpResultpublic String login(@RequestBody LoginBean loginBean, HttpServletRequest request) throws IOException {String username = loginBean.getAccount();String password = loginBean.getPassword();String captcha = loginBean.getCaptcha();// 從session中獲取之前保存的驗證碼跟前臺傳來的驗證碼進行匹配Object kaptcha = request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);if (kaptcha == null) {//return HttpResult.error("驗證碼已失效");return "已經(jīng)失效";}if (!captcha.equals(kaptcha)) {return "驗證碼不正確";//return HttpResult.error("驗證碼不正確");}// 用戶信息SysUser user = sysUserService.findByName(username);System.out.println(user);// 賬號不存在、密碼錯誤if (user == null) {//return HttpResult.error("賬號不存在");return "賬號不存在";}if (!PasswordUtils.matches(user.getSalt(), password, user.getPassword())) {return "密碼不正確";}// 賬號鎖定if (user.getStatus() == 0) {return "賬號已被鎖定,請聯(lián)系管理員";}// 系統(tǒng)登錄認證JwtAuthenticatioToken token = SecurityUtils.login(request, username, password, authenticationManager);System.out.println("yes!");System.out.println(token); // // return HttpResult.ok(token); // }return "ok";}}前端:
template:
<template><el-form :model="loginForm" :rules="fieldRules" ref="loginForm" label-position="left" label-width="0px" class="demo-ruleForm login-container"><span class="tool-bar"></span><h2 class="title" style="padding-left:22px;" >系統(tǒng)登錄</h2><el-form-item prop="account"><el-input type="text" v-model="loginForm.account" auto-complete="off" placeholder="賬號"></el-input></el-form-item><el-form-item prop="password"><el-input type="password" v-model="loginForm.password" auto-complete="off" placeholder="密碼"></el-input></el-form-item><el-form-item ><el-col :span="12"><el-form-item prop="captcha"><el-input type="test" v-model="loginForm.captcha" auto-complete="off" placeholder="驗證碼, 單擊圖片刷新"style="width: 100%;"></el-input></el-form-item></el-col><el-col class="line" :span="1"> </el-col><el-col :span="11"><el-form-item><img style="width: 100%;" class="pointer" :src="loginForm.src" @click="refreshCaptcha"></el-form-item></el-col></el-form-item><el-form-item style="width:100%;"><el-button type="primary" style="width:48%;" @click.native.prevent="reset">重 置</el-button><el-button type="primary" style="width:48%;" @click.native.prevent="login" :loading="loading">登 錄</el-button></el-form-item></el-form> </template>script:
export default {data() {return {loading: false,loginForm: {account: 'admin',password: 'admin',captcha:'',src: ''},fieldRules: {account: [{ required: true, message: '請輸入賬號', trigger: 'blur' }],password: [{ required: true, message: '請輸入密碼', trigger: 'blur' }]},checked: true}},methods: {login() {this.loading = truelet userInfo = { account:this.loginForm.account, password:this.loginForm.password,captcha:this.loginForm.captcha }this.$api.login.login(userInfo).then((res) => {if (res == "ok" ) {window.sessionStorage.setItem('flag','ok'); // session 放置-->this.$message.success("登陸成功!!!");this.$router.push({ path: "/home"});}this.loading = false}).catch((res) => {this.$message({ message: res.message, type: 'error' })})},refreshCaptcha: function(){this.loginForm.src = "http://localhost:8001/captcha.jpg?t=" + new Date().getTime();},reset() {this.$refs.loginForm.resetFields()}mounted() {this.refreshCaptcha()} }關于其中api:
目錄:
(src下)
index.js:
login.js:
import axios from '../axios'/* * 系統(tǒng)登錄模塊*/// 登錄 export const login = data => {return axios({url: 'login',method: 'post',data}) }// 登出 export const logout = () => {return axios({url: 'logout',method: 'get'}) }axios.js:
import axios from 'axios'; import config from './config'; import Cookies from "js-cookie"; import router from '@/router'export default function $axios(options) {return new Promise((resolve, reject) => {const instance = axios.create({baseURL: config.baseUrl,headers: config.headers,timeout: config.timeout,withCredentials: config.withCredentials})// request 請求攔截器instance.interceptors.request.use(config => {let token = Cookies.get('token')// 發(fā)送請求時攜帶tokenif (token) {config.headers.token = token} else {// 重定向到登錄頁面router.push('/login')}return config},error => {// 請求發(fā)生錯誤時console.log('request:', error)// 判斷請求超時if (error.code === 'ECONNABORTED' && error.message.indexOf('timeout') !== -1) {console.log('timeout請求超時')}// 需要重定向到錯誤頁面const errorInfo = error.responseconsole.log(errorInfo)if (errorInfo) {error = errorInfo.data // 頁面那邊catch的時候就能拿到詳細的錯誤信息,看最下邊的Promise.rejectconst errorStatus = errorInfo.status; // 404 403 500 ...router.push({path: `/error/${errorStatus}`})}return Promise.reject(error) // 在調用的那邊可以拿到(catch)你想返回的錯誤信息})// response 響應攔截器instance.interceptors.response.use(response => {return response.data},err => {if (err && err.response) {switch (err.response.status) {case 400:err.message = '請求錯誤'breakcase 401:err.message = '未授權,請登錄'breakcase 403:err.message = '拒絕訪問'breakcase 404:err.message = `請求地址出錯: ${err.response.config.url}`breakcase 408:err.message = '請求超時'breakcase 500:err.message = '服務器內部錯誤'breakcase 501:err.message = '服務未實現(xiàn)'breakcase 502:err.message = '網(wǎng)關錯誤'breakcase 503:err.message = '服務不可用'breakcase 504:err.message = '網(wǎng)關超時'breakcase 505:err.message = 'HTTP版本不受支持'breakdefault:}}console.error(err)return Promise.reject(err) // 返回接口返回的錯誤信息})// 請求處理instance(options).then(res => {resolve(res)return false}).catch(error => {reject(error)})}) }mock目錄下的index.js:
import Mock from 'mockjs'import * as login from './modules/login' import * as user from './modules/user' import * as role from './modules/role' import * as dept from './modules/dept' import * as menu from './modules/menu' import * as dict from './modules/dict' import * as config from './modules/config' import * as log from './modules/log' import * as loginlog from './modules/loginlog'// 1. 開啟/關閉[所有模塊]攔截, 通過調[openMock參數(shù)]設置. // 2. 開啟/關閉[業(yè)務模塊]攔截, 通過調用fnCreate方法[isOpen參數(shù)]設置. // 3. 開啟/關閉[業(yè)務模塊中某個請求]攔截, 通過函數(shù)返回對象中的[isOpen屬性]設置. let openMock = true //let openMock = false fnCreate(user, openMock) fnCreate(role, openMock) fnCreate(dept, openMock) fnCreate(menu, openMock) fnCreate(dict, openMock) fnCreate(config, openMock) fnCreate(log, openMock) fnCreate(loginlog, openMock) fnCreate(login, openMock)/*** 創(chuàng)建mock模擬數(shù)據(jù)* @param {*} mod 模塊* @param {*} isOpen 是否開啟?*/ function fnCreate (mod, isOpen = true) {if (isOpen) {for (var key in mod) {((res) => {if (res.isOpen !== false) {let url = "http://localhost:8001/"if(!url.endsWith("/")) {url = url + "/"}url = url + res.urlMock.mock(new RegExp(url), res.type, (opts) => {opts['data'] = opts.body ? JSON.parse(opts.body) : nulldelete opts.bodyconsole.log('\n')console.log('%cmock攔截, 請求: ', 'color:blue', opts)console.log('%cmock攔截, 響應: ', 'color:blue', res.data)return res.data})}})(mod[key]() || {})}} }mock目錄下的login.js:
/* * 系統(tǒng)登錄模塊*/// 登錄接口 export function login() {const loginData = {"code": 200,"msg": null,"data": {"authorities": [],"details": {"remoteAddress": "0:0:0:0:0:0:0:1","sessionId": "E9E774A8EB4405B25692D84B4521CB45"},"authenticated": false,"principal": "admin","credentials": "admin","token": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6MTU0NzkzMTYxOCwiY3JlYXRlZCI6MTU0Nzg4ODQxODgyMiwiYXV0aG9yaXRpZXMiOlt7ImF1dGhvcml0eSI6InN5czptZW51OmRlbGV0ZSJ9LHsiYXV0aG9yaXR5Ijoic3lzOmRpY3Q6ZWRpdCJ9LHsiYXV0aG9yaXR5Ijoic3lzOmRpY3Q6ZGVsZXRlIn0seyJhdXRob3JpdHkiOiJzeXM6Y29uZmlnOmFkZCJ9LHsiYXV0aG9yaXR5Ijoic3lzOm1lbnU6YWRkIn0seyJhdXRob3JpdHkiOiJzeXM6dXNlcjphZGQifSx7ImF1dGhvcml0eSI6InN5czpkZXB0OmRlbGV0ZSJ9LHsiYXV0aG9yaXR5Ijoic3lzOnJvbGU6ZWRpdCJ9LHsiYXV0aG9yaXR5Ijoic3lzOnJvbGU6dmlldyJ9LHsiYXV0aG9yaXR5Ijoic3lzOmRpY3Q6dmlldyJ9LHsiYXV0aG9yaXR5Ijoic3lzOnVzZXI6ZGVsZXRlIn0seyJhdXRob3JpdHkiOiJzeXM6ZGVwdDp2aWV3In0seyJhdXRob3JpdHkiOiJzeXM6bWVudTp2aWV3In0seyJhdXRob3JpdHkiOiJzeXM6ZGljdDphZGQifSx7ImF1dGhvcml0eSI6InN5czpyb2xlOmFkZCJ9LHsiYXV0aG9yaXR5Ijoic3lzOnVzZXI6dmlldyJ9LHsiYXV0aG9yaXR5Ijoic3lzOmRlcHQ6ZWRpdCJ9LHsiYXV0aG9yaXR5Ijoic3lzOmNvbmZpZzplZGl0In0seyJhdXRob3JpdHkiOiJzeXM6bG9naW5sb2c6dmlldyJ9LHsiYXV0aG9yaXR5Ijoic3lzOnVzZXI6ZWRpdCJ9LHsiYXV0aG9yaXR5Ijoic3lzOmNvbmZpZzp2aWV3In0seyJhdXRob3JpdHkiOiJzeXM6Y29uZmlnOmRlbGV0ZSJ9LHsiYXV0aG9yaXR5Ijoic3lzOmRlcHQ6YWRkIn0seyJhdXRob3JpdHkiOiJzeXM6cm9sZTpkZWxldGUifSx7ImF1dGhvcml0eSI6InN5czptZW51OmVkaXQifV19.Lw2qb2BJHwmiVMHS_vbaLf7vnTT6frr7vTS2-nJ1Lo0uOduqK6nPtBtgEka-fH7ow-s5n7OH1WZkUvH0PN6oyA","name": "admin"}}return {url: 'login',type: 'post',data: loginData} } // 登出接口 export function logout() {const logoutData = {"code": 200,"msg": null,"data": {}}return {url: 'logout',type: 'get',data: logoutData} }5.密碼加鹽和token相關的代碼
目錄:
PasswordUtils :
public class PasswordUtils {/*** 匹配密碼* @param salt 鹽* @param rawPass 明文 * @param encPass 密文* @return*/public static boolean matches(String salt, String rawPass, String encPass) {return new PasswordEncoder(salt).matches(encPass, rawPass);}/*** 明文密碼加密* @param rawPass 明文* @param salt* @return*/public static String encode(String rawPass, String salt) {return new PasswordEncoder(salt).encode(rawPass);}/*** 獲取加密鹽* @return*/public static String getSalt() {return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 20);} }- 密碼加密 PasswordEncoder
- Security相關操作
- JWT工具類
6.測試
后端打印的內容:
總結
以上是生活随笔為你收集整理的【项目】springboot中使用kaptcha生成验证码,登录时密码加盐处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【记录】python多线程的使用 线程同
- 下一篇: 【JAVA多线程学习笔记】(1)实现线程