目录
后端:
<!--token--> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.4.0</version> </dependency>
/** * @author :ZWQ * @version :1.0 * @date :2019/10/16 - 18:52 * @description : */ @Service public class TokenService { public String getToken(User user) { Date start = new Date(); long currentTime = System.currentTimeMillis() + 60* 60 * 1000;//一小时有效时间 Date end = new Date(currentTime); String token = ""; token = JWT.create().withAudience(user.getUserId().toString()).withIssuedAt(start).withExpiresAt(end) .sign(Algorithm.HMAC256(user.getPassword())); return token; } }@RestController @RequestMapping("/user") public class UserController { @Autowired UserService userService; @Autowired TokenService tokenService; /** * 登录方法 * @param request * @return ModelAndView */ @RequestMapping("/login") public String login(@RequestBody User user, HttpServletRequest request) { System.out.println(user.getUserName()+" "+user.getPassword()); User userForBase=userService.getUserByUsername(user.getUserName(), user.getPassword()); System.out.println("------------------------------"+userForBase); if(userForBase==null){ String msg = "用户名或者密码错误"; return msg; } String token = tokenService.getToken(userForBase); System.out.println(token); return token; } /*测试token 不登录没有token*/ @UserLoginToken @GetMapping("/getMessage") public String getMessage(){ return "你已通过验证"; }
package com.springboot.interceptor; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.exceptions.JWTVerificationException; import com.springboot.annotation.PassToken; import com.springboot.annotation.UserLoginToken; import com.springboot.pojo.User; import com.springboot.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.lang.reflect.Method; /** * @author :ZWQ * @version :1.0 * @date :2019/10/16 - 18:47 * @description :拦截器去获取token并验证token */ public class AuthenticationInterceptor implements HandlerInterceptor { @Autowired UserService userService; @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception { String token = httpServletRequest.getHeader("token");// 从 http 请求头中取出 token // 如果不是映射到方法直接通过 if (!(object instanceof HandlerMethod)) { return true; } HandlerMethod handlerMethod = (HandlerMethod) object; Method method = handlerMethod.getMethod(); //检查是否有passtoken注释,有则跳过认证 if (method.isAnnotationPresent(PassToken.class)) { PassToken passToken = method.getAnnotation(PassToken.class); if (passToken.required()) { return true; } } //检查有没有需要用户权限的注解 if (method.isAnnotationPresent(UserLoginToken.class)) { UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class); if (userLoginToken.required()) { // 执行认证 if (token == null) { throw new RuntimeException("无token,请重新登录"); } // 获取 token 中的 user id String userId = null; int id = Integer.parseInt(userId); try { userId = JWT.decode(token).getAudience().get(0); } catch (JWTDecodeException j) { throw new RuntimeException("401"); } User user = userService.findUserById(id); if (user == null) { throw new RuntimeException("用户不存在,请重新登录"); } // 验证 token JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build(); try { jwtVerifier.verify(token); } catch (JWTVerificationException e) { throw new RuntimeException("401"); } return true; } } return true; } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { } }
package com.springboot.config; import com.springboot.interceptor.AuthenticationInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * @author :ZWQ * @version :1.0 * @date :2019/10/16 - 18:49 * @description : */ @Configuration public class InterceptorConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(authenticationInterceptor()) .addPathPatterns("/**"); // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录 } @Bean public AuthenticationInterceptor authenticationInterceptor() { return new AuthenticationInterceptor(); } }
package com.springboot.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author :ZWQ * @version :1.0 * @date :2019/10/16 - 18:44 * @description :用来跳过验证的PassToken */ @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface PassToken { boolean required() default true; }package com.springboot.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author :ZWQ * @version :1.0 * @date :2019/10/16 - 18:46 * @description :需要登录才能进行操作的注解UserLoginToken */ @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface UserLoginToken { boolean required() default true; }
VUE
login.vue
<template> <div id="logo"> <div class="login-box" style="margin-top:200px"> <!-- 通过:rules="loginFormRules"来绑定输入内容的校验规则 --> <el-form :rules="loginFormRules" ref="LoginForm" :model="loginForm" label-position="right" label-width="auto" show-message> <span class="login-title" style="margin-left:-110px;font-size:30px">欢迎登录</span> <div style="margin-top: 5px"></div> <el-form-item label="用户名" prop="userName" style="margin-left:500px;margin-top:30px;font-weight:bold"> <el-col :span="8" > <el-input type="text" v-model="loginForm.userName"></el-input> </el-col> </el-form-item> <el-form-item label="密码" prop="password" style="margin-left:500px;font-weight:bold"> <el-col :span="8" > <el-input type="password" v-model="loginForm.password"></el-input> </el-col> </el-form-item> <el-form-item> <el-button type="primary" @click="login('LoginForm')" style="margin-left:-180px">登录</el-button> </el-form-item> </el-form> <p>还没有账号? 现在<router-link to='/register'>注册</router-link></p> </div> </div> </template> <script> import jwt from 'jwt-decode'; export default { name: "login", data () { return { loginForm: { userName: '', password: '' }, // 表单验证,需要在 el-form-item 元素中增加 prop 属性 loginFormRules: { userName: [ {required: true, message: '账号不可为空', trigger: 'blur'}, /* {min: 2,max: 7,message: '长度在 2 到 7 个字符'}, {pattern: /^[\u4E00-\u9FA5]+$/, message: '用户名只能为中文'}*/ ], password: [ {required: true, message: '密码不可为空', trigger: 'blur'} ] } } }, methods: { login (LoginForm) { this.$refs[LoginForm].validate( valid =>{ if(valid){ this.$axios.post('/user/login',this.loginForm).then( res =>{ //登陆成功 使用token const token = res.data; console.log(token); /*存储到ls*/ localStorage.setItem('eleToken',token); /*解析token中的信息*/ const decoded = jwt(token); /*存储至vuex*/ this.$store.dispatch("setAuthenticated",!this.isEmpty(decoded)) //decoded空,函数返回真,取反假 this.$store.dispatch("setUser",decoded) /*跳转*/ this.$router.push('/index/welcome'); }) } }) }, isEmpty(value){ return( value ===undefined || value ===null || (typeof value === "object" && Object.keys(value).length ===0) || (typeof value ==="string" && value.trim().length ===0) ); } } }; </script>
http.js
/** * axios请求配置 */ import axios from 'axios' import { Loading } from 'element-ui'; /*elementUI的loading*/ import { Message } from 'element-ui'; /*elementUI消息提醒*/ /*import { Message,Loading } from 'element-ui'; 也可以这样解构赋值*/ import router from '../router/index' let loading; function startLoading () { loading = Loading.service({ /*在需要调用时:*/ lock: true, text: '拼命加载中...', background: 'rgba(0,0,0,0,7)' }); } function endLoading () { loading.close(); } //请求拦截 axios.interceptors.request.use(config => { //加载动画 startLoading(); /*判断token存在 登录拦截*/ if(localStorage.eleToken){ /*设置统一的header*/ config.headers.Authorization = localStorage.eleToken; } return config; },error => { return Promise.reject(error); }); //响应拦截 axios.interceptors.response.use(Response => { //结束加载动画 endLoading(); return Response; },error => { //错误提醒 endLoading(); Message.error(error.response.data); /*获取错误状态码*/ const { status } =error.response; if(status == 401){ Message.error("token失效,重新登录"); /*清楚token*/ localStorage.removeItem('eleToken'); /*跳转登录*/ router.push('/') } return Promise.reject(error); }) export default axios;
store.js
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex) const types ={ SET_AUTHENTICATED: 'SET_AUTHENTICATE', SET_USER: 'SET_USER', }; const state = { isAuthenticated: false, user: {} }; const getters ={ isAuthenticated: state =>state.isAuthenticated, user: state => state.user }; const mutations ={ [types.SET_AUTHENTICATED](state,isAuthenticated){ /*设置是否授权*/ if(isAuthenticated) state.isAuthenticated = isAuthenticated; else state.isAuthenticated = false; }, /*类型,参数*/ [types.SET_USER](state,user){ if (user) state.user = user; else state.user = {}; } }; /*异步操作 调用mutations*/ const actions ={ setAuthenticated:( {commit},isAuthenticated) =>{ commit(types.SET_AUTHENTICATED,isAuthenticated); }, setUser:({commit},user) =>{ commit(types.SET_USER,user); } }; export default new Vuex.Store({ state, getters, mutations, actions });import Vue from 'vue' import Router from 'vue-router' import Index from '../pages/Index' import Login from '../pages/login/Login' import Registr from '../pages/login/Registr' import NotFound from '../pages/404' Vue.use(Router) const router = new Router({ routes: [ { path: '/', name: 'login', component: Login }, { path: '/index', name: 'index', component: Index },{ path: '/register', name: 'register', component: Registr },{ path: '*', name: '/404', component: NotFound } ] }) /*路由守卫 根据登录获得token*/ router.beforeEach((to,from,next) =>{ const isLogin = localStorage.eleToken ? true :false ; if(to.path ==="/" || to.path ==="/register"){ next(); }else{ isLogin ? next() :next("/") /*真跳转 假注册*/ } }) export default router<template> <div id="app"> <router-view/> </div> </template> <script> import jwt from 'jwt-decode'; export default { name: "App", comments:{}, created(){ /*在根组件进行判断,否则刷新就没了*/ if (localStorage.eleToken){ const decoded = jwt(localStorage.eleToken); /*存储至vuex*/ this.$store.dispatch("setAuthenticated",!this.isEmpty(decoded)) this.$store.dispatch("setUser",decoded) } }, methods: { isEmpty(value){ return( value ===undefined || value ===null || (typeof value === "object" && Object.keys(value).length ===0) || (typeof value ==="string" && value.trim().length ===0) ); } } }; </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
main.js
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; import axios from './api/http' /*配置axios*/ import store from './store/index' Vue.use(ElementUI); Vue.config.productionTip = false Vue.prototype.$axios = axios axios.defaults.baseURL ='/api'; /* eslint-disable no-new */ new Vue({ el: '#app', router, store, components: { App }, template: '<App/>' })