token可用於登陸驗證和權限管理。
大體步驟分爲:css
若token已過時,清除token信息,跳轉至登陸頁。
具體代碼以下:前端
<template> <div class="signin-form"> <h3 class="sign-title">ticket-sys 登陸</h3> <div> <el-form :model="loginForm" :rules="rules" status-icon ref="ruleForm" class="demo-ruleForm"> <el-form-item prop="username"> <el-input v-model="loginForm.username" autocomplete="off" placeholder="用戶名" prefix-icon="el-icon-user-solid" ></el-input> </el-form-item> <el-form-item prop="password"> <el-input type="password" v-model="loginForm.password" autocomplete="off" placeholder="請輸入密碼" prefix-icon="el-icon-lock" ></el-input> </el-form-item> <el-form-item> <el-button type="primary" @click="submitForm" id="login-btn">登陸</el-button> </el-form-item> </el-form> </div> </div> </template> <script> import api from '../constant/api'; import {mapMutations} from "vuex"; export default { name: 'login', data() { return { loginForm:{ username:'', password:'' }, userToken:'', rules:{ username:[ { required: true, message: '請輸入用戶名', trigger: 'blur' }, ], password:[ { required: true, message: '請輸入密碼', trigger: 'blur' }, ] } } }, methods: { ...mapMutations(['changeLogin']), submitForm() { let v=this; this.$axios({ method: 'post', url: api.base_url+'/user/login', data:{ 'username':v.loginForm.username, 'password':v.loginForm.password } }).then(function(res){ console.log(res.data); v.userToken = 'Bearer ' + res.data.token; // 將用戶token保存到vuex中 v.changeLogin({ Authorization:v.userToken }); v.$router.push('/home'); v.$message('登陸成功'); }).catch(function(err){ console.log("err",err); v.$message('密碼或用戶名錯誤'); }) } } } </script> <style scoped>...</style>
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); const store = new Vuex.Store({ state: { // 存儲token Authorization: localStorage.getItem('Authorization') ? localStorage.getItem('Authorization') : '' }, mutations: { // 修改token,並將token存入localStorage changeLogin (state, user) { state.Authorization = user.Authorization; localStorage.setItem('Authorization', user.Authorization); } } }); export default store;
import Vue from 'vue' import VueRouter from 'vue-router' import Home from '../views/Home.vue' Vue.use(VueRouter) const routes = [ { path: '/home', name: 'home', component: Home, } , { path: '/about', name: 'about', // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: function () { return import(/* webpackChunkName: "about" */ '../views/About.vue') } }, { path:'/login', name:'login', component:function () { return import('../views/Login.vue'); } } ] const router = new VueRouter({ <template> <div class="home"> <el-container> <!-- <Header/>--> <!-- <el-main>首頁</el-main>--> <el-button @click="exit">退出登陸</el-button> <el-button @click="test">攜帶token的測試請求</el-button> </el-container> </div> </template> <script> // @ is an alias to /src import HelloWorld from '@/components/HelloWorld.vue' import Header from "../components/Header"; import api from "../constant/api"; export default { name: 'home', components: { Header, HelloWorld }, methods:{ exit(){ localStorage.removeItem('Authorization'); this.$router.push('/login'); }, test(){ this.$axios({ method: 'get', url: api.base_url+'/user/test', }).then(function(res){ console.log("res",res); }).catch(function(err){ console.log("err",err); }) } } } </script> <style>...</style> mode: 'history', base: process.env.BASE_URL, routes }); // 導航守衛 // 使用 router.beforeEach 註冊一個全局前置守衛,判斷用戶是否登錄 router.beforeEach((to, from, next) => { if (to.path === '/login') { next(); } else { let token = localStorage.getItem('Authorization'); if (token === 'null' || token === '') { next('/login'); } else { next(); } } }); export default router
import Vue from 'vue' import App from './App.vue' import router from './router' import './plugins/element.js' import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; import axios from 'axios' ; import Vuex from 'vuex' //引入狀態管理 Vue.prototype.$axios= axios ; Vue.use(Vuex) ; Vue.config.productionTip = false Vue.use(ElementUI) //這裏要導入store import store from "./store"; // 添加請求攔截器,在請求頭中加token axios.interceptors.request.use( config => { if (localStorage.getItem('Authorization')) { config.headers.Authorization = localStorage.getItem('Authorization'); } return config; }, error => { return Promise.reject(error); }); new Vue({ //這裏要配置store router, store:store, render: function (h) { return h(App) } }).$mount('#app')
<template> <div class="home"> <el-container> <!-- <Header/>--> <!-- <el-main>首頁</el-main>--> <el-button @click="exit">退出登陸</el-button> <el-button @click="test">攜帶token的測試請求</el-button> </el-container> </div> </template> <script> // @ is an alias to /src import HelloWorld from '@/components/HelloWorld.vue' import Header from "../components/Header"; import api from "../constant/api"; export default { name: 'home', components: { Header, HelloWorld }, methods:{ exit(){ //退出登陸,清空token localStorage.removeItem('Authorization'); this.$router.push('/login'); }, test(){ this.$axios({ method: 'get', url: api.base_url+'/user/test', }).then(function(res){ console.log("res",res); }).catch(function(err){ console.log("err",err); }) } } } </script> <style>...</style>
package com.zxc.ticketsys.controller; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; @RestController @RequestMapping("/user") public class UserController{ @RequestMapping(value = "/login",method = RequestMethod.POST) @ResponseBody public String login(@RequestHeader Map<String,Object> he,@RequestBody Map<String,Object> para) throws JsonProcessingException { System.out.println(he); String username=(String)para.get("username"); String password=(String)para.get("password"); HashMap<String,Object> hs=new HashMap<>(); hs.put("token","token"+username+password); ObjectMapper objectMapper=new ObjectMapper(); return objectMapper.writeValueAsString(hs); } @RequestMapping(value = "/test",method = RequestMethod.GET) @ResponseBody public String test(@RequestHeader Map<String,Object> he) throws JsonProcessingException { System.out.println(he); HashMap<String,Object> hs=new HashMap<>(); ObjectMapper objectMapper=new ObjectMapper(); return objectMapper.writeValueAsString(hs); } }
{host=localhost:8088, connection=keep-alive, accept=application/json, text/plain, */*, origin=http://localhost:8080, user-agent=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36, sec-fetch-site=same-site, sec-fetch-mode=cors, referer=http://localhost:8080/home, accept-encoding=gzip, deflate, br, accept-language=zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7}
{host=localhost:8088, connection=keep-alive, accept=application/json, text/plain, */*, origin=http://localhost:8080, authorization=Bearer tokenadminadmin, user-agent=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36, sec-fetch-site=same-site, sec-fetch-mode=cors, referer=http://localhost:8080/home, accept-encoding=gzip, deflate, br, accept-language=zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7}
帶有token,能夠進行驗證vue
在實際的應用中,通常須要一個生成token的工具類和一個攔截器對請求進行攔截。java
package com.zxc.ticketsys.utils; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.interfaces.DecodedJWT; import com.zxc.ticketsys.model.User; import java.util.Date; public class TokenUtil { private static final long EXPIRE_TIME= 10*60*60*1000; private static final String TOKEN_SECRET="txdy"; //密鑰鹽 /** * 簽名生成 * @param user * @return */ public static String sign(User user){ String token = null; try { Date expiresAt = new Date(System.currentTimeMillis() + EXPIRE_TIME); token = JWT.create() .withIssuer("auth0") .withClaim("username", user.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.out.println("認證經過:"); System.out.println("username: " + jwt.getClaim("username").asString()); System.out.println("過時時間: " + jwt.getExpiresAt()); return true; } catch (Exception e){ return false; } } }
package com.zxc.ticketsys.interceptor; import com.alibaba.fastjson.JSONObject; import com.zxc.ticketsys.utils.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"); 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; } }
package com.zxc.ticketsys.config; import com.zxc.ticketsys.interceptor.TokenInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor; import org.springframework.web.servlet.config.annotation.*; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executors; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * 跨域請求支持/token攔截 * tip:只能寫在一個配置類裏 */ @Configuration public class WebConfiguration implements WebMvcConfigurer { private TokenInterceptor tokenInterceptor; //構造方法 public WebConfiguration(TokenInterceptor tokenInterceptor){ this.tokenInterceptor = tokenInterceptor; } @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowCredentials(true) .allowedHeaders("*") .allowedMethods("*") .allowedOrigins("*"); } @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("/user/register"); //登陸 excludePath.add("/user/login"); //註冊 excludePath.add("/static/**"); //靜態資源 excludePath.add("/assets/**"); //靜態資源 registry.addInterceptor(tokenInterceptor) .addPathPatterns("/**") .excludePathPatterns(excludePath); WebMvcConfigurer.super.addInterceptors(registry); } }
package com.zxc.ticketsys.controller; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.zxc.ticketsys.model.User; import com.zxc.ticketsys.utils.TokenUtil; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; @RestController @RequestMapping("/user") public class UserController{ @RequestMapping(value = "/login",method = RequestMethod.POST) @ResponseBody public String login(@RequestBody Map<String,Object> para) throws JsonProcessingException { String username=(String)para.get("username"); String password=(String)para.get("password"); String token= TokenUtil.sign(new User(username,password)); HashMap<String,Object> hs=new HashMap<>(); hs.put("token",token); ObjectMapper objectMapper=new ObjectMapper(); return objectMapper.writeValueAsString(hs); } @RequestMapping(value = "/test",method = RequestMethod.POST) @ResponseBody public String test(@RequestBody Map<String,Object> para) throws JsonProcessingException { HashMap<String,Object> hs=new HashMap<>(); hs.put("data","data"); ObjectMapper objectMapper=new ObjectMapper(); return objectMapper.writeValueAsString(hs); } }
帶有效token訪問test接口
訪問成功,得到數據。
webpack
githubios