首先 在api文件夹里封装axios
1、安装包
crypto-js jsencrypt
2、在utils下创建一个 .js文件夹 将加密封装
/*
* @Descripttion: 工具集
* @version: 1.2
* @LastEditors: sakuya
* @LastEditTime: 2022年5月24日00:28:56
*/
// 安装引包
import CryptoJS from 'crypto-js';
import JSEncrypt from 'jsencrypt';
const tool = {}
/* 复制对象 */
tool.objCopy = function (obj) {
return JSON.parse(JSON.stringify(obj));
}
/* 日期格式化 */
tool.dateFormat = function (date, fmt = 'yyyy-MM-dd hh:mm:ss') {
date = new Date(date)
var o = {
"M+": date.getMonth() + 1, //月份
"d+": date.getDate(), //日
"h+": date.getHours(), //小时
"m+": date.getMinutes(), //分
"s+": date.getSeconds(), //秒
"q+": Math.floor((date.getMonth() + 3) / 3), //季度
"S": date.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
}
for (var k in o) {
if (new RegExp("(" + k + ")").test(fmt)) {
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
}
}
return fmt;
}
/* 千分符 */
tool.groupSeparator = function (num) {
num = num + '';
if (!num.includes('.')) {
num += '.'
}
return num.replace(/(\d)(?=(\d{3})+\.)/g, function ($0, $1) {
return $1 + ',';
}).replace(/\.$/, '');
}
/* 常用加解密 */
tool.crypto = {
//MD5加密
MD5(data) {
return CryptoJS.MD5(data).toString()
},
//BASE64加解密
BASE64: {
encrypt(data) {
return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(data))
},
decrypt(cipher) {
return CryptoJS.enc.Base64.parse(cipher).toString(CryptoJS.enc.Utf8)
}
},
//AES加解密
AES: {
encrypt(data, secretKey, config = {}) {
if (secretKey.length % 8 != 0) {
console.warn("[SCUI error]: 秘钥长度需为8的倍数,否则解密将会失败。")
}
const result = CryptoJS.AES.encrypt(data, CryptoJS.enc.Utf8.parse(secretKey), {
iv: CryptoJS.enc.Utf8.parse(config.iv || ""),
mode: CryptoJS.mode[config.mode || "ECB"],
padding: CryptoJS.pad[config.padding || "Pkcs7"]
})
return result.toString()
},
decrypt(cipher, secretKey, config = {}) {
const result = CryptoJS.AES.decrypt(cipher, CryptoJS.enc.Utf8.parse(secretKey), {
iv: CryptoJS.enc.Utf8.parse(config.iv || ""),
mode: CryptoJS.mode[config.mode || "ECB"],
padding: CryptoJS.pad[config.padding || "Pkcs7"]
})
return CryptoJS.enc.Utf8.stringify(result);
}
},
//RSA公钥加密
RSA: {
encrypt(data, publicKey) {
if (!publicKey) {
console.warn("未设置publicKey,加密将会失败。");
}
var encrypt = new JSEncrypt();
encrypt.setPublicKey('-----BEGIN PUBLIC KEY-----' + publicKey + '-----END PUBLIC KEY-----');
return encrypt.encrypt(data.toString());
}
}
}
/* JWT */
tool.jwt = {
decrypt(token) {
token = token.replace(/_/g, "/").replace(/-/g, "+");
var json = decodeURIComponent(escape(window.atob(token.split(".")[1])));
return JSON.parse(json);
},
getDate(timestamp) {
return new Date(timestamp * 1000);
}
}
tool.helper = {
//去掉Html标签
removeHtml(value) {
return value.replace(/<[^>]+>/g, '');
},
removeHtmlSub(value) {
var str = value.replace(/<[^>]+>/g, '');
if (str.length > 50) return str.substring(0, 50) + '......';
else return str;
}
}
/* 文件 */
tool.file = {
/**
* 下载在线图片
* @param {*} url
* @param {*} fileName
* @param {*} mime
* @param {*} bom
*/
downloadByByOnlineUrl(url,fileName,mime,bom){
tool.file.urlToBase64(url).then((base64) => {
tool.file.downloadByBase64(base64, fileName, mime, bom);
});
},
/**
* 根据Base64下载 图片
* @param {*} buf
* @param {*} fileName
* @param {*} mime
* @param {*} bom
*/
downloadByBase64(buf,fileName,mime,bom){
const base64Buf = tool.file.dataURLtoBlob(buf);
tool.file.downloadByData(base64Buf, fileName, mime, bom);
},
/**
* 根据后台接口文件流下载
* @param {*} data
* @param {*} fileName
* @param {*} mime
* @param {*} bom
*/
downloadByData(data,fileName,mime,bom){
const blobData = typeof bom !== 'undefined' ? [bom, data] : [data];
const blob = new Blob(blobData, { type: mime || 'application/octet-stream' });
const blobURL = window.URL.createObjectURL(blob);
const tempLink = document.createElement('a');
tempLink.style.display = 'none';
tempLink.href = blobURL;
tempLink.setAttribute('download', fileName);
if (typeof tempLink.download === 'undefined') {
tempLink.setAttribute('target', '_blank');
}
document.body.appendChild(tempLink);
tempLink.click();
document.body.removeChild(tempLink);
window.URL.revokeObjectURL(blobURL);
},
/**
* 根据文件地址下载文件
* @param {*} param0
* @returns
*/
downloadByUrl({ url, target = '_blank', fileName }){
const isChrome = window.navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
const isSafari = window.navigator.userAgent.toLowerCase().indexOf('safari') > -1;
if (/(iP)/g.test(window.navigator.userAgent)) {
console.error('Your browser does not support download!');
return false;
}
if (isChrome || isSafari) {
const link = document.createElement('a');
link.href = url;
link.target = target;
if (link.download !== undefined) {
link.download = fileName || url.substring(url.lastIndexOf('/') + 1, url.length);
}
if (document.createEvent) {
const e = document.createEvent('MouseEvents');
e.initEvent('click', true, true);
link.dispatchEvent(e);
return true;
}
}
if (url.indexOf('?') === -1) {
url += '?download';
}
tool.file.openWindow(url, { target });
return true;
},
openWindow(url,opt){
const { target = '__blank', noopener = true, noreferrer = true } = opt || {};
const feature = [];
noopener && feature.push('noopener=yes');
noreferrer && feature.push('noreferrer=yes');
window.open(url, target, feature.join(','));
},
getFileName(headers){
var fileName = headers['content-disposition'].split(';')[1].split('filename=')[1];
var fileNameUnicode = headers['content-disposition'].split('filename*=')[1];
if (fileNameUnicode) {
//当存在 filename* 时,取filename* 并进行解码(为了解决中文乱码问题)
fileName = decodeURIComponent(fileNameUnicode.split("''")[1]);
}
return fileName;
},
/**
* base64 to blob
* @param {*} base64Buf
* @returns
*/
dataURLtoBlob(base64Buf){
const arr = base64Buf.split(',');
const typeItem = arr[0];
const mime = typeItem.match(/:(.*?);/)[1];
const bstr = window.atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
},
/**
* img url to base64
* @param {*} url
* @param {*} mimeType
* @returns
*/
urlToBase64(url,mimeType){
return new Promise((resolve, reject) => {
let canvas = document.createElement('CANVAS');
const ctx = canvas.getContext('2d');
const img = new Image();
img.crossOrigin = '';
img.onload = function () {
if (!canvas || !ctx) {
return reject();
}
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img, 0, 0);
const dataURL = canvas.toDataURL(mimeType || 'image/png');
canvas = null;
resolve(dataURL);
};
img.src = url;
});
},
/**
* File 转 base64
* @param {*} file
* @returns
*/
fileToBase64(file){
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = (error) => reject(error);
});
},
/**
* Base64 转 File
* @param {*} dataURL
* @param {*} fileName
* @param {*} mimeType [可选]文件类型,默认为base64中的类型
* @returns
*/
base64ToFile(dataURL,fileName,mimeType=null){
var arr = dataURL.split(',');
var defaultMimeType = arr[0].match(/:(.*?);/)[1];
var bStr = atob(arr[1]);
let n = bStr.length;
var u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bStr.charCodeAt(n);
}
return new File([u8arr], fileName, { type: mimeType || defaultMimeType });
},
/**
* Blob 转 File
* @param {*} blob
* @param {*} fileName 文件名
* @param {*} mimeType 文件类型
* @returns
*/
blobToFile(blob,fileName,mimeType){
return new File([blob], fileName, { type: mimeType });
}
}
export default tool
3、在登录页 引入 封装好的文件
import tool from "@/utils/tool.js";
<template>
<div class="header">
<!-- 登录 -->
<header>
<section class="center">
<div class="hear-left">
<img
src="https://yun-campus-res.oss-cn-shenzhen.aliyuncs.com/kzp/vip/login-home/hr_pc_logo.png"
alt=""
/>
</div>
<div class="head-right">
<button class="hear-btn">微信人工客服</button>
<button class="hear-btn">操作指南</button>
</div>
</section>
</header>
<div class="max-box">
<!-- 左边 -->
<div class="left">
<p class="left-p">
<img
src="https://yun-campus-res.oss-cn-shenzhen.aliyuncs.com/kzp/vip/login-home/fonts.png?v=1"
alt=""
/>
<span>部分合作高校</span>
</p>
<div class="left-box">
<img
src="https://o.bysjy.com.cn/kzp/vip/login-home/logos-1.png"
alt=""
/>
</div>
</div>
<!-- 右边 -->
<div class="right">
<div class="switch">
<el-button>微信扫码登录</el-button>
<div class="switch-twoCode">
<img
src="https://yun-campus-res.oss-cn-shenzhen.aliyuncs.com/kzp/vip/login-home/qr-code.png"
alt=""
/>
</div>
</div>
<el-form class="form-box" ref="loginFrom" :model="form" :rules="rules">
<el-input
v-model="form.phone"
placeholder="请输入账户"
type="text"
@blur="check"
ref="username"
/>
<el-input
v-model="form.password"
type="password"
placeholder="请输入密码"
ref="userpwd"
@blur="checkPwd"
>
<template #append>
<el-button @click="forget">忘记密码 </el-button>
</template>
</el-input>
<div class="inp-yzm">
<el-input
v-model="form.code"
placeholder="请输入验证码"
class="el-input_inner"
>
</el-input>
<img class="yzm" :src="urls.imgs" alt="" title="点击刷新验证码" />
</div>
<p>
<el-checkbox
v-model="checked1"
:checked="state.isOk"
label="同意云校招"
size="large"
/>
<a
href="https://hr.bysjy.com.cn/login_v2/word?guid=48FB7AC2-F562-D593-BBDE-5797D4556E30"
target="_blank"
>《用户协议》
</a>
<a
href="https://hr.bysjy.com.cn/login_v2/word?guid=C338A93C-6E71-4601-18EA-9F126A95A538"
target="_blank"
>《隐私协议》</a
>
</p>
<!-- 登录 -->
<el-button
class="btn-Login"
size="large"
type="primary"
@click="loginCheck"
:loading="islogin"
>登录</el-button
>
<div class="register">
<span class="register-left"> <a href="#">验证码登录</a> </span>
<span class="register-right"
>没有账号
<span class="reg-zc" @click="toregister">立即注册></span>
</span>
</div>
</el-form>
</div>
</div>
</div>
</template>
<script setup>
import { onMounted, reactive, ref } from "vue";
import { ElMessageBox } from "element-plus";
import { useRouter } from "vue-router";
// 引入接口
import { loginAdminApi, getCaptchaApi, RSAKeyApi, PhoneApi } from "@/api/index";
// 加密
import tool from "@/utils/tool.js";
const router = useRouter();
const form = ref({
phone: "",
password: "",
codeId: "",
code: "",
});
const urls = reactive({
imgs: "",
islogin: false,
});
const state = reactive({
isOk: false,
publicKey: "",
});
onMounted(async () => {
await getKey();
// 验证码
getCaptchaApi().then((res) => {
// console.log("res", res);
urls.imgs = "data:text/html;base64," + res.result?.img;
form.value.codeId = res.result.id;
});
});
const getKey = async () => {
var res = await RSAKeyApi();
state.publicKey = res.result;
};
// 手机号
const validateUserPhone = (rule, value, callback) => {
const reg = /^[1][3-9][0-9]{9}$/;
if (
(!validateUserPhone && value == "") ||
value == undefined ||
value == null
) {
callback();
return;
} else {
if (!reg.test(value) && value != "") {
callback(new Error("请按照格式输入正确的手机号码!"));
} else {
callback();
}
}
// 检查用户名是否存在
PhoneApi(form)
.then((response) => {
if (response.data.success) {
callback(new Error("当前账号已存在,请重新输入!"));
} else {
callback();
}
})
.catch(() => {
callback(new Error("异步校验出错!"));
});
};
// 密码
const validatePassword = (rule, value, callback) => {
if (value !== "") {
if (value.length < 8) {
callback(new Error("请输入至少8位的密码"));
return false;
} else if (
!/^(?=.*[A-Za-z])(?=.*\d)(?=.*[@!*#$%&_=])[A-Za-z\d@!*#$%&_=]{8,18}$/.test(
value
)
) {
callback(new Error("密码必须包含字母、数字和特殊字符(@!*#$%&_=)"));
return false;
} else {
callback();
}
}
};
const rules = reactive({
ruleValidate: {
phone: [
{ required: true, message: "手机号不能为空!", trugger: "blur" },
{ validator: validateUserPhone, trugger: "blur" },
],
password: [
{ required: true, message: "请输入密码!", trugger: "blur" },
{ validator: validatePassword, trugger: "blur" },
],
},
});
//登录
const loginCheck = async () => {
var params = Object.assign({}, form.value);
params.password = tool.crypto.RSA.encrypt(params.password, state.publicKey);
loginAdminApi(params).then((res) => {
console.log("res", res);
if (state.isOk === true) {
//登录成功
//保存用户的信心(用户名、token)
sessionStorage.setItem("username", form.value.phone);
sessionStorage.setItem("token", res.data.data.token);
sessionStorage.setItem(
"checkedKeys",
JSON.stringify(res.data.data.checkedkeys)
);
//获取当前登录人信息并缓存
getHrInfoApi().then((res1) => {
if (res1.code == 200) {
sessionStorage.setItem("userInfo", JSON.stringify(res1.result));
}
})
ElMessageBox({
title: "提示",
message: "登录成功!",
});
//跳转到主页
router.push("/home");
}
});
};
// 点击立即注册
let toregister = () => {
router.push("/register");
};
</script>
<style scoped>
</style>
4、在请求头携带token
在util下新建serve.js文件
//请求拦截器
service.interceptors.request.use((config => {
//处理token
//携带token
// 获取token
let token = sessionStorage.getItem("accessToken");
// 判断是否存在 然后发送token // if (token) {
if (token) {
config.headers.Authorization ='Bearer '+ token
}
return config;
}
), () => {
})