springboot +vue 基于token(jwt)前后端登录开发
token定义
Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。
token作用
Token的目的是为了减轻服务器的压力,减少频繁的查询数据库,使服务器更加健壮
开发环境
后端: springboot + jwt + gradle(maven功能差不多) + jdk1.8 等
前端: vue-cli3 + axios + vuex 等
下面直接看代码
java
架包工具 https://mvnrepository.com/
build.gradle 文件
// 导入jwt等其他工具,其它自行导入如 mybatis springboot 等
// jjwt
compile 'io.jsonwebtoken:jjwt:0.9.0'
在jwtUtil.java里面写入生成token与解析token的代码
jwtUtil.java 类
@Component
@ConfigurationProperties("jwt") //匹配 application.yml
public class JwtUtil {
private String salt; // 盐
private long limitTime; // 过期时间 毫秒
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
public long getLimitTime() {
return limitTime;
}
public void setLimitTime(long limitTime) {
this.limitTime = limitTime;
}
// 生成jwt
public String createJWT(String id, String subject, String roles) {
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
//如果要加上权限设定的在singwith()前面加上.addClaims这个进行权限设定
JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT").setId(id).setSubject(subject).setIssuedAt(now)
.signWith(SignatureAlgorithm.HS256, salt);
if (limitTime > 0) {
builder.setExpiration(new Date(nowMillis + limitTime));
}
return builder.compact();
}
/**
* 解析JWT
*/
public Claims parseJWT(String jwtStr) {
return Jwts.parser().setSigningKey(salt).parseClaimsJws(jwtStr).getBody();
}
public JwtUtil jwtUtil() {
return new JwtUtil();
}
控制层进行调用即可
String token = jwtutil.createJWT(name, paw, "admin"); //admin类似就是一个权限等级。
前端
想法: 首先我进行对axios进行一个封装,然后在把后台传过来的token机进行存储到store里面。然后每一次跨域调用时候经过axios时候进行一个查看。
代码:
自己先创建axios的一个文件然后建立 api.js 和request.js文件
在 request.js 文件里面
//进行封装
// import Vue from 'vue'
// import app from '../main.js';
import axios from 'axios';
import store from "../vuex/store.js"
import qs from 'qs';
//Vue.use(axios)
//创建一个axios实例
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
// baseURL 此处是取多环境配置的url,也可以直接写死
// withCredentials: true, // send cookies when cross-domain requests
timeout: 5000 // request timeout
})
service.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8';
service.interceptors.request.use(
config => {
if (config.method === 'post') {
config.data = JSON.stringify(config.data)
}
if (sessionStorage.getItem("token")) { // 判断是否存在token,如果存在的话,则每个http header都加上token
config.headers.Authorization = `token: ${sessionStorage.getItem("token")}`;
}
return config
},
error => {
// do something with request error
console.log(error) // for debug
return Promise.reject(error)
}
)
// response interceptor
service.interceptors.response.use(
response => {
const res = response.data //我后台就是使用list<object>传值 下标0表示token值 1表示为状态码
//下面我是进行一个时间的一个对比;如果前台进行一个三十分钟没有操作的话会进行一个重新登入状态;重新登入时候后台会重新生成一个新token;从而不要担心后端token的一个刷新导致前端token不相同问题。
var today = new Date().getTime();
if(sessionStorage.getItem("nowTime")!=null){
if(today-sessionStorage.getItem("nowTime")>1000*60*30){ //如果第一次请求后在第二次请求大于30分钟就进行到登入页。
sessionStorage.removeItem('token');
sessionStorage.removeItem('nowTime');
router.push('/login');
location.reload()
return;
}else{ //如果小于的话并且token改变就替换token
sessionStorage.removeItem('nowTime');
Store.commit("set_time",today) //每一次请求都会添加新的一个时间从而进行保存。
}
}else{ //如果是今天第一次请求的话那就把时间添加进去。
// var today = new Date().getTime();
Store.commit("set_time",today) //退出登入后再一次登入会进行添加这一次登入时间。
}
if (res[1].id !== 200) {
// Message({
// message: res.message || 'Error',
// type: 'error',
// duration: 5 * 1000
// })
}
return Promise.reject(new Error(res.message || 'Error'))
} else {
return res
}
},
error => {
if (error.response) {
switch (error.response.status) {
case 401:
// 返回 401 清除token信息并跳转到登录页面
store.commit(types.LOGOUT);
router.replace({
path: '/login',
query: {redirect: router.currentRoute.fullPath}
})
}
}
// console.log('err' + error) // for debug
// Message({
// message: error.message,
// type: 'error',
// duration: 5 * 1000
// })
return Promise.reject(error)
}
)
export default service
api.js
就可以这样调用了,
export function requestLogin(params){
return requests({
url: '/api/loggintwo',
method: 'post',
data: params
})
}
但是前提是进行开启跨域
dev: {
env: require('./dev.env'),
port: 8080,
autoOpenBrowser: true,
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {
'/api': {
target:'http://跨域ip:端口/api/',//这里后台的地址模拟的;应该填写你们真实的后台接口
ws: true,
changOrigin: true,//允许跨域
pathRewrite: {
'^/api': ''//请求的时候使用这个api就可以
}
}
},
cssSourceMap: false
}
想保存token就要引入vuex
然后在 store.js里面写上
import Vue from 'vue'
import Vuex from 'vuex'
import * as actions from './actions'
import * as getters from './getters'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
token: '',
nowTime: '',
},
mutations: {
set_token(state, token) {
state.token = token
sessionStorage.token = token
},
del_token(state) {
state.token = ''
sessionStorage.removeItem('token')
},
//保存的时间
set_time(state,nowTime){
state.nowTime=nowTime;
sessionStorage.nowTime=nowTime
},
del_time(state){
state.nowTime='';
sessionStorage.removeItem('nowTime')
}
}
})
同时在 router里面配置
//表示你没有退出登入时候如果你不小心关掉了页面后第二次进去不要登入可以直接进入。
router.beforeEach((to, from, next) => {
if (to.path == '/login') {
var f=sessionStorage.getItem("token");
if (f) {
next();
}
}
var ff=sessionStorage.getItem("token");
if (!ff && to.path != '/login') {
next({ path: '/login' })
} else {
next()
}
})
login.vue
如果你登入成功就要进行一个对token的保存到store里面。
this.$store.commit("set_token",res.data.token) //保存token
this.$router.push({ path: '/table' }); //跳转页面
alert('登陆成功');
以后在每次请求下都会有token的一个产生结果如下:
如果有什么错误的话,希望各位大佬指点指点