Spring boot+VUE实现token验证的示例代码
作者:初夏0811
一、 步骤
Vue+Spring Boot实现token认证主要可分为六步:
1.前端登录,post用户名和密码到后端。
2.后端验证用户名和密码,若通过,生成一个token返回给前端。
3.前端拿到token用vuex和localStorage管理,登录成功进入首页。
4.之后前端每一次权限操作如跳转路由,都需要判断是否存在token,若不存在,跳转至登录页。
5.前端之后的每一个对后端的请求都要在请求头上带上token,后端查看请求头是否有token,拿到token检查是否过期,返回对应状态给前端。(通常失败返回401)
6.若token已过期,清除token信息,跳转至登录页。
二、后端
1.导依赖
<!-- jwt.token要用到的--> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.4.0</version> </dependency>
2.添加token工具类
.withClaim(“Username”, staff.getUsername())
我这个项目没有用户密码,所以我这里只用一个Username,如果有密码的话可以加多一行,比如说:
.withClaim(“Password”, staff.getPassword())
package com.xfish.employeeManagement.token; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.interfaces.DecodedJWT; import com.xfish.employeeManagement.pojo.staff; import java.util.Date; public class TokenUtil { private static final long EXPIRE_TIME= 10*60*60*1000; //十小时 private static final String TOKEN_SECRET="123456"; //密钥盐 /** * 签名生成 * @param staff * @return */ public static String sign(staff staff){ String token = null; try { Date expiresAt = new Date(System.currentTimeMillis() + EXPIRE_TIME); token = JWT.create() .withIssuer("auth0") .withClaim("Username", staff.getUsername()) // .withAudience(staff.getUsername()) .withExpiresAt(expiresAt) // 使用了HMAC256加密算法。 .sign(Algorithm.HMAC256(TOKEN_SECRET)); } catch (Exception e){ e.printStackTrace(); } return token; } /** * 签名验证 * @param token * @return */ public static boolean verify(String token){ try { JWTVerifier verifier = JWT.require(Algorithm.HMAC256(TOKEN_SECRET)).withIssuer("auth0").build(); DecodedJWT jwt = verifier.verify(token); System.err.println("认证通过:"); System.err.println("Username: " + jwt.getClaim("Username").asString()); System.err.println("过期时间: " + jwt.getExpiresAt()); return true; } catch (Exception e){ return false; } } }
3.添加拦截器
这个拦截器主要的功能就是,把一些没有token的请求拦截下来并返回错误信息,有token就可以直接通过
package com.xfish.employeeManagement.Interceptor; import com.alibaba.fastjson.JSONObject; import com.xfish.employeeManagement.token.TokenUtil; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Component public class TokenInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler)throws Exception{ if(request.getMethod().equals("OPTIONS")){ response.setStatus(HttpServletResponse.SC_OK); return true; } response.setCharacterEncoding("utf-8"); String token = request.getHeader("token"); //前端vue将token添加在请求头中 // System.err.println(request.getHeader()); if(token != null){ boolean result = TokenUtil.verify(token); if(result){ System.out.println("通过拦截器"); return true; } } response.setCharacterEncoding("UTF-8"); response.setContentType("application/json; charset=utf-8"); try{ JSONObject json = new JSONObject(); json.put("msg","token verify fail"); json.put("code","50000"); response.getWriter().append(json.toJSONString()); System.out.println("认证失败,未通过拦截器"); }catch (Exception e){ e.printStackTrace(); response.sendError(500); return false; } return false; } }
4.配置跨域,并处理请求
注意:这边拦截的是后端的接口,不是前端的,
在中’ /** ‘无论是restful的,还是后面有一大长串地址都可以识别到
excludePath.add(“/toLogin/**”);
package com.xfish.employeeManagement.config; import com.xfish.employeeManagement.Interceptor.TokenInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor; import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executors; @Configuration public class WebMvcConfig implements WebMvcConfigurer { /** * 开启跨域 */ @Override public void addCorsMappings(CorsRegistry registry) { // 设置允许跨域的路由 registry.addMapping("/**") // 设置允许跨域请求的域名 .allowedOriginPatterns("*") // 设置允许的方法 .allowedMethods("GET","HEAD","POST","PUT","DELETE","OPTIONS") // 是否允许携带cookie参数 .allowCredentials(true) // 设置允许的方法 .allowedMethods("*") // 跨域允许时间 .maxAge(4600); } private TokenInterceptor tokenInterceptor; //构造方法 public WebMvcConfig(TokenInterceptor tokenInterceptor){ this.tokenInterceptor = tokenInterceptor; } @Override public void configureAsyncSupport(AsyncSupportConfigurer configurer){ configurer.setTaskExecutor(new ConcurrentTaskExecutor(Executors.newFixedThreadPool(3))); configurer.setDefaultTimeout(30000); } @Override public void addInterceptors(InterceptorRegistry registry) { List<String> excludePath = new ArrayList<>(); //排除拦截,除了注册登录(此时还没token),其他都拦截 // excludePath.add(""); //登录 excludePath.add("/toLogin/**"); //登录 // excludePath.add("/admin/login"); //注册 // excludePath.add("/**"); excludePath.add("/img/**"); //静态资源 excludePath.add("/song/**"); //静态资源 registry.addInterceptor(tokenInterceptor) .addPathPatterns("/**") .excludePathPatterns(excludePath); WebMvcConfigurer.super.addInterceptors(registry); } }
5.登录接口
@GetMapping("/toLogin/{username}") public Object toLogin(@PathVariable("username") String username){ staff staff = staffService.queryStaffDataByName(username); JSONObject jsonObject = new JSONObject(); if(staff!=null){ String token = TokenUtil.sign(staff); jsonObject.put("token",token); jsonObject.put("staff",staff); jsonObject.put("msg","登录成功"); jsonObject.put("code",200); }else { jsonObject.put("msg","账号或密码错误"); jsonObject.put("code",500); } return jsonObject; }
三、前端
1.main.js配置
添加路由前置守卫beforeEach拦截请求,2.在axios中添加请求拦截器:
//路由全局前置守卫 router.beforeEach((to,from,next) => { // if(to.path === '/register' || to.path === '/login' || to.path === '/'){ //若是进入登录与注册页面 ==> pass if(to.path === '/register' || to.path === '' || to.path === '/'){ next() }else{ let userToken = localStorage.getItem('token'); // console.log("Token为:"+userToken); if(userToken == null || userToken == ''){ alert("无权限,请先登录!"); return next('/'); }else{ next(); } } }), //请求拦截器 在请求头中加token axios.interceptors.request.use( config => { // 将获取到的token设置给header中的token if(localStorage.getItem('token')){ config.headers.token = localStorage.getItem('token'); } return config; }, error => { return Promise.reject(error); } )
2.配置Vuex
在配置前记得一定要下载Vuex的依赖
cnpm install vuex --save
vuex的使用方式(可以不看)
store/index.js
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { user: localStorage.getItem('staff') ? localStorage.getItem('staff') : null, //若localSorage存在token,将值赋给Vuex.state.token token: localStorage.getItem('token') ? localStorage.getItem('token') : null }, mutations: { setUsername(state, staff) { state.staff = staff // JSON.stringify(ary) //将staff存成JSON格式 localStorage.setItem('staff', JSON.stringify(staff)) }, setToken(state, token) { localStorage.setItem('token', token) state.token = token }, //我页面中写了退出登录的按钮所以补了一个logout用来清空localStorage中的数据 logout(state) { localStorage.removeItem('token') state.token = null localStorage.removeItem('staff') state.setUsername = null //我写的RSA加密需向后端获取公钥,为了方便我在拿到公钥后直接存入localStorage中,所以在这里也要清空 localStorage.removeItem('publickey') state.publickey=null } } })
3.登录方法
记得一定要导包
import store from ‘…/store/index.js’
import store from '../store/index.js' export default { data() { return { ruleForm: { pass: '', username: ''}, staff:null, } }, methods: { }
submitForm() { var vm=this; vm.axios.get('http://localhost:8090/toLogin/'+this.ruleForm.username+'' ).then(function (response) { console.log(response.data.staff) if(response.data.code == 200){//将token和user保存到localStorage中 store.commit('setToken',response.data.token) store.commit('setUsername',response.data.staff) //跳转到登录成功后的页面 console.log("========"+response.data.msg) vm.$router.push('/index') //获取本地存储中的staff vm.staff=JSON.parse(localStorage.getItem('staff')) console.log(vm.staff); } else{ alert(response.data.msg) } }).catch(function (e) { console.log(e) }) }
4.退出登录
退出登录方法,记得一定要导包
import store from ‘…/store/index.js’
loginOut(){ store.commit('logout') }
Spring boot+VUE为什么不用session,
因为session是存在与服务器的,跨域session是会变的。
到此这篇关于Spring boot+VUE实现token验证的示例代码的文章就介绍到这了,更多相关Spring boot VUE token验证内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
您可能感兴趣的文章:
- springboot实现token验证登陆状态的示例代码
- SpringBoot整合JWT(JSON Web Token)生成token与验证的流程及示例
- springboot+shiro+jwtsession和token进行身份验证和授权
- SpringBoot集成JWT实现Token登录验证的示例代码
- SpringBoot登录验证token拦截器的实现
- 实战SpringBoot集成JWT实现token验证
- Springboot 如何实现filter拦截token验证和跨域
- SpringBoot整合JWT框架,解决Token跨域验证问题
- SpringBoot集成JWT实现token验证的流程
- SpringBoot下token短信验证登入登出权限操作(token存放redis,ali短信接口)