Spring Boot + JWT + Vue

实现功能

前端登录成功后 后端给前端一个token 之后前端带着这个token去进行操作并让后端检验

后端搭建

编写实体类

package com.jie.bootjwt.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String username;
    private String password;
    private String token;
}

编写工具类 生成token

package com.jie.bootjwt.util;

import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;
import java.util.UUID;

public class JwtUtil {
    private static long time=1000*60*60*24;
    private static String signature="admin";

    public static String CreateToken(){
        JwtBuilder jwtBuilder= Jwts.builder();
        String jwtToken=jwtBuilder
                .setHeaderParam("typ","JWT")
                .setHeaderParam("alg","HS256")
                .claim("username","tom")
                .setSubject("admin")
                .setExpiration(new Date(System.currentTimeMillis()+time))
                .setId(UUID.randomUUID().toString())
                .signWith(SignatureAlgorithm.HS256,signature)
                .compact();
        return jwtToken;
    }
}

编写控制类 这里就不连数据库了

package com.jie.bootjwt.controller;

import com.jie.bootjwt.pojo.User;
import com.jie.bootjwt.util.JwtUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {
    private final String USERNAME="root";
    private final String PASSWORD="123456";
    @GetMapping("/login")
    public User login(User user){
        if(user.getUsername().equals(USERNAME) && user.getPassword().equals(PASSWORD)){
            //登录成功 添加token
            user.setToken(JwtUtil.CreateToken());
            return user;
        }
        return null;
    }
}

控制类添加@CrossOrigin注解解决垮域问题

前端编写

输入vue create jwt-demo创建项目
安装ele
npm install element-ui -S
main.js中引入ele

import Element from "element-ui";
import "element-ui/lib/theme-chalk/index.css";

Vue.use(Element);

安装axios
vue add axios
编写一个简单的登录页面

<template>
  <div>
    <el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
      <el-form-item label="用户名" prop="username">
        <el-input v-model="ruleForm.username"></el-input>
      </el-form-item>
      <el-form-item label="密码" prop="password">
        <el-input type="password" v-model="ruleForm.password" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>


export default {
  data() {
    return {
      ruleForm: {
        username: '',
        password: '',
      },
      rules: {
        password: [
          { require:true,message:'请输入密码', trigger: 'blur' }
        ],
        username: [
          { require:true,message:'请输入用户名', trigger: 'blur'}
        ]
      }
    };
  },
  methods: {
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          let _this=this
          axios.get('http://localhost:8181/login',{params:_this.ruleForm}).then(
              function (resp){
                console.log(resp.data)
              }
          )
        } else {
          console.log('error submit!!');
          return false;
        }
      });
    },
  }
}
</script>

<style scoped>

</style>

使用axios提交数据给后端 并获取后端返回的数据

if (valid) {
          let _this=this
          axios.get('http://localhost:8181/login',{params:_this.ruleForm}).then(
              function (resp){
                console.log(resp.data)
              }
          )
        }

测试发现成功获得

实现token的检验

首先在登录成功后 我们吧token保存到本地数据里面 之后所有操作都会去检查这个token

if (valid) {
          let _this=this
          axios.get('http://localhost:8181/login',{params:_this.ruleForm}).then(
              function (resp){
               if(resp.data!=null){//成功获取
                 //将JSON转化成字符串格式 保存在localStorage中
                 localStorage.setItem("access-admin",JSON.stringify(resp.data))
                 //跳转到登录页面
                 _this.$router.replace({path:'/'})
               }
              }
          )
        }

写两个网页可以互相跳转 模拟平时上网的操作
home.vue

<template>
  <div class="home">
    欢迎 {{admin.username}}
    <div id="nav">
      <router-link to="/about">下载</router-link>
    </div>
    <h1>这是首页</h1>
  </div>
</template>

<script>
// @ is an alias to /src


export default {
  data(){
      return {
        admin:''
      }
    },
  created() {
    this.admin=JSON.parse(window.localStorage.getItem('access-admin'))
  }
}
</script>

about.vue

<template>
  <div class="about">
    欢迎 {{admin.username}}
    <div id="nav">
      <router-link to="/">首页</router-link>
    </div>
    <a href="">资源1</a> |
    <a href="">资源2</a> |
    <a href="">资源3</a> |
    <a href="">资源4</a> |
    <a href="">资源5</a> |
  </div>
</template>
<script>
export default {
  data(){
    return {
      admin:''
    }
  },
  created() {
    this.admin=JSON.parse(window.localStorage.getItem('access-admin'))
  }
}
</script>

配置路由规则

由于要实现在任何跳转上vue的路由上进行设置
index.js代码

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Login from "@/views/Login";
import Error from "@/views/Error";

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/login',
    name: 'Login',
    component: Login
  },
  {
    path: '/error',
    name: 'Error',
    component: Error
  },
  {
    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: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]

const router = new VueRouter({
  routes
})
//路由设置
router.beforeEach((to,from,next)=>{
  if(to.path.startsWith('/login')){
    //如果访问的是登录页面 就删除旧的token
    window.localStorage.removeItem('access-admin')
    next()
  }
  else {
    //尝试获取token
    let admin=JSON.parse(window.localStorage.getItem('access-admin'))
    //如果没有token就直接跳转到登录页面
    if(!admin){
      next({path:'/login'})
    }
    else {
      //检查token是否正确
      axios({
        url:'http://localhost:8181/checkToken',
        method:'get',
        //将信息保存在header里
        headers:{
          token:admin.token
        }
      }).then((response)=>{
          if(!response.data){
            console.log('检验失败')
            next({path:'/error'})
          }
      })
      next()
    }
  }
})
export default router

编写一个error组件用于提醒token失效同时跳转

<template>

</template>

<script>
export default {
  name: "Error",
  created() {
    let _this=this
    this.$alert('登录信息失效','提示',{
      confirmButtonText:'确定'
    }).then((response)=>{
      localStorage.removeItem('access-admin')
      _this.$router.replace({path:'/login'})
    })
  }
}
</script>

<style scoped>

</style>

后端实现检查token功能

工具类添加检查方法

public static boolean CheckToken(String token){
        if(token==null) return false;
        JwtParser jwtParser=Jwts.parser();
        //进行解密
        try{
            Jws<Claims> claimsJws = jwtParser.setSigningKey(signature).parseClaimsJws(token);
        }
        catch (Exception e){
        //出现异常即说明token失效或者其他问题
            return false;
        }
        return true;
    }

控制类调用该方法即可

@GetMapping("/checkToken")
    public Boolean checkToken(HttpServletRequest request){
        String token = request.getHeader("token");
        return JwtUtil.CheckToken(token);
    }

为了方便测试 我们吧token的生存时间效果到6秒

测试在点击网页过了6秒后就会提示信息失效

posted @ 2021-08-23 17:39  一个经常掉线的人  阅读(409)  评论(0)    收藏  举报