Spring boot+VUE實現(xiàn)token驗證的示例代碼
一、 步驟
Vue+Spring Boot實現(xiàn)token認證主要可分為六步:
1.前端登錄,post用戶名和密碼到后端。
2.后端驗證用戶名和密碼,若通過,生成一個token返回給前端。
3.前端拿到token用vuex和localStorage管理,登錄成功進入首頁。
4.之后前端每一次權限操作如跳轉路由,都需要判斷是否存在token,若不存在,跳轉至登錄頁。
5.前端之后的每一個對后端的請求都要在請求頭上帶上token,后端查看請求頭是否有token,拿到token檢查是否過期,返回對應狀態(tài)給前端。(通常失敗返回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參數(shù) .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/**"); //靜態(tài)資源 excludePath.add("/song/**"); //靜態(tài)資源 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配置
添加路由前置守衛(wèi)beforeEach攔截請求,2.在axios中添加請求攔截器:
//路由全局前置守衛(wèi) 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中的數(shù)據(jù) 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實現(xiàn)token驗證的示例代碼的文章就介紹到這了,更多相關Spring boot VUE token驗證內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- springboot實現(xiàn)token驗證登陸狀態(tài)的示例代碼
- SpringBoot整合JWT(JSON?Web?Token)生成token與驗證的流程及示例
- springboot+shiro+jwtsession和token進行身份驗證和授權
- SpringBoot集成JWT實現(xiàn)Token登錄驗證的示例代碼
- SpringBoot登錄驗證token攔截器的實現(xiàn)
- 實戰(zhàn)SpringBoot集成JWT實現(xiàn)token驗證
- Springboot 如何實現(xiàn)filter攔截token驗證和跨域
- SpringBoot整合JWT框架,解決Token跨域驗證問題
- SpringBoot集成JWT實現(xiàn)token驗證的流程
- SpringBoot下token短信驗證登入登出權限操作(token存放redis,ali短信接口)
相關文章
劍指Offer之Java算法習題精講字符串操作與數(shù)組及二叉搜索樹
跟著思路走,之后從簡單題入手,反復去看,做過之后可能會忘記,之后再做一次,記不住就反復做,反復尋求思路和規(guī)律,慢慢積累就會發(fā)現(xiàn)質的變化2022-03-03java新增關聯(lián)的三張表,每張表要求都插入集合,代碼實現(xiàn)方式
這篇文章主要介紹了java新增關聯(lián)的三張表,每張表要求都插入集合,代碼實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12Mybatis執(zhí)行Update返回行數(shù)為負數(shù)的問題
這篇文章主要介紹了Mybatis執(zhí)行Update返回行數(shù)為負數(shù)的問題,具有很好的參考價值,希望大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12redis.clients.jedis.exceptions.JedisMovedDataException異常解決
redis.clients.jedis.exceptions.JedisMovedDataException?異常是在使用?Jedis?客戶端與?Redis?集群進行交互時發(fā)生的,下面就來介紹一下解決方法,感興趣的可以了解一下2024-05-05