【极简入门】30分钟学会 Spring Boot + JWT + Vue前后端分离登录认证
  px8Y25gMnWbQ 2023年11月02日 19 0


新建项目

新建springboot项目,内建vue模块,如图

【极简入门】30分钟学会 Spring Boot + JWT + Vue前后端分离登录认证_spring boot

 

【极简入门】30分钟学会 Spring Boot + JWT + Vue前后端分离登录认证_vue.js_02

springboot后端

导入依赖

jwt依赖

<dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.15</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.shrimpking</groupId>
    <artifactId>springboot-63</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-63</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

配置

application.properties

server.port=8089

pojo

user.java

package com.shrimpking.pojo;

import lombok.Data;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2023/9/14 18:10
 */
@Data
public class User
{
    private Integer id;
    private String username;
    private String password;
    private String token;
}

controller

userController.java

package com.shrimpking.controller;

import com.shrimpking.pojo.User;
import com.shrimpking.utils.JwtUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2023/9/14 18:12
 */
@RestController
public class UserController
{
    private final String USERNAME = "admin";
    private final String PASSWORD = "1234";

    @GetMapping("/login")
    public User login(User user){
        if(USERNAME.equals(user.getUsername()) && PASSWORD.equals(user.getPassword())){
            //添加token
            user.setToken(JwtUtil.createToken());
            return user;
        }
        return null;
    }

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

}

解决跨域访问

config

package com.shrimpking.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

// 案例 一
@Configuration
public class CorsConfig implements WebMvcConfigurer
{
 
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                //是否发送Cookie
                .allowCredentials(true)
                //放行哪些原始域
                .allowedOriginPatterns("*")
                .allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"})
                .allowedHeaders("*")
                .exposedHeaders("*");
    }
}

工具类

jwtutils

package com.shrimpking.utils;

import ch.qos.logback.classic.turbo.TurboFilter;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

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

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2023/9/14 18:50
 */
public class JwtUtil
{
    //1天
    //private static long time = 1000 * 60 * 60 * 24;
    private static long time = 1000 * 5;
    private static String signature = "king";

    public static String createToken(){
        JwtBuilder jwtBuilder = Jwts.builder();
        String token = jwtBuilder
                //header
                .setHeaderParam("typ","JWT")
                .setHeaderParam("alg","HS256")
                //payload
                .claim("username","admin")
                .claim("role","admin")
                .setSubject("admin-test")
                .setExpiration(new Date(System.currentTimeMillis() + time))
                .setId(UUID.randomUUID().toString())
                .signWith(SignatureAlgorithm.HS256, signature)
                .compact();
        return token;
    }

    public static boolean checkToken(String token){
        if(token == null){
            return false;
        }

        try
        {
            //token是否能正常解析,出现异常说明token异常
            JwtParser jwtParser = Jwts.parser();
            Jws<Claims> claimsJws = jwtParser.setSigningKey(signature).parseClaimsJws(token);
        }
        catch (Exception e)
        {
            return false;
        }
        return true;
    }

}

vue前端

配置

main.js

import Vue from 'vue'
import App from './App.vue'
import store from '@/store'
import router from "@/router";
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import axios from "axios";

axios.defaults.baseURL='http://localhost:8089';
Vue.prototype.$http = axios;
Vue.use(ElementUI,{size:'small'});
Vue.config.productionTip = false;

new Vue({
  render: h => h(App),
  store,
  router
}).$mount('#app');

app.vue

<template>
  <div id="app">
    <router-view/>
  </div>
</template>

<style lang="scss">

</style>

router.js

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

Vue.use(VueRouter);

const routes = [
  {
    path:'/',
    redirect:'/login'
  },
  {
    path:'/login',
    name:'Login',
    component:Login
  },
  {
    path:'/home',
    name:'Home',
    component: Home
  },
  {
    path:'/about',
    name:'About',
    component:About
  },
  {
    path:'/error',
    name:'Error',
    component:Error
  }
];

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
});

//导航守卫
router.beforeEach( (to, from, next) =>{
  //前往登录的,把本地存储的user删除
  if(to.path.startsWith('/login')){
    window.localStorage.removeItem('access-admin');
    next();
  }else {
    let admin = JSON.parse(window.localStorage.getItem('access-admin'));
    if(!admin){
      next({path:'/login'});
    } else {
      //校验token的合法性
      axios({
        url:'/checkToken',
        method:'get',
        headers:{
          token: admin.token
        }
      })
    .then( (res) => {
        if(!res.data){
          //验证失败
          console.log('校验失败');
          next({path:'/error'});
        }
      });
      next();
    }
  }
});

export default router

views

login.vue

<template>
    <div style="width: 400px;height: 300px;margin: 100px auto;
        border: 1px solid gray;border-radius: 15px;padding: 20px;">
        <h1 style="margin-bottom: 45px; text-align: center;">系统登录</h1>
        <el-form
                ref="ruleForm"
                :model="ruleForm"
                :rules="rules"
                label-width="80px"
                label-position="left">
            <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 v-model="ruleForm.password" type="password"></el-input>
            </el-form-item>
            <el-form-item>
                <el-button type="primary"
                           @click="onSubmit"
                           style="width: 200px;margin-left: 30px;margin-top: 26px;">
                    登录
                </el-button>
            </el-form-item>
        </el-form>
    </div>
</template>

<script>
    export default {
        name: "Login",
        data(){
            return {
                ruleForm:{
                    username:'admin',
                    password:'1234'
                },
                rules:{
                    username:[{required: true, message:'请输入用户名', trigger: 'blur'}],
                    password: [{required: true, message: '请输入密码', trigger: 'blur'}]
                }
            }
        },
        methods:{
            onSubmit(){
                this.$refs.ruleForm.validate( (valid) => {
                    if(valid){
                        this.$http.get('/login',{ params:this.ruleForm})
                            .then(res => {
                                console.log(res);
                                if(res.data !== ""){
                                    //登录成功
                                    localStorage.setItem("access-admin",JSON.stringify(res.data));
                                    this.$message.success('登录成功');
                                    this.$router.push('/home');
                                }else {
                                    this.$message.error('用户名或密码错误!');
                                }
                            })
                    } else {
                        //啥都没填
                        console.log('error login');
                        return false;
                    }
                })
            }
        }
    }
</script>

<style scoped>

</style>

home.vue

<template>
    <div>
        <p>用户:{{ admin.username }}</p>
        <div id="nav">
            <router-link to="/about">下载</router-link>
        </div>
        <h1>这是首页</h1>
    </div>
</template>

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

<style scoped>

</style>

about.vue

<template>
    <div>
        <p>用户:{{ admin.username }}</p>
        <div id="nav">
            <router-link to="/home">返回首页</router-link>
        </div>
        <a href="#">资源1</a>
        <a href="#">资源2</a>
        <a href="#">资源3</a>
        <a href="#">资源4</a>
        <a href="#">资源5</a>
        <a href="#">资源6</a>
    </div>
</template>

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

<style scoped>
    #nav{
        margin-bottom: 30px;
    }
    a{
        margin-left: 10px;
    }
</style>

error.vue

<template>
    <div>
        <h1>ERROR</h1>
        <h3>出错了!!!</h3>
    </div>
</template>

<script>
    export default {
        name: "Error",
        created(){
            this.$alert('登录信息失效,点击确定3秒后回到登录页面','提示',{
                confirmButtonText:'确定'
            }).then(() => {
                window.localStorage.removeItem('access-admin');
                setTimeout(() =>{
                    this.$router.push('/login');
                },3000);
            })
        }
    }
</script>

<style scoped>

</style>

测试

登录

【极简入门】30分钟学会 Spring Boot + JWT + Vue前后端分离登录认证_spring_03

首页

【极简入门】30分钟学会 Spring Boot + JWT + Vue前后端分离登录认证_vue.js_04

 等待5秒后,点击下载

【极简入门】30分钟学会 Spring Boot + JWT + Vue前后端分离登录认证_json_05

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  E929ZvlRxyUs   2023年12月23日   37   0   0 前端url前端URL
px8Y25gMnWbQ