springboot+vue前后端分离项目中使用jwt实现登录认证

news2024/9/23 7:32:36

文章目录

  • 一、后端代码
    • 1.响应工具类
    • 2.jwt工具类
    • 3.登录用户实体类
    • 4.登录接口
    • 5.测试接口
    • 6.过滤器
    • 7.启动类
  • 二、前端代码
    • 1.登录页
    • index 页面
  • 三、效果展示


一、后端代码

1.响应工具类

package com.etime.util;

import com.etime.vo.ResponseModel;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.MediaType;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @Date 2024/6/10 10:00
 * @Author liukang
 **/
public class ResponseUtil {
    public static void write(ResponseModel rm, HttpServletResponse response) throws IOException {
        // 构造响应头
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("utf-8");
        // 解决跨域问题 设置跨域头
        response.setHeader("Access-Control-Allow-Origin","*");
        // 输出流
        PrintWriter out = response.getWriter();
        // 输出
        out.write(new ObjectMapper().writeValueAsString(rm));
        // 关闭流
        out.close();
    }
}

2.jwt工具类

package com.etime.util;

import io.jsonwebtoken.*;

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

/**
 * @Date 2024/6/10 10:04
 * @Author liukang
 **/
public class JwtUtil {
    private static String secret = "secret";

    /**
     * 创建jwt
     * @author liukang
     * @date 10:36 2024/6/10
     * @param expire
     * @param map
     * @return java.lang.String
     **/
    public static String generateToken(long expire, Map map){
        // 床jwt构造器
        JwtBuilder jwtBuilder = Jwts.builder();
        // 生成jwt字符串
        String jwt = jwtBuilder
                //头部
                .setHeaderParam("typ","JWT")
                .setHeaderParam("alg","HS256")
                // 载荷
                .setClaims(map) // 设置多个自定义数据  位置只能放在前面,如果放在后面,那前面的载荷会失效
                .setId(UUID.randomUUID().toString())// 唯一标识
                .setIssuer("liukang")// 签发人
                .setIssuedAt(new Date())// 签发时间
                .setSubject("jwtDemo")// 主题
                .setExpiration(new Date(System.currentTimeMillis()+expire))//过期时间
                // 签名
                .signWith(SignatureAlgorithm.HS256,secret)
                .compact();
        return jwt;
    }
    /**
     * 创建jwt
     * @author liukang
     * @date 10:36 2024/6/10
     * @param expire
     * @return java.lang.String
     **/
    public static String generateToken(long expire){
        // 床jwt构造器
        JwtBuilder jwtBuilder = Jwts.builder();
        // 生成jwt字符串
        String jwt = jwtBuilder
                //头部
                .setHeaderParam("typ","JWT")
                .setHeaderParam("alg","HS256")
                // 载荷
                .setId(UUID.randomUUID().toString())// 唯一标识
                .setIssuer("liukang")// 签发人
                .setIssuedAt(new Date())// 签发时间
                .setSubject("jwtDemo")// 主题
                .setExpiration(new Date(System.currentTimeMillis()+expire))//过期时间
                // 签名
                .signWith(SignatureAlgorithm.HS256,secret)
                .compact();
        return jwt;
    }
    /**
     * 解析jwt
     * @author liukang
     * @date 10:36 2024/6/10
     * @param jwt
     * @return io.jsonwebtoken.Claims
     **/
    public static Claims parseToken(String jwt){
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(secret).parseClaimsJws(jwt);
        Claims playload = claimsJws.getBody();
        return playload;

    }
}

3.登录用户实体类

package com.etime.entity;

import lombok.Data;

/**
 * @Date 2024/6/10 10:39
 * @Author liukang
 **/
@Data
public class User {
    private String username;
    private String password;
}

4.登录接口

package com.etime.controller;

import com.etime.entity.User;
import com.etime.util.JwtUtil;
import com.etime.vo.ResponseModel;
import org.springframework.web.bind.annotation.*;

/**
 * @Date 2024/6/10 10:38
 * @Author liukang
 **/
@RestController
@CrossOrigin
public class LoginController {
    @PostMapping("/login")
    public ResponseModel login(@RequestBody User user){
        Integer code = 200;
        String msg = "success";
        String token = null;
        if(user.getUsername().equals("admin")&&user.getPassword().equals("123")){
            // 生成jwt
            token = JwtUtil.generateToken(1000*10);// 设置有效期为10s
        }else {
            code = 500;
            msg = "failure";
        }
        return new ResponseModel(code,msg,token);
    }


}

5.测试接口

package com.etime.controller;

import com.etime.vo.ResponseModel;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Date 2024/6/10 12:51
 * @Author liukang
 **/
@CrossOrigin
@RestController
public class TestController {
    @PostMapping("/test")
    public ResponseModel test() {
        return new ResponseModel(200,"success","测试请求接口成功!");
    }

}

6.过滤器

package com.etime.filter;

import com.etime.util.JwtUtil;
import com.etime.util.ResponseUtil;
import com.etime.vo.ResponseModel;
import com.sun.deploy.net.HttpResponse;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRequest;
import org.springframework.util.StringUtils;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @Description jwt过滤器
 * @Date 2024/6/10 9:46
 * @Author liukang
 **/
@WebFilter(urlPatterns = "/*") // 过滤所有路径
public class JwtFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 得到两个对象
        HttpServletRequest request =  (HttpServletRequest) servletRequest;
        HttpServletResponse response =  (HttpServletResponse) servletResponse;
        //直接放行
        if(HttpMethod.OPTIONS.toString().equals(request.getMethod())){
            filterChain.doFilter(request,response);
            return;
        }
        String requestURI = request.getRequestURI(); // 不含主机和端口号
        if(requestURI.contains("/login")){
            filterChain.doFilter(request,response);
            return;
        }
        // 得到请求头的信息(accessToken)
        String token = request.getHeader("accessToken");
        if(!StringUtils.hasText(token)){
            //响应前端错误的消息提示
            ResponseModel responseModel = new ResponseModel(500,"failure","令牌缺失!");
            ResponseUtil.write(responseModel,response);
            return;
        }
        // 解析Token信息
        try {
            JwtUtil.parseToken(token);
        }catch (Exception e){
            //响应前端错误的消息提示
            ResponseModel responseModel = new ResponseModel(401,"failure","令牌过期!");
            ResponseUtil.write(responseModel,response);
            return;
        }
        filterChain.doFilter(request,response);


    }
}

7.启动类

package com.etime;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

/**
 * @Author liukang
 * @Date 2022/7/4 11:32
 */
@SpringBootApplication
@ServletComponentScan(basePackages = "com.etime.filter")// 这个包下激活WebFilter这个注解
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
}

二、前端代码

1.登录页

<template>
    <div class="hello">
      <form>
        用户名:<input v-model="username"/>
        <br>
        密码<input v-model="password" />
        <br>
        <button @click="login">登录</button>
      </form>

    </div>
  </template>

  <script>


  export default {
    data () {
      return {
        username:'',
        password:'',

      }
    },
    methods:{
        login(){
          this.axios.post('http://localhost:8088/login',{

            username:this.username,
            password:this.password,

          }).then(response => {
              console.log(response.data);
              if(response.data.code==200){
                sessionStorage.setItem("accessToken",response.data.token)
                this.$router.push({ path: 'index'});
              }
            }).catch(error => {
              console.error(error);
            });

        }
    },
  }
  </script>

  <style scoped>

  </style>

index 页面

<template>
    <div>
        <button @click="test">请求受保护的接口</button>
    </div>
  </template>

  <script>
  export default {
    data () {
      return {
      }
    },
    methods:{
      test(){
        const accessToken = sessionStorage.getItem('accessToken')
        let token = null
        if(accessToken){
          token = accessToken
        }
        console.log(token)
        this.axios.post('http://localhost:8088/test',{},{headers:{accessToken:token}
        }).then(response => {
          // if(response.data.code==200){
            console.log(response.data);
          // }
        }).catch(error => {
          console.error(error);
        });
      },
    
    },
  }
  </script>

  <style scoped>

  </style>


三、效果展示

1.点击登录后,后端给前端办法jwt令牌,前端将其存入sessionStorage中
在这里插入图片描述
2.点击【请求后端受保护的接口】按钮
在这里插入图片描述
3.继续多次点击【请求后端受保护的接口】按钮
在这里插入图片描述
可以看见,请求几次成功后,便显示令牌过期,这是因为,为了测试方便,我们颁发令牌时有效期设置的10秒
在这里插入图片描述
4.在请求接口中不传递Token
在这里插入图片描述
重新登录并点击【请求后端受保护的接口】按钮
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1813735.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RAG核心算法

一、分块与向量化 首先,我们的目标是创建一个向量索引,用以代表我们文档的内容,然后在运行时寻找所有这些向量与查询向量之间的最小余弦距离,以匹配最接近的语义含义。 1、分块 由于 Transformer 模型具有固定的输入序列长度,即便输入上下文窗口很大,一个句子或几个句…

【全网最有效,保姆级教程】KEPServerEX 6下载安装解决时长问题

1、下载KEPServer KEPServerEX 6下载链接(为了防止版本不兼容&#xff0c;一定要使用下面链接里面的版本&#xff01;)&#xff1a; https://pan.baidu.com/s/19pAXzhWa5nxduU3mi1V4Nw?pwd1234 提取码:1234 2、安装KEPServer 基本上都是默认下一步&#xff0c;选择中文&…

python中用列表实现栈

【小白从小学Python、C、Java】 【考研初试复试毕业设计】 【Python基础AI数据分析】 python中用列表实现栈 选择题 以下代码最后一次输出的结果是&#xff1f; stack [] stack.append(1) stack.append(2) stack.append(3) print(【显示】stack ,stack) print(【显示】stack.…

SpringCloud 前端-网关-微服务-微服务间实现信息共享传递

目录 1 网关获取用户校验信息并保存至请求头&#xff08;前端-网关&#xff09; 2 微服务获取网关中的用户校验信息&#xff08;网关-微服务&#xff09; 2.1 一般的做法是在公共的module中添加&#xff0c;此处示例为common 公共配置module中添加 2.2 定义拦截器 2.3 定义…

C++|哈希结构封装unordered_set和unordered_map

上一篇章&#xff0c;学习了unordered系列容器的使用&#xff0c;以及哈希结构&#xff0c;那么这一篇章将通过哈希结构来封装unordered系列容器&#xff0c;来进一步的学习他们的使用以及理解为何是如此使用。其实&#xff0c;哈希表的封装方式和红黑树的封装方式形式上是差不…

鸿蒙低代码开发的局限性

在版本是DevEco Studio 3.1.1 Release&#xff0c;SDK是3.1.0(API9) 的基础上。 1、低代码插件没有WebView组件。 2、低代码插件没有空白的自定义组件&#xff0c;当前提供的所谓自定义组件&#xff0c;只能用列表中提供的组件来拼接新的组件。 3、使用ets代码自定义的组件&…

JVM 常量池汇总

Tips JVM常量池分为静态常量池和运行时常量池&#xff0c;因为Jdk1.7后字符串常量池从运行时常量池存储位置剥离&#xff0c;故很多博客也是区分开来&#xff0c;存储位置和内容注意区别&#xff01; 字符串常量池底层是由C实现&#xff0c;是一个类似于HashTable的数据结构&am…

Spring 中使用MyBatis

一、Mybatis 的作用 1、MyBatis&#xff08;前身为iBatis&#xff09;是一个开源的Java持久层框架&#xff0c;它主要用于与数据库交互&#xff0c;帮助开发者更轻松地进行数据库操作。 持久层&#xff1a;指的是就是数据访问层(dao)&#xff0c;是用来操作数据库的。 2、MyB…

Filament 【表单操作】修改密码

场景描述&#xff1a; 新增管理员信息时需要填写密码&#xff0c;修改管理员信息时密码可以为空&#xff08;不修改密码&#xff09;&#xff0c;此时表单中密码输入有冲突&#xff0c;需要对表单中密码字段进项条件性的判断&#xff0c;使字段在 create 操作时为必需填写&…

深度学习-注意力机制和分数

深度学习-注意力机制 注意力机制定义与起源原理与特点分类应用领域实现方式优点注意力机制的变体总结注意力分数定义计算方式注意力分数的作用注意力分数的设计总结 注意力机制&#xff08;Attention Mechanism&#xff09;是一个源自对人类视觉研究的概念&#xff0c;现已广泛…

实测 WordPress 最佳优化方案:WP Super Cache+Memcached+CDN

说起 WordPress 优化加速来可以说是个经久不衰的话题了&#xff0c;包括明月自己都撰写发表了不少相关的文章。基本上到现在为止明月的 WordPress 优化方案已经固定成型了&#xff0c;那就是 WP Super CacheMemcachedCDN 的方案&#xff0c;因为这个方案可以做到免费、稳定、安…

如何用R语言ggplot2画高水平期刊散点图

文章目录 前言一、数据集二、ggplot2画图1、全部代码2、细节拆分1&#xff09;导包2&#xff09;创建图形对象3&#xff09;主题设置4&#xff09;轴设置5&#xff09;图例设置6&#xff09;散点颜色7&#xff09;保存图片 前言 一、数据集 数据下载链接见文章顶部 处理前的数据…

基于FreeRTOS+STM32CubeMX+LCD1602+MCP6S26(SPI接口)的6通道模拟可编程增益放大器Proteus仿真

一、简介: MCP6S26是模拟可 编程增益放大器(Programmable Gain Amplifiers, PGA)。它们可配置为输出 +1 V/V 到 +32 V/V 之间的增 益,输入复用器可通过 SPI 端口选择最多 6 个通道中的 一个。串行接口也可以将 PGA 置为关断模式,以降低 功耗。这些 PGA 针对高速度、低失调…

Python编程基础5

邮件编程 SMTP&#xff08;Simple Mail Transfer Protocol&#xff09;简单邮件传输协议&#xff0c;使用TCP协议25端口&#xff0c;它是一组用于由源地址到目的地址传送邮件的规则&#xff0c;由它来控制信件的中转方式。python的smtplib提供了一种很方便的途径发送电子邮件。…

【python】tkinter GUI开发: Button和Entry的应用实战探索

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

MySQL----排序ORDER BY

在对数据进行处理的时候&#xff0c;我们通常需要对读取的数据进行排序。而 MySQL 的也提供了 ORDER BY 语句来满足我们的排序要求。 ORDER BY 可以按照一个或多个列的值进行升序&#xff08;ASC&#xff09;或降序&#xff08;DESC&#xff09;排序。 语法 SELECT column1…

航班进出港管理系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;用户管理&#xff0c;航班信息管理&#xff0c;航飞降落请求管理&#xff0c;公告信息管理 前台账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;公告信息&a…

中国新兴的数字证书品牌——JoySSL

JoySSL是一个基于全球可信顶级根创新推出的新一代https数字证书&#xff0c;也是中国为数不多的自主品牌SSL证书。以下是关于JoySSL的详细介绍&#xff1a; 1 品牌背景&#xff1a; JoySSL是网盾安全旗下的产品&#xff0c;专注于网络安全技术服务、安全防护系统集成、数据安…

计算机网络知识CIDR(无类别域区间路由)

目录 介绍 基本信息 优点与关联 如何计算判定范围&#xff08;你应该是来看这个的&#xff0c;前面是水字数的&#xff09; 省流版 介绍 无类别域间路由&#xff08;Classless Inter-Domain Routing、CIDR&#xff09;是一个用于给用户分配IP地址以及在互联网上有效地路由…

【SkiaSharp绘图】01使用SkiaSharp绘制Hello World

文章目录 SkiaSharp简介主要特点适用场景 SkiaSharp的Hello World!1、创建一个.NET Framework项目2、拖入SKGLControl控件GLControl、SKControl、SKGLControl对比GLControlSKControlSKGLControl选择和使用场景高性能的选择 SKGLControl 3、绘制Hello World 为何选择SkiaSharpIm…