JAVA代码优化:Token验证处理

简述:

Token验证处理是指在客户端和服务端之间进行身份验证和授权的过程。在这个过程中,客户端通常会提供一个令牌(Token),用于证明其合法性和权限。服务端接收到该令牌后,需要对其进行验证,以确定该请求是否来自合法的客户端。

JWT是一种常见的Token验证处理方式。

JWT简述:

JWT(JSON Web Token)由三部分组成,它们分别是头部(Header)、载荷(Payload)和签名(Signature)。每个部分都使用Base64编码进行序列化,并使用点号(.)作为分隔符。

  1. 头部(Header):头部包含了关于JWT的元数据信息,以及指定所使用的算法的声明。常见的算法有HMAC、RSA和ECDSA等。头部通常是一个JSON对象,例如:
    {//"alg"表示所使用的算法(此处为HMAC SHA-256)"alg": "HS256",//"typ"表示令牌的类型(此处为JWT)"typ": "JWT"
    }
  2. 载荷(Payload):载荷包含了一些声明(claims),这些声明是关于实体(如用户)和其他数据的陈述。载荷可以包含预定义的声明,如"sub"(主题,表示主体的唯一标识)、"exp"(过期时间,表示令牌的有效期)、"iat"(发布时间,表示令牌的发行时间)等,也可以包含自定义的声明。载荷通常也是一个JSON对象,例如:
    {"sub": "1234567890","name": "John Doe","iat": 1516239022
    }
    
  3. 签名(Signature):签名是使用指定的算法(如HMAC、RSA等)对头部和载荷进行签名生成的一串字符串。签名用于验证令牌的完整性和真实性,以防止被篡改。签名的生成需要使用密钥(秘钥),服务端在验证令牌时也需要使用相同的密钥进行签名验证。
  4. JWT的三部分是通过点号(.)连接起来形成一个完整的令牌,例如:
    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
    .
    eyJzdWIiOiAiMTIzNDU2Nzg5MCIsIm5hbWUiOiAiSm9obiBEb2UiLCAiaWF0IjogMTUxNjIzOTAyMn0
    .
    SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
    

    token验证处理(TokenService)

  5. package com.muyuan.framework.web.service;import java.util.HashMap;
    import java.util.Map;
    import java.util.concurrent.TimeUnit;
    import javax.servlet.http.HttpServletRequest;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    import com.muyuan.common.constant.Constants;
    import com.muyuan.common.core.domain.model.LoginUser;
    import com.muyuan.common.core.redis.RedisCache;
    import com.muyuan.common.utils.ServletUtils;
    import com.muyuan.common.utils.StringUtils;
    import com.muyuan.common.utils.ip.AddressUtils;
    import com.muyuan.common.utils.ip.IpUtils;
    import com.muyuan.common.utils.uuid.IdUtils;
    import eu.bitwalker.useragentutils.UserAgent;
    import io.jsonwebtoken.Claims;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureAlgorithm;/*** token验证处理** */
    @Component
    public class TokenService {// 令牌自定义标识@Value("${token.header}")private String header;// 令牌秘钥@Value("${token.secret}")private String secret;// 令牌有效期(默认30分钟)@Value("${token.expireTime}")private int expireTime;protected static final long MILLIS_SECOND = 1000;protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L;@Autowiredprivate RedisCache redisCache;/*** 获取用户身份信息** @return 用户信息*/public LoginUser getLoginUser(HttpServletRequest request) {// 获取请求携带的令牌String token = getToken(request);//判断一个字符串是否为非空串(详见字符串工具类)if (StringUtils.isNotEmpty(token)) {//Claims对象,它包含了Payload部分的信息,也就是我们在生成Token时添加的各种自定义属性。// 例如,如果我们在生成Token时添加了用户名、角色等信息,// 那么在解析Token时就可以通过claims.get("username")、claims.get("role")等方法来获取这些信息。Claims claims = parseToken(token);// 解析对应的权限以及用户信息//令牌前缀//public static final String LOGIN_USER_KEY = "login_user_key";String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);String userKey = getTokenKey(uuid);//redisCache.getCacheObject获得缓存的基本对象(详见spring redis 工具类)LoginUser user = redisCache.getCacheObject(userKey);return user;}return null;}/*** 设置用户身份信息*/public void setLoginUser(LoginUser loginUser){//判断一个字符串是否为非空串(详见字符串工具类)if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken())){refreshToken(loginUser);}}/*** 删除用户身份信息*/public void delLoginUser(String token){//判断一个字符串是否为非空串(详见字符串工具类)if (StringUtils.isNotEmpty(token)){String userKey = getTokenKey(token);//删除单个对象redisCache.deleteObject(userKey);}}/*** 创建令牌** @param loginUser 用户信息* @return 令牌*/public String createToken(LoginUser loginUser) {//IdUtils  id快速生成器(详见文章ID生成工具)String token = IdUtils.fastUUID();//登录对象类的唯一标识tokenloginUser.setToken(token);//设置用户代理信息setUserAgent(loginUser);//刷新令牌有效期refreshToken(loginUser);//claims是用于存放Payload部分的信息的Map对象,它包含了我们需要在Token中添加的各种自定义属性,// 例如用户ID、用户名、角色等Map<String, Object> claims = new HashMap<>();//常量令牌前缀public static final String LOGIN_USER_KEY = "login_user_key";claims.put(Constants.LOGIN_USER_KEY, token);//存放非敏感信息claims.put("username",loginUser.getUsername());claims.put("nickName",loginUser.getUser().getNickName());claims.put("createTime",loginUser.getUser().getCreateTime());return createToken(claims);}/*** 验证令牌有效期,相差不足20分钟,自动刷新缓存** @param loginUser* @return 令牌*/public void verifyToken(LoginUser loginUser){//过期时间long expireTime = loginUser.getExpireTime();//当前时间long currentTime = System.currentTimeMillis();if (expireTime - currentTime <= MILLIS_MINUTE_TEN){refreshToken(loginUser);}}/*** 刷新令牌有效期** @param loginUser 登录信息*/public void refreshToken(LoginUser loginUser){//设置登录时间loginUser.setLoginTime(System.currentTimeMillis());//设置过期时间loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);// 根据uuid将loginUser缓存String userKey = getTokenKey(loginUser.getToken());//储存redis详见文章(spring redis 工具类)redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);}/*** 设置用户代理信息** @param loginUser 登录信息*/public void setUserAgent(LoginUser loginUser){//User-Agent是HTTP协议中的一个头部信息,通常用于标识发送HTTP请求的客户端软件或代理程序的详细信息。// 它包含了客户端软件类型、版本号、操作系统类型、语言等信息。// 在Web开发中,服务器可以通过User-Agent头部信息来识别客户端的浏览器和操作系统等信息。UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));//获取ip详见文章(ip获取地址类)String ip = IpUtils.getIpAddr(ServletUtils.getRequest());//存入以下数据loginUser.setIpaddr(ip);loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip));loginUser.setBrowser(userAgent.getBrowser().getName());loginUser.setOs(userAgent.getOperatingSystem().getName());}/*** 从数据声明生成令牌** @param claims 数据声明* @return 令牌*/private String createToken(Map<String, Object> claims){String token =//Jwts.builder()方法创建一个JWT Builder对象,用于构建JWT Token。Jwts.builder()//调用setClaims(claims)方法设置JWT Token中的payload部分,即要传递的自定义信息。//这里的claims参数是一个Map对象,其中包含了需要传递的键值对信息。.setClaims(claims)//signWith(SignatureAlgorithm.HS512, secret)方法对JWT Token进行签名,使用的算法是HS512,密钥是secret变量.signWith(SignatureAlgorithm.HS512, secret)//compact()方法将JWT Token生成为一个字符串,并将其作为方法的返回值。.compact();return token;}/*** 从令牌中获取数据声明** @param token 令牌* @return 数据声明*/private Claims parseToken(String token){//Jwts.parser()方法创建一个JWT Parser对象,用于解析JWT Tokenreturn Jwts.parser()//setSigningKey(secret)方法设置解析Token时所需的签名密钥,密钥是secret变量。.setSigningKey(secret)//parseClaimsJws(token)方法对传入的JWT Token进行解析。这里的token参数是要解析的JWT Token字符串。.parseClaimsJws(token)//getBody()方法获取解析后的Token内容,返回的是一个Claims对象,包含了Token中的payload部分的键值对信息。.getBody();}/*** 从令牌中获取用户名** @param token 令牌* @return 用户名*/public String getUsernameFromToken(String token){//parseToken(token)方法解析传入的JWT TokenClaims claims = parseToken(token);return claims.getSubject();}/*** 获取请求token** @param request* @return token*/private String getToken(HttpServletRequest request){//获取请求头名称,通常为Authorization。String token = request.getHeader(header);//判断一个字符串是否为非空串(详见字符串工具类)//判断获取到的Token字符串是否非空,并且是否以预定义的Token前缀Constants.TOKEN_PREFIX开头if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)){//将Token前缀替换为空字符串,只保留真实的Token内容。token = token.replace(Constants.TOKEN_PREFIX, "");}return token;}private String getTokenKey(String uuid){//登录用户 redis key//public static final String LOGIN_TOKEN_KEY = "login_tokens:";return Constants.LOGIN_TOKEN_KEY + uuid;}
    }
    

    附加登录用户身份权限(LoginUser)

    package com.muyuan.common.core.domain.model;import java.util.Collection;
    import java.util.Set;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.userdetails.UserDetails;
    import com.fasterxml.jackson.annotation.JsonIgnore;
    import com.muyuan.common.core.domain.entity.SysUser;/*** 登录用户身份权限* * */
    public class LoginUser implements UserDetails
    {private static final long serialVersionUID = 1L;/*** 用户唯一标识*/private String token;/*** 登录时间*/private Long loginTime;/*** 过期时间*/private Long expireTime;/*** 登录IP地址*/private String ipaddr;/*** 登录地点*/private String loginLocation;/*** 浏览器类型*/private String browser;/*** 操作系统*/private String os;/*** 权限列表*/private Set<String> permissions;/*** 用户信息*/private SysUser user;public String getToken(){return token;}public void setToken(String token){this.token = token;}public LoginUser(){}public LoginUser(SysUser user, Set<String> permissions){this.user = user;this.permissions = permissions;}@JsonIgnore@Overridepublic String getPassword(){return user.getPassword();}@Overridepublic String getUsername(){return user.getUserName();}/*** 账户是否未过期,过期无法验证*/@JsonIgnore@Overridepublic boolean isAccountNonExpired(){return true;}/*** 指定用户是否解锁,锁定的用户无法进行身份验证* * @return*/@JsonIgnore@Overridepublic boolean isAccountNonLocked(){return true;}/*** 指示是否已过期的用户的凭据(密码),过期的凭据防止认证* * @return*/@JsonIgnore@Overridepublic boolean isCredentialsNonExpired(){return true;}/*** 是否可用 ,禁用的用户不能身份验证* * @return*/@JsonIgnore@Overridepublic boolean isEnabled(){return true;}public Long getLoginTime(){return loginTime;}public void setLoginTime(Long loginTime){this.loginTime = loginTime;}public String getIpaddr(){return ipaddr;}public void setIpaddr(String ipaddr){this.ipaddr = ipaddr;}public String getLoginLocation(){return loginLocation;}public void setLoginLocation(String loginLocation){this.loginLocation = loginLocation;}public String getBrowser(){return browser;}public void setBrowser(String browser){this.browser = browser;}public String getOs(){return os;}public void setOs(String os){this.os = os;}public Long getExpireTime(){return expireTime;}public void setExpireTime(Long expireTime){this.expireTime = expireTime;}public Set<String> getPermissions(){return permissions;}public void setPermissions(Set<String> permissions){this.permissions = permissions;}public SysUser getUser(){return user;}public void setUser(SysUser user){this.user = user;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities(){return null;}
    }
    

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

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

相关文章

隐写术和人工智能

在一项新的研究中&#xff0c;人工智能对齐研究实验室 Redwood Research 揭示了大型语言模型 (LLM) 可以掌握“编码推理”&#xff0c;这是一种隐写术形式。 这种有趣的现象使得大型语言模型能够以人类读者无法理解的方式巧妙地将中间推理步骤嵌入到生成的文本中。 大型语言…

java版王者荣耀

1.主要功能 键盘W,A,S,D键&#xff1a;控制玩家上下左右移动。按钮一&#xff1a;控制英雄发射一个矩形攻击红方小兵。按钮二&#xff1a;控制英雄发射魅惑技能&#xff0c;伤害小兵并让小兵停止移动。技能三&#xff1a;攻击多个敌人并让小兵停止移动。普攻&#xff1a;对小兵…

C++初阶 | [七] string类(上)

摘要&#xff1a;标准库中的string类的常用函数 C语言中&#xff0c;字符串是以\0结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c;C标准库中提供了一些str系列的库函数&#xff0c; 但是这些库函数与字符串是分离开的&#xff0c;不太符合OOP(面向对象)的思想&#…

03、pytest初体验

官方实例 # content of test_sample.py def func(x):return x 1def test_ansewer():assert func(3) 5步骤解释 [100%]指的是所有测试用例的总体进度&#xff0c;完成后&#xff0c;pytest显示一个失败报告&#xff0c;因为func(3)没有返回5 注意&#xff1a;你可以使用ass…

【滤波第二期】中值滤波的原理和C代码

中值滤波是一种非线性数字滤波技术&#xff0c;主要应用于信号处理和图像处理领域&#xff0c;用于减小信号中的噪声和离群值。中值滤波的核心思想是通过计算一组数据点的中间值&#xff0c;以抑制脉冲噪声等离群值的影响&#xff0c;从而实现信号的平滑处理。 1&#xff0c;中…

PIL、cv2读取类型以及转换,PIL、numpy、tensor格式以及cuda、cpu的格式转换

一、PIL&#xff0c;cv2读取数据图片以及之间的转换 cv2PIL读取acv2.imread()aImage.open()读取类型数组类型PIL类型读取尺寸排列&#xff08;H,W,C&#xff09;&#xff08;W,H,C&#xff09;显示图片cv2.imshow(“a”, a)cv2.waitKey (0)a.show()相互之间转换显示Image.from…

<Linux>(极简关键、省时省力)《Linux操作系统原理分析之linux存储管理(5)》(21)

《Linux操作系统原理分析之linux存储管理&#xff08;5&#xff09;》&#xff08;21&#xff09; 6 Linux存储管理6.6 Linux 物理空间管理6.6.1 Linux 物理内存空间6.6.2 物理页面的管理6.6.3 空闲页面管理——buddy 算法 6.7 内存的分配与释放6.7.1 物理内存分配的数据结构 6…

canvas绘制小丑

说明&#xff1a; 借鉴博主基于canvas绘制一个爱心(10行代码就够了) - 掘金 (juejin.cn) 代码实现 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content&quo…

实现简单的Http服务器+SpringMvc,集成到Spring

实现简单的Http服务器SpringMvc&#xff0c;集成到Spring 1、Http协议 1.1、HTTP 协议请求格式 方法 空格 URL 空格 版本 回车符 换行符头部域名称&#xff1a;头部域值 回车符 换行符...头部域名称&#xff1a;头部域值 回车符 …

《系统架构设计师教程(第2版)》第2章-计算机系统基础知识-03-嵌入式

文章目录 1. 基本概念2. 嵌入式系统的组成3. 嵌入式系统的特点4. 嵌入式系统分类4.1 分类4.2 实时系统(Real-Time System,RTS)4.3 安全攸关系统 (Safety-Critical System)7. 嵌入式软件7.1. 嵌入式系统软件组成架构7.1.1 硬件层7.1.2 抽象层7.1.3 操作系统层7.1.4 中间件层7.1…

【云备份】服务端热点管理业务处理模块

28. 服务端热点管理模块实现-热点管理实现思路 服务器端的热点文件管理是对上传的非热点文件进行压缩存储&#xff0c;节省磁盘空间。 而热点文件的判断在于上传的文件的最后一次访问时间是否在热点判断时间之内&#xff0c;比如如果一个文件一天都没有被访问过我们就认为这是…

【UGUI】sprite精灵的创建与编辑

如何切图&#xff08;sprite editor&#xff09; 有时候一张图可能包含了很多张子图&#xff0c;就需要在Unity 临时处理一下&#xff0c;切开&#xff0c;比如动画序列帧图集 虽然我们可以在PS里面逐个切成一样的尺寸导出多张&#xff0c;再放回Unity&#xff0c;但是不需要这…

音视频技术开发周刊 | 322

每周一期&#xff0c;纵览音视频技术领域的干货。 新闻投稿&#xff1a;contributelivevideostack.com。 超级AI不会主宰人类&#xff0c;但人工智能必须开源&#xff01;LeCun最新采访引全网300万人围观 LeCun最新访谈视频中&#xff0c;再次坦露了自己对开源AI的看法。超级AI…

安路Anlogic FPGA下载器的驱动安装教程

安路FPGA下载器驱动安装教程 安路FPGA下载器&#xff1a;EN-ALC10,是一款高性能FPGA下载线&#xff08;编程器&#xff09;&#xff0c;支持安路的开发软件TDS和全系列FPGA芯片下载编程&#xff0c;支持全速USB2.0与电脑进行数据通信&#xff0c;通过JTAG协议与FPGA进行程序下…

鸿蒙开发:UIAbility组件间交互探索实战【鸿蒙专栏-22】

UIAbility组件间交互(设备内) 在设备内,UIAbility(用户界面能力)是系统调度的最小单元,它们负责展示用户界面和执行相关的业务逻辑。设备内的不同功能模块之间的交互是应用程序开发中的重要部分。本文将探讨设备内UIAbility之间的交互方式,包括启动应用内的UIAbility、…

LeetCode330. Patching Array

文章目录 一、题目二、题解 一、题目 Given a sorted integer array nums and an integer n, add/patch elements to the array such that any number in the range [1, n] inclusive can be formed by the sum of some elements in the array. Return the minimum number of…

Redux

一、纯函数 1、react 中的纯函数 react 中组件就被要求像是一个纯函数&#xff08;因为还有类组件&#xff09;redux 中有一个reducer 的概念&#xff0c;也是要求必须是一个纯函数 2、 纯函数的条件 确定的输入一定会产生确定的输出函数在执行过程中&#xff0c;不能产生副…

vue自定义指令:指定文字高亮

vue自定义指令&#xff1a;指定文字高亮 自定义指令 除了核心功能默认内置的指令 (v-model 和 v-show)&#xff0c;Vue 也允许注册自定义指令。注意&#xff0c;在 Vue2.0 中&#xff0c;代码复用和抽象的主要形式是组件。然而&#xff0c;有的情况下&#xff0c;你仍然需要对…

【重点】【区间问题】56.合并区间

题目 注意有个类似的题目&#xff1a;&#xff0c;注意区分。 class Solution {public int[][] merge(int[][] intervals) {List<List<Integer>> res new ArrayList<>();Arrays.sort(intervals, (a1, a2) -> {return a1[0] - a2[0];});int left Intege…

JS实现成才网注册系统(网页数据验证)

主代码 <!DOCTYPE htmlPUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns"http://www.w3.org/1999/xhtml"><head><meta http-equiv"Conten…