SpringBoot + Vue前后端分离项目实战 || 六:Jwt加密整合配置

这篇具有很好参考价值的文章主要介绍了SpringBoot + Vue前后端分离项目实战 || 六:Jwt加密整合配置。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

回顾

在之前的系统中,我们利用UUID配合Redis以达到角色登录的功能。

当前整个系统存在一个问题:人为修改token值后,用户仍然能在前端进行数据库操作,后台没有校验当前用户token就允许一些请求,导致系统存在安全漏洞

解决方法:Jwt签名验证。整合Jwt后,前端发出的请求后端会先进行token验证,然后执行操作。

整合Jwt的效果如下:找到token值,然后进行修改
SpringBoot + Vue前后端分离项目实战 || 六:Jwt加密整合配置,spring boot,vue.js,后端

token前加上值123,保存后进行一些操作
SpringBoot + Vue前后端分离项目实战 || 六:Jwt加密整合配置,spring boot,vue.js,后端

此时点击页面修改按钮,会弹出token错误的信息
SpringBoot + Vue前后端分离项目实战 || 六:Jwt加密整合配置,spring boot,vue.js,后端

后端也会记录token错误的信息
SpringBoot + Vue前后端分离项目实战 || 六:Jwt加密整合配置,spring boot,vue.js,后端
现在开始来实现这个功能

添加依赖

SpringBoot + Vue前后端分离项目实战 || 六:Jwt加密整合配置,spring boot,vue.js,后端

Jwt依赖

在pom文件中添加下述依赖

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

Jwt配置

common文件夹下新建一个文件夹utils,然后新建java文件JwtUtil
SpringBoot + Vue前后端分离项目实战 || 六:Jwt加密整合配置,spring boot,vue.js,后端

写上下述代码,注释已标出

package com.ums.common.utils;

import com.alibaba.fastjson2.JSON;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;

@Component
public class JwtUtil {
    // 有效期
    private static final long JWT_EXPIRE = 30*60*1000L;  //半小时, 单位为毫秒
    // 令牌秘钥
    private static final String JWT_KEY = "123456";

    // Object data 可放入User对象,给User中的信息加密后成为token
    public  String createToken(Object data){
        // 当前时间
        long currentTime = System.currentTimeMillis();
        // token过期时间
        long expTime = currentTime+JWT_EXPIRE;
        // 构建jwt
        JwtBuilder builder = Jwts.builder()
                .setId(UUID.randomUUID()+"")
                .setSubject(JSON.toJSONString(data))    // User对象序列化
                .setIssuer("system")
                .setIssuedAt(new Date(currentTime))
                .signWith(SignatureAlgorithm.HS256, encodeSecret(JWT_KEY))  // 加密
                .setExpiration(new Date(expTime));
        return builder.compact();
    }

    // 加密算法
    private SecretKey encodeSecret(String key){
        byte[] encode = Base64.getEncoder().encode(key.getBytes());
        SecretKeySpec aes = new SecretKeySpec(encode, 0, encode.length, "AES");
        return  aes;
    }

    // token 解密
    public Claims parseToken(String token){
        Claims body = Jwts.parser()
                .setSigningKey(encodeSecret(JWT_KEY))
                .parseClaimsJws(token)
                .getBody();
        return body;
    }

    // token 解密,并返回一个对象,可是User对象
    public <T> T parseToken(String token,Class<T> clazz){
        Claims body = Jwts.parser()
                .setSigningKey(encodeSecret(JWT_KEY))
                .parseClaimsJws(token)
                .getBody();
        return JSON.parseObject(body.getSubject(),clazz);
    }

}

定义Jwt拦截器

XAdminApplication同级目录下新建文件夹interceptor,再新建java文件JwtValidateInterceptor
SpringBoot + Vue前后端分离项目实战 || 六:Jwt加密整合配置,spring boot,vue.js,后端

文件中写入以下代码,注释已给出

package com.ums.interceptor;

import com.alibaba.fastjson2.JSON;
import com.ums.common.utils.JwtUtil;
import com.ums.common.vo.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

// HandlerInterceptor继承该接口,然后重写方法
@Component
@Slf4j
public class JwtValidateInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtUtil jwtUtil;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // X-Token 是前端定义的token标头,与前端保持一致
        String token = request.getHeader("X-Token");

        log.debug(request.getRequestURI() +"需要验证:"+ token);     // 后台日志记录
        if (token != null){
            try {
                jwtUtil.parseToken(token);

                // 不要写System.out.println(); 此为垃圾代码
                // 加上注解@Slf4j , 用log.debug()来打印
                log.debug(request.getRequestURI() +"验证通过:");
                return true;
            }catch (Exception e) {
                e.printStackTrace();
            }

        }
        log.debug(request.getRequestURI() +"验证失败,禁止访问");    // 后台日志记录
        
        // 创建一个返回对象,当token错误后反馈给前端
        Result<Object> fail = Result.fail(20003, "token无效,请重新登录");

        // 验证不成功,给前端返回数据
        response.setContentType("application/json;charset=utf-8");  // 定义返回数据格式
        response.getWriter().write(JSON.toJSONString(fail));    // 将对象序列化后以json格式反馈至前端
        return false;   // 拦截当前用户的操作
    }
}

注册Jwt拦截器,配置需要验证token的URL

config目录下新建java文件MyInterceptorConfig
SpringBoot + Vue前后端分离项目实战 || 六:Jwt加密整合配置,spring boot,vue.js,后端
写入以下代码

package com.ums.config;

import com.ums.interceptor.JwtValidateInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MyInterceptorConfig implements WebMvcConfigurer {

    @Autowired
    private JwtValidateInterceptor iwtValidateInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        InterceptorRegistration registration = registry.addInterceptor(iwtValidateInterceptor);
        registration.addPathPatterns("/**")     // 拦截所有URL请求
                .excludePathPatterns(       // 开放下述URL请求
                        "/user/login",
                        "/user/info",
                        "/user/logout"
                );
    }
}

自此,Jwt就算配置完毕
总共新建下述三个文件
SpringBoot + Vue前后端分离项目实战 || 六:Jwt加密整合配置,spring boot,vue.js,后端

测试Jwt

新建一个测试类JwtUtilsTest
SpringBoot + Vue前后端分离项目实战 || 六:Jwt加密整合配置,spring boot,vue.js,后端

@Autowired
private JwtUtil jwtUtil;

@Test
public void testCreateJwt(){
    User user = new User();
    user.setUsername("anthony");
    user.setPhone("14766665555");
    String token = jwtUtil.createToken(user);
    System.out.println(token);
}

运行testCreateJwt(),系统会打印出一个加密后的字符串,此串会作为token使用。
SpringBoot + Vue前后端分离项目实战 || 六:Jwt加密整合配置,spring boot,vue.js,后端

将这个字符串复制

新建一个解密的测试方法testParseJwt(),下述代码中复制你自己的token

 @Test
 public void testParseJwt(){
     String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIwNmRlOGJmOS1kYmM1LTQzNjUtYWRmYi0yYzBjMmVmM2FkOGYiLCJzdWIiOiJ7XCJwaG9uZVwiOlwiMTQ3NjY2NjU1NTVcIixcInVzZXJuYW1lXCI6XCJhbnRob255XCJ9IiwiaXNzIjoic3lzdGVtIiwiaWF0IjoxNjkwMjQ4MjY1LCJleHAiOjE2OTAyNTAwNjV9.iskJNmm6b6rDFs1oxsinrCdFmul0dd9-4_zswD6eGV0";
     Claims claims = jwtUtil.parseToken(token);
     System.out.println(claims);
 }

运行后可得到加密的信息
SpringBoot + Vue前后端分离项目实战 || 六:Jwt加密整合配置,spring boot,vue.js,后端

因为我们是将一个对象整体进行加密,所以希望在解密的时候还原为一个对象

此时代码可这样写

 @Test
 public void testParseJw2t(){
     String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIwNmRlOGJmOS1kYmM1LTQzNjUtYWRmYi0yYzBjMmVmM2FkOGYiLCJzdWIiOiJ7XCJwaG9uZVwiOlwiMTQ3NjY2NjU1NTVcIixcInVzZXJuYW1lXCI6XCJhbnRob255XCJ9IiwiaXNzIjoic3lzdGVtIiwiaWF0IjoxNjkwMjQ4MjY1LCJleHAiOjE2OTAyNTAwNjV9.iskJNmm6b6rDFs1oxsinrCdFmul0dd9-4_zswD6eGV0";
     User user = jwtUtil.parseToken(token,User.class);
     System.out.println(user);
 }

运行后得到一个对象
SpringBoot + Vue前后端分离项目实战 || 六:Jwt加密整合配置,spring boot,vue.js,后端

修改登录等逻辑

现在有了Jwt签名验证机制,可将之前的UUID + redis登录逻辑进行修改

打开UserServiceImpl文件
SpringBoot + Vue前后端分离项目实战 || 六:Jwt加密整合配置,spring boot,vue.js,后端

将之前写的login(User user)getUserInfo(String token)logout(String token)这三段函数全部重写
SpringBoot + Vue前后端分离项目实战 || 六:Jwt加密整合配置,spring boot,vue.js,后端

  1. login(User user)
     @Autowired
     private JwtUtil jwtUtil;
     
     @Override
     public Map<String, Object> login(User user) {
         // 根据用户名查询
         LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
         wrapper.eq(User::getUsername, user.getUsername());
         User loginUser = this.baseMapper.selectOne(wrapper);
    
         // 结果不为空,并且密码与数据库解密后的密码匹配,生成token,将用户信息存入redis
         if (loginUser != null &&
                 passwordEncoder.matches(user.getPassword(), loginUser.getPassword())    // 匹配加密密码
         ) {
             
             loginUser.setPassword(null);    // 设置密码为空,密码没必要放入
    
             // 创建jwt
             String token = jwtUtil.createToken(loginUser);
    
             // 返回数据
             Map<String, Object> data = new HashMap<>();
             data.put("token",token);
             return data;
         }
    
         // 结果不为空,生成token,前后端分离,前端无法使用session,可以使用token
         return null;
     }
    
  2. getUserInfo(String token)
    @Override
    public Map<String, Object> getUserInfo(String token) {
        // 之前已将对象进行序列化处理存入redis,现在从redis中取出需要反序列化处理
        // Object obj = redisTemplate.opsForValue().get(token);    // 此对象是map类型,稍后需要序列化为Json字符串
        // User loginUser = JSON.parseObject(JSON.toJSONString(obj), User.class);
    
    
        User loginUser = null;
    
        try {
            // 解析Token
            loginUser = jwtUtil.parseToken(token, User.class);
        }catch (Exception e) {
            e.printStackTrace();
        }
    
        if (loginUser != null) {
            Map<String,Object> data = new HashMap<>();
            data.put("name",loginUser.getUsername());
            data.put("avatar",loginUser.getAvatar());
    
            // 先在xml里写SQL语句 id=getRoleNameByUserId,然后去UserMapper里实现接口
            List<String> roleList = this.baseMapper.getRoleNameByUserId(loginUser.getId());
            data.put("roles",roleList);
            return data;
        }
        return null;
    }
    
  3. logout(String token) , 注释以前的代码,可啥也不用写!
    @Override
    public void logout(String token) {
        // redisTemplate.delete(token);    // 从redis中删除token
    }
    

自此完毕!文章来源地址https://www.toymoban.com/news/detail-616016.html

到了这里,关于SpringBoot + Vue前后端分离项目实战 || 六:Jwt加密整合配置的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • SpringBoot + Vue前后端分离项目实战 || 四:用户管理功能实现

    SpringBoot + Vue前后端分离项目实战 || 四:用户管理功能实现

    系列文章: SpringBoot + Vue前后端分离项目实战 || 一:Vue前端设计 SpringBoot + Vue前后端分离项目实战 || 二:Spring Boot后端与数据库连接 SpringBoot + Vue前后端分离项目实战 || 三:Spring Boot后端与Vue前端连接 SpringBoot + Vue前后端分离项目实战 || 四:用户管理功能实现 SpringBoot + Vue前后

    2024年02月11日
    浏览(13)
  • 【SpringBoot+Vue】全网最简单但实用的前后端分离项目实战笔记 - 项目概述

    【SpringBoot+Vue】全网最简单但实用的前后端分离项目实战笔记 - 项目概述

    配套视频地址:https://www.bilibili.com/video/BV1dG4y1T7yp/ 如果您需要原版笔记,请up喝口水,可以上我的淘宝小店 青菜开发资料 购买,或点击下方链接直接购买: 源码+PDF版本笔记 源码+原始MD版本笔记 感谢支持! 通过学习本项目,深刻理解前后端分离的思想,具备独立搭建前后端

    2024年02月12日
    浏览(12)
  • 【SpringBoot+Vue】全网最简单但实用的前后端分离项目实战笔记 - 后端

    【SpringBoot+Vue】全网最简单但实用的前后端分离项目实战笔记 - 后端

    配套视频地址:https://www.bilibili.com/video/BV1dG4y1T7yp/ 如果您需要原版笔记,请up喝口水,可以上我的淘宝小店 青菜开发资料 购买,或点击下方链接直接购买: 源码+PDF版本笔记 源码+原始MD版本笔记 感谢支持! 创建springboot项目:2.7.8 pom依赖 yml 测试 编写代码生成器 启动类加注

    2024年02月04日
    浏览(6)
  • 【SpringBoot+Vue】全网最简单但实用的前后端分离项目实战笔记 - 前端

    【SpringBoot+Vue】全网最简单但实用的前后端分离项目实战笔记 - 前端

    配套视频地址:https://www.bilibili.com/video/BV1dG4y1T7yp/ 如果您需要原版笔记,请up喝口水,可以上我的淘宝小店 青菜开发资料 购买,或点击下方链接直接购买: 源码+PDF版本笔记 源码+原始MD版本笔记 感谢支持! 官网:https://nodejs.org 注意,node可以比我稍低,但不要更高 https://p

    2024年01月17日
    浏览(16)
  • SpringBoot + Vue前后端分离项目实战 || 三:Spring Boot后端与Vue前端连接

    SpringBoot + Vue前后端分离项目实战 || 三:Spring Boot后端与Vue前端连接

    系列文章: SpringBoot + Vue前后端分离项目实战 || 一:Vue前端设计 SpringBoot + Vue前后端分离项目实战 || 二:Spring Boot后端与数据库连接 SpringBoot + Vue前后端分离项目实战 || 三:Spring Boot后端与Vue前端连接 SpringBoot + Vue前后端分离项目实战 || 四:用户管理功能实现 SpringBoot + Vue前后

    2024年02月12日
    浏览(14)
  • 【SpringBoot+Vue】全网最简单但实用的前后端分离项目实战笔记 - 数据库设计

    配套视频地址:https://www.bilibili.com/video/BV1dG4y1T7yp/ 如果您需要原版笔记,请up喝口水,可以上我的淘宝小店 青菜开发资料 购买,或点击下方链接直接购买: 源码+PDF版本笔记 源码+原始MD版本笔记 感谢支持!

    2024年02月16日
    浏览(6)
  • 【Docker】docker部署springboot+vue+mysql+nginx前后端分离项目【部署实战篇】

    【Docker】docker部署springboot+vue+mysql+nginx前后端分离项目【部署实战篇】

    安装docker: https://blog.csdn.net/qq_39900031/article/details/121666892 springboot-vue前后端分离项目:https://gitee.com/ma-haojie/springboot-vue-demo.git https://jackwei.blog.csdn.net/article/details/110227719 或者 --restart=always 参数能够使我们 在重启docker时,自动启动相关容器 。 Docker容器的重启策略如下: no,默认

    2024年02月13日
    浏览(9)
  • 【项目实战】手把手教你搭建前后端分离项目 SpringBoot + Vue + Element UI + Mysql

    【项目实战】手把手教你搭建前后端分离项目 SpringBoot + Vue + Element UI + Mysql

    👉 博主介绍 : 博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家,WEB架构师,阿里云专家博主,华为云云享专家,51CTO TOP红人 Java知识图谱点击链接: 体系化学习Java(Java面试专题) 💕💕 感兴趣的同学可以收藏关注下 , 不然下次找不到哟

    2024年02月16日
    浏览(11)
  • SpringBoot + Vue前后端分离项目实战 || 二:Spring Boot后端与数据库连接

    SpringBoot + Vue前后端分离项目实战 || 二:Spring Boot后端与数据库连接

    系列文章: SpringBoot + Vue前后端分离项目实战 || 一:Vue前端设计 SpringBoot + Vue前后端分离项目实战 || 二:Spring Boot后端与数据库连接 SpringBoot + Vue前后端分离项目实战 || 三:Spring Boot后端与Vue前端连接 SpringBoot + Vue前后端分离项目实战 || 四:用户管理功能实现 SpringBoot + Vue前后

    2024年02月11日
    浏览(19)
  • SpringBoot&Vue&EmementUI前后端分离整合、统一封装axios、跨域配置

    SpringBoot&Vue&EmementUI前后端分离整合、统一封装axios、跨域配置

    🧑‍💻作者名称:DaenCode 🎤作者简介:CSDN实力新星,后端开发两年经验,曾担任甲方技术代表,业余独自创办智源恩创网络科技工作室。会点点Java相关技术栈、帆软报表、低代码平台快速开发。技术尚浅,闭关学习中······ 😎人生感悟:尝尽人生百味,方知世间冷暖。

    2024年02月09日
    浏览(16)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包