当前位置: 首页 > news >正文

【JWT的使用】

文章目录

  • 前言
    • 1、用户登录
      • 1.1 JWT
      • ThreadLocal
    • 2.1 代码实现
      • 2.1.1 ThreadLocal工具类
      • 2.2.2 定义拦截器
      • 2.2.3 注册拦截器


前言

1、用户登录

1.1 JWT

JSON Web Token简称JWT,用于对应用程序上用户进行身份验证的标记。使用 JWTS 之后不需要保存用户的 cookie 或其他session数据,同时可保证应用程序的安全。

JWT是经过加密处理与校验处理的字符串,形式为:A.B.C

  1. –A由JWT头部信息header加密得到
  2. –B由JWT用到的身份验证信息JSON数据加密得到
  3. –C由A和B加密得到,是校验部分
  4. –官方测试网站: https://jwt.io/
    @Testpublic void testCreateToken() {//生成token//1、准备数据Map map = new HashMap();map.put("id",1);map.put("mobile","13800138000");//2、使用JWT工具类生成tokenlong now = System.currentTimeMillis();String token = Jwts.builder().signWith(SignatureAlgorithm.HS512, "itcast") //指定加密算法.setClaims(map)//指定写入的数据.setExpiration(new Date(now + 5000))  //设置失效时间.compact();System.out.println(token);}@Testpublic void testParseToken() {String token = "eyJhbGciOiJIUzUxMiJ9.e1yJtb2JpbGUiOiIxMzgwMDEzODAwMCIsImlkIjoxLCJleHAiOjE2MTgzOTA4NzB9.WhZfFSJNEZJGeZAHqMaVIslvzvkFzQ1FCLCULSaR-yZYprbzgmuxNaSr3oW__zRFkBCnNRGllzaKb0ZJujs1GA";//解析tokentry {Claims claims = Jwts.parser().setSigningKey("itcast").parseClaimsJws(token).getBody();Object id = claims.get("id");Object mobile = claims.get("mobile");System.out.println(id + "--" + mobile);}catch (ExpiredJwtException e) {System.out.println("token已过期");}catch (SignatureException e) {System.out.println("token不合法");}}

JWT工具类

public class JwtUtils {// TOKEN的有效期1小时(S)private static final int TOKEN_TIME_OUT = 3_600;// 加密KEYprivate static final String TOKEN_SECRET = "itcast";// 生成Tokenpublic static String getToken(Map params){long currentTime = System.currentTimeMillis();return Jwts.builder().signWith(SignatureAlgorithm.HS512, TOKEN_SECRET) //加密方式.setExpiration(new Date(currentTime + TOKEN_TIME_OUT * 1000)) //过期时间戳.addClaims(params).compact();}/*** 获取Token中的claims信息*/public static Claims getClaims(String token) {return Jwts.parser().setSigningKey(TOKEN_SECRET).parseClaimsJws(token).getBody();}/*** 是否有效 true-有效,false-失效*/public static boolean verifyToken(String token) {if(StringUtils.isEmpty(token)) {return false;}try {Claims claims = Jwts.parser().setSigningKey("itcast").parseClaimsJws(token).getBody();}catch (Exception e) {return false;}return true;}
}

ThreadLocal

  • 线程内部的存储类,赋予了线程存储数据的能力。

  • 线程内调用的方法都可以从ThreadLocal中获取同一个对象。

  • 多个线程中ThreadLocal数据相互隔离

2.1 代码实现

2.1.1 ThreadLocal工具类

定义ThreadLocal工具类,仅需要调用set方法即可将数据存入ThreadLocal中

package com.tanhua.server.interceptor;import com.tanhua.model.domain.User;/*** @author Administrator*/
public class UserHolder {private static ThreadLocal<User> tl = new ThreadLocal<User>();/*** 保存数据到线程*/public static void set(User user) {tl.set(user);}/*** 获取线程中的用户信息*/public static User get() {return tl.get();}/*** 从当前线程,获取用户对象的id*/public static Long getUserId() {if (tl.get() == null) {return null;}return tl.get().getId();}/*** 从当前线程,获取用户对象的手机号码*/public static String getMobile() {if (tl.get() == null) {return null;}return tl.get().getMobile();}/*** 移除线程中数据*/public static void remove() {tl.remove();}
}

2.2.2 定义拦截器

定义拦截器,在前置拦截方法preHandle中解析token并验证有效性,如果失效返回状态码401。如果有效,解析User对象,存入ThreadLocal中

package com.tanhua.server.interceptor;import com.tanhua.model.domain.User;
import com.tanhua.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwt;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** @author Administrator*/
public class TokenInterceptor extends HandlerInterceptorAdapter {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//1、获取请求头String token = request.getHeader("Authorization");//2、使用工具类,判断token是否有效boolean verifyToken = JwtUtils.verifyToken(token);//3、如果token失效,返回状态码401,拦截if(!verifyToken) {response.setStatus(401);return false;}//4、如果token正常可用,放行//解析token,获取id和手机号码,Claims claims = JwtUtils.getClaims(token);String mobile = (String) claims.get("mobile");Integer id = (Integer) claims.get("id");//构造User对象,存入ThreadlocalUser user = new User();user.setId(Long.valueOf(id));user.setMobile(mobile);UserHolder.set(user);return true;}//清空@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {UserHolder.remove();}
}

2.2.3 注册拦截器

拦截器需要注册到MVC容器中

/*** @author Administrator*/
@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new TokenInterceptor()).addPathPatterns("/**").excludePathPatterns("/user/login", "/user/loginVerification");}
}
package com.tanhua.server.controller;import com.tanhua.server.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.Map;@RestController
@RequestMapping("/user")
public class LoginController {@Autowiredprivate UserService userService;/*** 获取登录验证*  请求参数:phone(Map)*  响应:void*ResponseEntity* @return*/@PostMapping("/login")public ResponseEntity login(@RequestBody Map map){String phone = (String) map.get("phone");userService.sendMsg(phone);
//        return ResponseEntity.status(500).body("出错了");return ResponseEntity.ok(null);//正常返回状态码200}/***检验登录* /user/loginVerification* phone,verificationCode*/@PostMapping("/loginVerification")public ResponseEntity loginVerification(@RequestBody Map map){//1.调用map集合获取请求参数String phone = (String) map.get("phone");String code = (String) map.get("verificationCode");//2.调用userService完成用户登录Map retMap = userService.loginVerification(phone,code);//3.构造返回return ResponseEntity.ok(retMap);}
}
package com.tanhua.server.service;import com.tanhua.autoconfig.template.SmsTemplate;
import com.tanhua.commons.utils.JwtUtils;
import com.tanhua.dubbo.api.UserApi;
import com.tanhua.model.domain.User;
import com.tanhua.model.vo.ErrorResult;
import com.tanhua.server.exception.BusinessException;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;import java.time.Duration;
import java.util.HashMap;
import java.util.Map;@Service
public class UserService {@Autowiredprivate SmsTemplate smsTemplate;@Autowiredprivate RedisTemplate<String,String> redisTemplate;@DubboReferenceprivate UserApi userApi;/*** 发送短信验证码* @param phone*/public void sendMsg(String phone) {//1.随机生成6位数字
//        String code = RandomStringUtils.randomNumeric(6);String code = "123456";//2.调用templat对象,发送手机短信
//        smsTemplate.sendSms(phone,code);//3.将验证码存入到redisredisTemplate.opsForValue().set("CHECK_CODE" + phone,code, Duration.ofMinutes(5));}/*** 验证登录* @param phone* @param code* @return*/public Map loginVerification(String phone, String code) {//1.从redis中获取下发的验证码String redisCode = redisTemplate.opsForValue().get("CHECK_CODE" + phone);//2.对验证码进行校验(验证码是否存在,是否和输入的验证码是否一致)if (StringUtils.isEmpty(redisCode) || !redisCode.equals(code)){//验证码无效throw new BusinessException(ErrorResult.loginError());}//3.删除redis中的验证码redisTemplate.delete("CHECK_CODE"+phone);//4.通过手机号码查询用户User user = userApi.findByMobile(phone);boolean isNew = false;//5.如果用户不存在,创建用户保存到数据库中if (user == null){user = new User();user.setMobile(phone);user.setPassword(DigestUtils.md5Hex("123456"));Long userId = userApi.save(user);user.setId(userId);isNew = true;}//6.通过JWT生成token(存入id和手机号码)Map tokenMap = new HashMap();tokenMap.put("id",user.getId());tokenMap.put("mobile",phone);String token = JwtUtils.getToken(tokenMap);//7.构造返回值Map retMap = new HashMap();retMap.put("token",token);retMap.put("isNew",isNew);return retMap;}
}

相关文章:

【JWT的使用】

文章目录 前言1、用户登录1.1 JWTThreadLocal 2.1 代码实现2.1.1 ThreadLocal工具类2.2.2 定义拦截器2.2.3 注册拦截器 前言 1、用户登录 1.1 JWT JSON Web Token简称JWT&#xff0c;用于对应用程序上用户进行身份验证的标记。使用 JWTS 之后不需要保存用户的 cookie 或其他…...

Python获取音视频时长

Python获取音视频时长 Python获取音视频时长1、安装插件2、获取音视频时长.py3、打包exe4、下载地址 Python获取音视频时长 1、安装插件 pip install moviepy -i https://pypi.tuna.tsinghua.edu.cn/simple2、获取音视频时长.py 上代码&#xff1a;获取音视频时长.py # -*-…...

TCP四次握手为什么客户端等待的时间是2MSL

目录 什么是MSL从第三次握手开始分析总结 什么是MSL MSL是Maximum Segment Lifetime英文的缩写&#xff0c;中文可以译为“报文最大生存时间”&#xff0c;他是任何报文在网络上存在的最长时间&#xff0c;超过这个时间报文将被丢弃。 从第三次握手开始分析 第三次握手服务端…...

Android Studio 启用设备远程调试配置完整步聚

启用手机设置->开发者选项-无线调试,然后选择允许 已启用后无线调试变成绿色 ,点击无线调试进入详情页面 点击Android Studio的Device Manager 下的WIFI图标 会弹出下图窗口 打开手机的开发者选项中的WIFI调试(无线调试)下的使用二维码配对设备进行扫描. 设备配对成功后手机…...

玩转LaTeX(三)【数学公式(基础)、​矩阵、多行公式】

数学公式基础 导言区&#xff08;引包&#xff09; \usepackage{amsmath} %带星号的eqution 正文区 \begin{document}%数学公式初步 \section{简介} \LaTeX{}将排版内容分为文本模式和数学模式。文本模式用于普通文本排版&#xff0c;数学模式用于数学公式排版。 …...

jenkins 配置git

在linux 中输入 保证git 安装成功 git --version使用查看git 安装目录&#xff08;非源码安装直接用yum 安装的&#xff09; which gitjenkins 中到 系统管理–>全局工具配置–> Git installations 新建一个项目 选择自由风格 源码管理选择 git 如果使用的是码云&a…...

单机部署MinIo并设置开机自启

MinIO 是高性能的对象存储&#xff0c;是为海量数据存储、人工智能、大数据分析而设计的&#xff0c;它完全兼容Amazon S3接口&#xff0c;单个对象最大可达5TB&#xff0c;适合存储海量图片、视频、日志文件、备份数据和容器/虚拟机镜像等。MinIO主要采用Golang语言实现&#…...

Latex | 使用MATLAB生成.eps矢量图并导入Latex中的方法

一、问题描述 用Latex时写paper时&#xff0c;要导入MATLAB生成的图进去 二、解决思路 &#xff08;1&#xff09;在MATLAB生成图片的窗口中&#xff0c;导出.eps矢量图 &#xff08;2&#xff09;把图上传到overleaf的目录 &#xff08;3&#xff09;在文中添加相应代码 三…...

宝塔面板定时任务重启各种服务

一个php项目&#xff0c;laravel框架&#xff0c;使用了nginx php redis mysql 还有进程守护supervisor&#xff0c;用于laravel的异步队列进程queue&#xff0c;当服务器重启后有可能部分服务没有成功启动这个时候可以用定时任务去检查服务状态&#xff0c;然后对不正常的自动…...

Ansible playbook编写

目录 palybooks 组成示例&#xff1a;运行palybook定义&#xff0c;引用变量when 条件判断循环Templates模块tags 模块 palybooks 组成 Tasks&#xff1a;任务&#xff0c;即通过 task 调用 ansible 的模板将多个操作组织在一个 playbook 中运行Variables&#xff1a;变量Temp…...

个人博客系统 -- 登录页面添加图片验证码

目录 1. 功能展示 2. 前段代码 3. 后端代码 1. 功能展示 在登录页面添加验证码登录 1. 检测到没有输入验证码或者输入的验证码错误时,进行弹窗提示.并且刷新当前验证码图片 2. 点击验证码进行刷新 2. 前段代码 1. 添加验证码标签,在密码的下面,在login.html进行修改 主要…...

剑指offer10-I.斐波那契数列

学计算机的对这道题肯定不陌生&#xff0c;我记得是学C语言的时候学递归的时候有这道题&#xff0c;于是我就世界用递归写了如下代码&#xff1a; class Solution {public int fib(int n) {if(n1) return 1;if(n0) return 0;return (fib(n-1) fib(n-2)) % 1000000007;} } 到…...

13年测试经验,性能测试-压力测试指标分析总结,看这篇就够了...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 一般推荐&#xf…...

大数据课程D3——hadoop的Source

文章作者邮箱:yugongshiye@sina.cn 地址:广东惠州 ▲ 本章节目的 ⚪ 掌握Source的AVRO Source; ⚪ 掌握Source的Exec Source; ⚪ 掌握Source的Spooling Directory Source; ⚪ 掌握Source的Netcat Source; ⚪ 掌握Source的Sequence Generator Source;…...

F5 LTM 知识点和实验 4-持久化

第四章:持久化 持久化: 大多数应用都是有状态的,比如,使用一个购物网站,最重要的是用户在放入一个商品之后,刷新网页要能继续看到购物车里的东西,这就需要请求报文发到同一个后端服务器上,持久化就能完成这个功能。 持久化支持一下几种场景: 源地址目标地址SSLSIPH…...

SpringBoot之WebMvcConfigurer详解

目录 一、基本介绍 二、WebMvcConfigurer接口展示 三、常用方法列举 3.1 addInterceptors&#xff1a;添加拦截器 3.2 addResourceHandlers&#xff1a;添加静态资源 3.3 addCorsMappings&#xff1a;添加跨域 编写的初衷是为了自己巩固复习&#xff0c;如果能帮到你将是…...

WPF实战学习笔记22-添加自定义询问窗口

添加自定义询问窗口 详细代码&#xff1a;https://github.com/DongLiqiang/Mytodo/commit/221de6b2344d5c861f1d3b2fbb2480e3e3b35c26 添加自定义询问窗口显示方法 修改文件Mytodo.Extensions.DialogExtension 添加内容&#xff0c;类中添加内容 /// <summary> /// …...

Spring Boot项目的创建

hi 大家好,又见面了,今天继续讲解Spring Boot 文章目录 &#x1f436;1.什么是Spring Boot?&#x1f436;2.Spring Boot的优势&#x1f436;3.Spring Boot项目创建&#x1f33c;3.1使用ieda创建&#x1f95d;3.1.1下载插件Spring Boot Helper&#x1f95d;3.1.2创建项目 &…...

Python加载数据的5种方法

大家好&#xff0c;今天回顾五种引入数据的Python技术&#xff0c;并附有代码实例参考。 我们将使用Numpy、Pandas和Pickle包&#xff0c;所以要导入它们&#xff1a; import numpy as np import pandas as pd import pickle Manual功能 这是最困难的&#xff0c;因为你必须…...

QPoint、QLine、QSize、QRect

QPoint、QLine、QSize、QRect QPointQLineQSizeQRect QPoint // 构造函数 // 构造一个坐标原点, 即(0, 0) QPoint::QPoint(); // 参数为 x轴坐标, y轴坐标 QPoint::QPoint(int xpos, int ypos);// 设置x轴坐标 void QPoint::setX(int x); // 设置y轴坐标 void QPoint::setY(in…...

React Native 开发环境搭建(全平台详解)

React Native 开发环境搭建&#xff08;全平台详解&#xff09; 在开始使用 React Native 开发移动应用之前&#xff0c;正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南&#xff0c;涵盖 macOS 和 Windows 平台的配置步骤&#xff0c;如何在 Android 和 iOS…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

c# 局部函数 定义、功能与示例

C# 局部函数&#xff1a;定义、功能与示例 1. 定义与功能 局部函数&#xff08;Local Function&#xff09;是嵌套在另一个方法内部的私有方法&#xff0c;仅在包含它的方法内可见。 • 作用&#xff1a;封装仅用于当前方法的逻辑&#xff0c;避免污染类作用域&#xff0c;提升…...

保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!

目录 补间动画 1.创建资源文件夹 2.设置文件夹类型 3.创建.xml文件 4.样式设计 5.动画设置 6.动画的实现 内容拓展 7.在原基础上继续添加.xml文件 8.xml代码编写 (1)rotate_anim (2)scale_anim (3)translate_anim 9.MainActivity.java代码汇总 10.效果展示 逐帧…...

热烈祝贺埃文科技正式加入可信数据空间发展联盟

2025年4月29日&#xff0c;在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上&#xff0c;可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞&#xff0c;强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...

恶补电源:1.电桥

一、元器件的选择 搜索并选择电桥&#xff0c;再multisim中选择FWB&#xff0c;就有各种型号的电桥: 电桥是用来干嘛的呢&#xff1f; 它是一个由四个二极管搭成的“桥梁”形状的电路&#xff0c;用来把交流电&#xff08;AC&#xff09;变成直流电&#xff08;DC&#xff09;。…...

Python训练营-Day26-函数专题1:函数定义与参数

题目1&#xff1a;计算圆的面积 任务&#xff1a; 编写一个名为 calculate_circle_area 的函数&#xff0c;该函数接收圆的半径 radius 作为参数&#xff0c;并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求&#xff1a;函数接收一个位置参数 radi…...

Spring Boot + MyBatis 集成支付宝支付流程

Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例&#xff08;电脑网站支付&#xff09; 1. 添加依赖 <!…...

2025年- H71-Lc179--39.组合总和(回溯,组合)--Java版

1.题目描述 2.思路 当前的元素可以重复使用。 &#xff08;1&#xff09;确定回溯算法函数的参数和返回值&#xff08;一般是void类型&#xff09; &#xff08;2&#xff09;因为是用递归实现的&#xff0c;所以我们要确定终止条件 &#xff08;3&#xff09;单层搜索逻辑 二…...