springboot+vue实现token验证

目录


后端:

<!--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>&nbsp;&nbsp;&nbsp;&nbsp;
        </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/>'
})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值