SpringBoot集成JWT快速入门Demo

news2024/11/16 11:51:37

目录

1. 概述

2. JWT的请求流程

3. Session认证与JWT认证的区别 

4 JWT优缺点

4.1 优点

4.2 缺点

5. 快速入门

5.1 创建工程

5.2 导入依赖

5.3 添加配置文件

5.4 添加Swagger2配置类

5.5 添加JWT工具类

5.6 添加entity、service、controller类

5.7 添加拦截器类

5.8 添加拦截器配置文件

5.9 创建启动类

5.10 测试

5.10.1 通过swaggler测试  

5.10.2 通过Postman测试

6. Demo下载地址


1. 概述

        近年来,随着前后端分离、微服务等架构的兴起,传统的cookie+session身份验证模式已经逐渐被基于Token的身份验证模式取代。

备注:将token或者一个唯一标识UUID=UUID.randomUUID().toString()存进Cookie中(别存在Http的header中了),设置路径为整个项目根路径/*; 往往以这个唯一标识为key,用户信息为value缓存在服务器中,实现单点登录

        JWT (Json web token)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519)。它定义了一种紧凑的,自包含的方式,用于通信双方之间以JSON对象的形式安全传递信息。JWT使用HMAC算法或者是RSA的公私秘钥的数字签名技术,所以这些信息是可被验证和信任的。

        JWT官网: https://jwt.io/

        JWT(Java版)的github地址: https://github.com/jwtk/jjwt

        在使用 JWT 前,需要先了解它的组成结构。它是由以下三段信息构成的:

  • Header 头部(包含签名和/或加密算法的类型)

  • Payload 载荷 (存放有效信息)

  • Signature 签名/签证

        将这三段信息文本用‘.’连接一起就构成完整的JWT字符串(比如:xxxxx.yyyyy.zzzzz),也是就我们需要的Token。

2. JWT的请求流程

        JWT的请求流程也特别简单,首先使用账号登录获取Token,然后后面的各种请求,都带上这个Token即可。具体流程如下:

  1. 客户端发起登录请求,传入账号密码;

  2. 服务端使用私钥创建一个Token;

  3. 服务器返回Token给客户端;

  4. 客户端向服务端发送请求,在请求头添加中该Token;

  5. 服务器验证该Token;

  6. 返回结果。

3. Session认证与JWT认证的区别 

        基于session和基于jwt的方式的主要区别就是用户的状态保存的位置。

        session是保存在服务端的,下一次再取从session当中取数据。

        jwt认证:用户输入用户名与密码,校验(从数据库当中查看有没有对应的数据),如果有对应的数据,会把用户取出来,把取出的用户数据,转成JWT,以token令牌的形式传给前端,前端拿到数据之后,会给存储到cookie,以后面每一次请求都要携带token,服务器就会获取token之后,再进行jw解析,读取用户数据,如果没有数据,就代表没有登录,而jwt是保存在客户端的。

4 JWT优缺点

4.1 优点

  •  jwt基于json,非常方便解析
  • 可以在令牌中自定义丰富的内容,易扩展
  • 通过非对称加密算法及数字签名技术,JWT防止篡改,安全性高
  • 资源服务使用JWT可不依赖认证服务即可完成授权

4.2 缺点

  • JWT令牌较长,占存储空间比较大

5. 快速入门

5.1 创建工程

         

        设置Maven

        设置自动导入包 Auto Import

        设置启动注解 Annotation Processors

5.2 导入依赖

<!--引入springboot依赖-->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.4.RELEASE</version>
</parent>

<dependencies>
    <!--引入spring-boot启动器依赖, 添加启动器后web工程常用的依赖会自动帮你引入-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--test-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <!--lombok-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <!--Swagger2-->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>2.7.0</version>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>2.7.0</version>
    </dependency>
    <!-- jwt -->
    <dependency>
        <groupId>com.auth0</groupId>
        <artifactId>java-jwt</artifactId>
        <version>3.4.0</version>
    </dependency>
</dependencies>

<!--打包-->
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

5.3 添加配置文件

        resources\application.yml 当中 添加配置信息

server:
  port: 8081

5.4 添加Swagger2配置类

package com.miaxis.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.miaxis"))// 指定扫描包下面的注解
                .paths(PathSelectors.any())
                .build();
    }
    // 创建api的基本信息
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("集成Swagger2构建RESTful APIs")
                .description("集成Swagger2构建RESTful APIs")
                .termsOfServiceUrl("https://www.miaxis.com")
                .contact("Mickey")
                .version("1.0.0")
                .build();
    }
}

5.5 添加JWT工具类

package com.miaxis.util;

import com.miaxis.user.entity.User;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.apache.logging.log4j.util.Strings;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * <p> @Title TokenUtil
 * <p> @Description Token 工具类
 */
public class TokenUtil {

    public static final String JWT_SECRET_KEY = "testjwt";

    /**
     * 创建Token
     *
     * @param user 用户实体
     * @return Token
     */
    public static String createToken(User user) {

        // 登录成功后生成JWT
        // JWT的header部分,该map可以是空的,因为有默认值{"alg":HS256,"typ":"JWT"}
        Map<String, Object> map = new HashMap<>();

        // 30分钟过期时间
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.MINUTE,30);

        return JWT.create()
                // 添加头部
                .withHeader(map)
                // 添加payload
                .withClaim("userId",user.getId())
                .withClaim("username",user.getUsername())
                .withClaim("email",user.getEmail())
                // 设置过期时间
                .withExpiresAt(instance.getTime())
                // 设置签名 密钥
                .sign(Algorithm.HMAC256(JWT_SECRET_KEY));
    }

    /**
     * 检查Token是否有效
     *
     * @param token Token
     * @return 是否有效
     */
    public static boolean isValid(String token) {
        if (Strings.isNotBlank(token)) {
            try {
                //创建验证对象,这里使用的加密算法和密钥必须与生成TOKEN时的相同否则无法验证
                JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(JWT_SECRET_KEY)).build();
                //验证JWT
                DecodedJWT decodedJwt = jwtVerifier.verify(token);
                return new Date().before(decodedJwt.getExpiresAt());
            } catch (Exception e) {
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * 检查Token所有Claims
     *
     * @param token Token
     * @return Claims
     */
    public static Map<String, Object> getClaims(String token) {

        if (isValid(token))  {
            //创建验证对象,这里使用的加密算法和密钥必须与生成TOKEN时的相同否则无法验证
            JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(JWT_SECRET_KEY)).build();
            //验证JWT
            DecodedJWT decodedJwt = jwtVerifier.verify(token);

            //获取JWT中的数据,注意数据类型一定要与添加进去的数据类型一致,否则取不到数据
            Map<String, Object> map = new HashMap<>();
            map.put("userId", decodedJwt.getClaim("userId").asInt());
            map.put("username", decodedJwt.getClaim("username").asString());
            map.put("email", decodedJwt.getClaim("email").asString());
            map.put("expire", decodedJwt.getExpiresAt());
            return map;
        } else {
            throw new RuntimeException("Token验证失败,请重新登录");
        }
    }
}

5.6 添加entity、service、controller类

  • entity\User
package com.miaxis.user.entity;

import lombok.AllArgsConstructor;
import lombok.Data;

/**
 * <p> @Title User
 * <p> @Description 用户实体
 */
@Data
@AllArgsConstructor
public class User {
    /**
     * 主键
     */
    public Integer id;

    /**
     * 用户名
     */
    public String username;

    /**
     * 密码
     */
    public String password;

    /**
     * 邮箱
     */
    public String email;
}
  • service\UserService
package com.miaxis.user.service;

import com.miaxis.user.entity.User;
import org.springframework.stereotype.Service;

/**
 * <p> @Title UserService
 * <p> @Description 用户 业务层
 */
@Service
public class UserService {

    public User findUser() {
        return new User(1, "ACGkaka", "123456", "123@123.com");
    }
}
  • controller\UserController

   controller带token的接口配置Swagger带token

package com.miaxis.user.controller;

import com.miaxis.user.entity.User;
import com.miaxis.user.service.UserService;
import com.miaxis.util.TokenUtil;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * <p> @Title DemoController
 * <p> @Description 登录页面
 */
@RestController
@RequestMapping("index")
public class UserController {
    @Resource
    private UserService userService;

    /**
     * 登录
     *
     * @return Token
     */
    @ResponseBody
    @PostMapping("/login")
    public Map<String, Object> login() {
        System.out.println("============login");
        User user = userService.findUser();
        String token = TokenUtil.createToken(user);
        Map<String, Object> result = new HashMap<>();
        result.put("code", 200);
        result.put("message", "登录成功");
        result.put("data", token);
        return result;
    }

    /**
     * 获取Token信息
     *
     * @return 验证结果
     */
    @ResponseBody
    @GetMapping("/getInfo")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", name = "accessToken", required = true),
    })
    public Map<String, Object> getInfo(HttpServletRequest request) {
        Map<String, Object> result = new HashMap<>();
        String token = request.getHeader("accessToken");
        Map<String, Object> data = TokenUtil.getClaims(token);
        result.put("code", 200);
        result.put("message", "验证成功");
        result.put("data", data);
        return result;
    }
}

5.7 添加拦截器类

package com.miaxis.interceptor;

import com.miaxis.user.service.UserService;
import com.miaxis.util.TokenUtil;
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;


/**
 * <p> @Title TokenInterceptor
 * <p> @Description Token 验证拦截器
 */
public class TokenInterceptor implements HandlerInterceptor {

    @Autowired
    UserService userService;

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) {
        // 从 http 请求头中取出 token
        String token = httpServletRequest.getHeader("accessToken");
        // 如果不是映射到方法直接通过
        if(!(object instanceof HandlerMethod)){
            return true;
        }
        // 执行认证
        if (token == null) {
            throw new RuntimeException("accessToken不存在,请重新登录");
        }
        // 验证 token
        if (TokenUtil.isValid(token)) {
            return true;
        } else {
            throw new RuntimeException("Token验证失败,请重新登录");
        }
    }

    @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 {

    }
}

5.8 添加拦截器配置文件

  • 拦截器配置排除拦截Swagger

package com.miaxis.config;

import com.miaxis.interceptor.TokenInterceptor;
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;

/**
 * <p> @Title InterceptorConfig
 * <p> @Description 拦截器配置
 */
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //定义排除swagger访问的路径配置
        String[] swaggerExcludes=new String[]{"/swagger-ui.html","/swagger-resources/**","/webjars/**"};

        // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录
        registry.addInterceptor(authenticationInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/index/login")
                .excludePathPatterns(swaggerExcludes);
        WebMvcConfigurer.super.addInterceptors(registry);
    }

    @Bean
    public TokenInterceptor authenticationInterceptor() {
        return new TokenInterceptor();
    }
}

5.9 创建启动类

package com.miaxis;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

5.10 测试

5.10.1 通过swaggler测试  

        http://localhost:8081/swagger-ui.html

5.10.2 通过Postman测试

        http://localhost:8081/index/login

        http://localhost:8081/index/getInfo

        accessToken

        eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MDcwMzc3NDUsInVzZXJJZCI6MSwiZW1haWwiOiIxMjNAMTIzLmNvbSIsInVzZXJuYW1lIjoiQUNHa2FrYSJ9.TT4CZgUfmWCNhbQa6UTWhSl3Tcf48uAVsAyqNQoR6KI

6. Demo下载地址

编译器版本:IntelliJ IDEA 2020.3.2 x64

JDK版本:java 1.8.0_111

下载地址:https://download.csdn.net/download/mickey2007/89110981

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

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

相关文章

【Linux】CentOS 7安装后没有图形界面

专栏文章索引&#xff1a;Linux 有问题可私聊&#xff1a;QQ&#xff1a;3375119339 目录 一、项目场景 二、问题描述 三、原因分析 四、解决方案 1.当前处于命令行界面&#xff0c;可以切换为图形界面 2.安装时没有安装图形界面&#xff0c;选择了Minimal Install 3.下…

【Linux】磁盘分区扩容到原有目录(LVM)

一、LVM基本组成 LVM(Logical Volume Manager&#xff0c;逻辑卷管理)逻辑卷管理器是负责管理物理卷、卷组和逻辑卷的软件层。它提供了创建、调整和管理这些组件的命令和工具&#xff0c;使得用户能够灵活地调整和管理磁盘空间。 1.物理卷&#xff08;PV&#xff0c;Physical…

基于Springcloud可视化项目:智慧工地可视化大数据云平台源码

目录 技术架构 智慧工地系统在实际推行过程中遇到的问题 智慧工地接纳程度较低 基础设施条件有待完善 智慧工地整体生态尚未完善 智慧工地平台各功能模块 施工过程工信程息信管息理管模理块 人员管理模块 生产管理模块 技术管理模块 质量管理模块 安全管理模块 绿…

免费的 ChatGPT 网站(六个)

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《C》 《Linux》 《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 文章目录 一、insCode二、讯飞星火三、豆包四、文心一言五、通义千问六、360智脑 现在智能…

关于GDAL计算图像坐标的几个问题

关于GDAL计算图像坐标的几个问题_gdal读取菱形四角点坐标-CSDN博客 这篇文章写的很好&#xff0c;讲清楚了图像行列号与图像点坐标&#xff08;x,y&#xff09;对应关系&#xff0c;以及图像行列号如何转为地理坐标的&#xff0c;转载一下做个备份。 1.关于GDAL计算图像坐标的…

【Python】使用OPC UA创建数据服务器

目录 准备工作服务器设置创建或获取节点设置节点值启动服务器查看服务器客户端总结 在工业自动化和物联网&#xff08;IoT&#xff09;领域&#xff0c;OPC UA&#xff08;开放平台通信统一架构&#xff09;已经成为一种广泛采用的数据交换标准。它提供了一种安全、可靠且独立于…

51单片机-独立按键模块

1. 独立按键控制LED状态 轻触按键实现原理&#xff1a;按下时&#xff0c;接通&#xff0c;通过金属弹片受力弹动来实现接通和断开。 松开按键 按下之后&#xff1a;就会被连接 同时按下K1和K2时&#xff0c;P2_0,接口所连LED灯才亮。 #include <REGX52.H> void ma…

【opencv】示例-travelsalesman.cpp 使用模拟退火算法求解旅行商问题

// 载入 OpenCV 的核心头文件 #include <opencv2/core.hpp> // 载入 OpenCV 的图像处理头文件 #include <opencv2/imgproc.hpp> // 载入 OpenCV 的高层GUI(图形用户界面)头文件 #include <opencv2/highgui.hpp> // 载入 OpenCV 的机器学习模块头文件 #includ…

Devin AI: The World’s First AI Software Engineer

Devin AI是Cognition AI团队推出的一款名为Devin的人工智能软件工程师&#xff0c;它被誉为世界上第一个完全自主的AI软件工程师。Devin AI在2024年3月12日发布&#xff0c;并在SWE-bench编码基准测试中设立了新的技术标杆。 Devin AI具备多项强大的能力&#xff0c;包括学习如…

简述OSI七层模型及每层的功能任务和协议

文章目录 一、OSI七层模型的功能和任务1.物理层2.数据链路层3.网络层4.传输层5.会话层6.表示层7. 应用层 二、OSI七层模型每层的协议 开放系统互连参考模型&#xff08;Open System Interconnect&#xff0c;简称OSI&#xff09;是国际标准化组织(ISO)和国际电报电话咨询委员会…

openstack安装dashboard后登录网页显示404错误

1. 2.进入该目录vim /etc/httpd/conf.d/openstack-dashboard.conf 增加这一行 WSGIApplicationGroup %{GLOBAL} 重启httpd后就可以访问了

SpringBoot+FreeMaker

目录 1.FreeMarker说明2.SpringBootFreeMarker快速搭建Pom文件application.properties文件Controller文件目录结构 3.FreeMarker数据类型3.1.布尔类型3.2.数值类型3.3.字符串类型3.4.日期类型3.5.空值类型3.6.sequence类型3.7.hash类型 4.FreeMarker指令assign自定义变量指令if…

[大模型]DeepSeek-7B-chat FastApi 部署调用

DeepSeek-7B-chat FastApi 部署调用 DeepSpeek 介绍 由70亿个参数组成的高级语言模型 DeepSeek LLM。它是在一个包含2万亿个英文和中文代币的庞大数据集上从零开始训练的。为了促进研究&#xff0c;DeepSeek 已经为研究社区开放了DeepSeek LLM 7B/67B Base 和 DeepSeek LLM 7…

软考129-上午题-【软件工程】-McCabe度量法+白盒测试真题

一、真题 真题1&#xff1a; 简单路径&#xff1a; 简单路径是指在一个图中&#xff0c;从一个顶点出发&#xff0c;经过一系列不同的顶点&#xff0c;最终到达另一个顶点&#xff0c;且在整个过程中&#xff0c;除了起点和终点外&#xff0c;每个顶点只被访问一次的路径。在简…

Linux 目录结构与基础查看命令

介绍 目录结构如下 /bin&#xff1a;存放着用户最经常使用的二进制可执行命令&#xff0c;如cp、ls、cat等。这些命令是系统管理员和普通用户进行日常操作所必需的。 /boot&#xff1a;存放启动系统使用的一些核心文件&#xff0c;如引导加载器&#xff08;bootstrap loader…

商业银行业务与管理

商业银行业务与管理 资产负债表恒等式中国商业银行的资产负债表商业银行的业务种类银行运行管理的案例银行管理的基本准则流动性管理资产和负债管理资本充足管理 资产负债表恒等式 &#xff08;一般&#xff09;资产负债所有者权益 一个公司的资产是由负债和所有者权益所构成…

飞驰云联入选金融信创生态实验室「金融信创优秀解决方案」

近日&#xff0c;由中国人民银行领导、中国金融电子化集团有限公司牵头组建的金融信创生态实验室发布了第三期金融信创优秀解决方案&#xff0c;Ftrans飞驰云联“文件数据传输解决方案”成功入选&#xff01; 本次金融信创优秀解决方案遴选经方案征集、方案初审、专家评审等多环…

【MATLAB源码-第188期】基于matlab的64QAM系统相位偏移估计EOS算法仿真,对比补偿前后的星座图误码率。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 1. 引言 M-QAM调制技术的重要性 现代通信系统追求的是更高的数据传输速率和更有效的频谱利用率。M-QAM调制技术&#xff0c;作为一种高效的调制方案&#xff0c;能够通过在相同的带宽条件下传输更多的数据位来满足这一需求…

《自动机理论、语言和计算导论》阅读笔记:p172-p224

《自动机理论、语言和计算导论》学习第 8 天&#xff0c;p172-p224总结&#xff0c;总计 53 页。 一、技术总结 1.Context-Free Grammar(CFG) 2.parse tree (1)定义 p183&#xff0c;But perhaps more importantly, the tree, known as a “parse tree”, when used in a …

【Java】新手一步一步安装 Java 语言开发环境

文章目录 一、Windows 10 系统 安装 JDK8二、 Mac 系统 安装 JDK8三、IDEA安装 一、Windows 10 系统 安装 JDK8 &#xff08;1&#xff09;打开 JDK下载网站&#xff0c;根据系统配置选择版本&#xff0c;这里选择windows 64位的版本&#xff0c;点击下载&#xff08;这里需要…