令牌(token)+加密(加盐)

news2025/1/30 15:59:20

目录

一,令牌技术

1,不使用session的原因:

2,有两种解决方案:

(1)服务器层面的

(2)客户端层面的(JWT令牌)

生成签名:

生成jwt令牌:

验证令牌是否合法:

(3)令牌实际运用

二,加密加盐:

进行加密:

进行验证:


一,令牌技术

1,不使用session的原因:

登录页面,用户会将密码和账号传给服务器,服务器会进行校验并将校验结果传给前端,如果密码和账号正确服务器就会创建session,通过Cookie把sessionId返回给浏览器,但是一般情况下session都是储存在内存中的,当只有一台机子的时候,可以正常使用session来验证用户是否登录,但是在企业开发中通常是使用集群(单台机子如果如果一旦出现问题,就会整个无法访问了,为了保证服务器的稳定性,通常会将web应用部署到多个服务器上,并进行负载均衡,使用户的请求分配到不同的服务器上),集群环境无法部署session.

集群环境无法部署Session的原因,当用户发出请求代某一台服务器的时候,这台服务器会将session储存在这台服务器上,但是当用户再次访问服务器的时候,会被分配到其他的服务器上,但是此时,这台机子并没有用户的Session信息,这是就会出现问题.所以集群环境无法使用Session

2,有两种解决方案:

(1)服务器层面的

将session存储到公共服务器(Redis服务器).这时每个部署的web应用的服务器就会通过访问Redis服务器来查找session

<dependency> 
  <groupld>org.springframework.boot</groupld>
  <artifactld>spring-boot-starter-data-redis</artifactld></dependency>
<dependency>
  <groupld>org.springframework.session</groupld>
  <artifactld>spring-session-data-redis</artifactld>
</dependency>
 修改配置
spring.session.store-type=redis
server.servlet.session.timeout=1800
spring.session.redis.flush-mode=on_save
spring.session.redis.namespace=spring:session
spring.redis.host=82.157.14.10
spring.redis.password=
spring.redis.port=6379

(2)客户端层面的(JWT令牌)

使用令牌技术

用户登录,将请求通过负载均衡传给一个服务器,服务器将密码和账户进行验证了之后生成一个令牌,并返回给客户端,客户端收到令牌之后可以储存到Cookie中或者储存到localStorage,当用户再次访问的时候,此时这台服务器会先进性验证是否有令牌,且令牌是否过期.

我们这里使用的是JWT令牌:

JSON Web Tokens - jwt.io(官方链接)

JWT分为三个部分:

header:包括令牌的类型,以及使用的哈希算法

payload(负载):存放一些有效信息,可以进行自定义

signature:此部分防止JWT内容被篡改,确保安全性

引入依赖:

<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api -->
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt-api</artifactId>
			<version>0.11.5</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-impl -->
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt-impl</artifactId>
			<version>0.11.5</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
			<version>0.11.5</version>
			<scope>runtime</scope>
		</dependency>
生成签名:

签名有长度的限制,我们可以利用Keys.secretKeyFor()进行生成:

public void getKey(){
        SecretKey secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);
        String encode = Encoders.BASE64.encode(secretKey.getEncoded());
        System.out.println(encode);
    }

key是以HS256的编码生成,然后在通过Base64编码,将二进制形式的key编码成一个字符串,这就是签名

private static final String secret="4XhWaPIDMYSvaUTsqqDobe93QzC7gMCLd+xU5cIlNaA=";
private static final Key key=Keys.hmacShaKeyFor(Decoders.BASE64.decode(secret));

上述代码第一行为getkey函数生成的签名,这个签名通过(相同编码:Base64)解码的方式再次转化成二进制的形式,然后通过Keys.hmacShaKeyFor()的方法生成key;

生成jwt令牌:

然后使用Jwts的构建器,构建一个令牌,其中可以设置以下相关参数:

setId设置为一标识
setIssuer设置颁发者
setSubject设置主题
setIssuedAt设置颁发时间
setExpiration设置过期时间
signWith设置签名
setClaims自定义载荷
setAudience设置受众

header中的哈希算法的值,可以通过识别 生成key的算法 来获取

 public static String getToken(Map<String,Object> map){
        return Jwts.builder()
                .setClaims(map)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis()+expirationTime))
                .signWith(key)
                .compact();
    }
验证令牌是否合法:

利用Jwts生成一个解析器,在解析器中要对令牌的key(签名)进行配置,然后通过这个解析器验证令牌是否合法,代码如下:

public static Claims parseToken(String token){
        if (!StringUtils.hasLength(token)){
            throw new BlogException("token为空");
        }
        Claims claims = null;
        try {
            JwtParser build = Jwts.parserBuilder().setSigningKey(key).build();
            claims = build.parseClaimsJws(token).getBody();
            return claims;
        }catch (ExpiredJwtException e){
            log.error("token 过期");
        }catch (SignatureException e){
            log.error("签名不匹配");
        }catch (Exception e){
            log.error("token 解析失败,e:{}",e.getMessage());
        }
        return null;

    }

(3)令牌实际运用

令牌技术通常与拦截器配合使用,用户访问某个网站的时候,我们通常要验证用户是否登录,就需要从客户端拿到token来验证是否登录,或者令牌是否过期

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("拦截器进行拦截");
        String token=request.getHeader("user_header_token");
        String userId=request.getHeader("user_header_id");
        Claims claims = JwtUtil.parseToken(token);
        if (claims==null|| userId==null || !userId.equals(claims.get("id").toString())){
            response.setStatus(HttpStatus.UNAUTHORIZED.value());//返回401
            return false;
        }
        return true;
    }

当一个用户登录的时候,我们就需要根据用户信息生成对应的token,然后储存到客户端(Cookie/localStorage.......)

public LoginResponse login(LoginParam loginParam) {
        UserInfo userInfo = selectOneUser(loginParam);
        if (userInfo==null){
            throw new BlogException("用户不存在");
        }
        if (!userInfo.getPassword().equals(loginParam.getPassword())){
            throw new BlogException("登录密码错误");
        }
        Map<String,Object> map=new HashMap<>();
        map.put("id", userInfo.getId());
        map.put("name",userInfo.getUserName());
        String token= JwtUtil.getToken(map);
        LoginResponse loginResponse=new LoginResponse(userInfo.getId(),token);
        BeanUtils.copyProperties(userInfo,loginResponse);
        return loginResponse;

    }

二,加密加盐:

在数据库中,我们通常要对敏感信息比如,密码,身份证信息进行加密,以确保数据的安全性,加密的方式分为三种:

对称加密常见的算法有:AES,DES,3DES...
非对称加密常见的算法有RSA,DSA...
摘要算法把任意长度的数据转化为固定长度输出数据的一种密码算法,摘要算法是不可逆的,也就是无法解密,常见算法有MD5,SHA系列...

这里我们以MD5算法举例:

由于MD5算法没有办法进行解密,经过MD5算法加密后的密文是一样的,所以如果用户的密码过于简单的话,即使通过MD5加密,也会很容易破解出来,所以我们采取密码拼接字符串的的方式,这个拼接的字符串就称之为"盐",首先加盐后的字符串本身就不易被破解,其次加盐后密码和盐混在一起,也增加了密码的安全性.

由此,我们数据库中的储存的是[(用户的密码+盐)一起进行MD5加密+盐].当用户登录的时候,我们取出数据库密码中的盐,然后将[(用户输入是密码+盐)MD5加密+盐],看这时生成是数据与数据库中的数据是否一致,如果一致,则说明密码正确,如果不一种,这密码错误.

注意:"(用户输入是密码+盐)MD5加密"中用户密码和盐的顺序可自定义,"[(用户输入是密码+盐)MD5加密+盐]"中,加密后的字符串加盐的顺序也可自定义.

进行加密:

public static String encrypt(String password){
        if(!StringUtils.hasLength(password)){
            throw new BlogException("密码不能为空");
        }
        String salt= UUID.randomUUID().toString().replace("-","");//盐
        String securityPassword=DigestUtils.md5DigestAsHex((salt+password).getBytes(StandardCharsets.UTF_8));
        return salt+securityPassword;
    }

进行验证:

public static boolean verify(String password,String sqlSecurity){
        if (!StringUtils.hasLength(password)||!StringUtils.hasLength(sqlSecurity)){
            return false;
        }
        if (sqlSecurity.length()!=64){
            return false;
        }
        String salt = sqlSecurity.substring(0, 32);
        String securityPassword=DigestUtils.md5DigestAsHex((salt+password).getBytes(StandardCharsets.UTF_8));
        return (salt+securityPassword)
                .equals(sqlSecurity);
    }

在程序应用中,只需要将从数据库中查询的过程改为上述两个方法就可以了.

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

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

相关文章

Flask入门:打造简易投票系统

目录 准备工作 创建项目结构 编写HTML模板 编写Flask应用 代码解读 进一步优化 结语 Flask,这个轻量级的Python Web框架,因其简洁和易用性,成为很多开发者入门Web开发的首选。今天,我们就用Flask来做一个简单的投票系统,让你快速上手Web开发,同时理解Flask的核心概…

阿里巴巴前端面试经验

阿里巴巴面经&#xff08;新零售事业群-CBU技术部&#xff09; 笔试 /*** 1. 查找落单的数字* 描述&#xff1a;给定一个非空的数字数组&#xff0c;数组有且只有一个非重复项&#xff0c;实现一个方法获取落单项* 示例:* getSingleNumber([1, 2, 1, 2, 0]); // 0* getSingle…

指针的深入讲解

本章重点&#xff1a; 字符指针数组指针指针数组数组传参和指针传参函数指针函数指针数组指向函数指针数组的指针回调函数 我们在指针的初阶的时候主要讲了&#xff1a; 1.指针就是变量&#xff0c;用来存放地址&#xff0c;地址唯一标识一块内存空间 2.指针的大小是固定4个…

网络多层的协议详述

网络层 1&#xff09;地址管理&#xff1a;制定一系列的规则&#xff0c;通过地址&#xff0c;在网络上描述出一个设备的位置 2&#xff09;路由选择&#xff1a;网络环境比较复杂&#xff0c;从一个节点到另一个节点&#xff0c;存在很多条不同的路径&#xff0c;需要规划出…

Zabbix6.0升级为6.4

为了体验一些新的功能&#xff0c;比如 Webhook 和问题抑制等&#xff0c;升级个小版本。 一、环境信息 1. 版本要求 一定要事先查看官方文档&#xff0c;确认组件要求的版本&#xff0c;否则版本过高或者过低都会出现问题。 2. 升级前后信息 环境升级前升级后操作系统CentOS…

UML复习题

用例与用户的4种关系对象图和类图有什么关系:对象图是类图某一时刻的快照组件图&#xff0c;体现的是静态图部署图&#xff0c;涉及到硬件的结点&#xff0c;实线链接 以上都是静态图 时序图&#xff0c;消息先后协作图 &#xff0c;谁和谁交互&#xff0c;对象之间的交互某一…

【MFC】多工具栏如何保存状态

MFC中的工具栏本来只有一个&#xff0c;如果想增加几个工具栏是比较简单&#xff0c;但现在一个重要的问题是&#xff0c;状态无法保存&#xff0c;导致每次打开&#xff0c;工具栏就会出现问题&#xff0c;要么偏移位置要么显示不出。 经过研究&#xff0c;发现是MFC框架中的…

Buck开关电源闭环控制的仿真研究15V/5V[Matlab/simulink源码+Word文档]

课题设计要求 ⑴输入直流电压(VIN)&#xff1a;15V ⑵输出电压(VO)&#xff1a;5.0V ⑶负载电阻&#xff1a;R2欧 ⑷输出电压纹波峰-峰值 Vpp≤50mV &#xff0c;电感电流脉动&#xff1a;输出电流的10% ⑸开关频率(fs)&#xff1a;100kHz ⑹BUCK主电路二极管的通态压降VD0.5V…

鸿蒙项目云捐助第十八讲云捐助我的页面下半部分的实现

鸿蒙项目云捐助第十八讲云捐助我的页面下半部分的实现 在一般的应用app中都会有一个“我的”页面&#xff0c;在“我的”页面中可以完成某些设置&#xff0c;也可以完成某些附加功能&#xff0c;如“修改密码”等相关功能。这里的鸿蒙云捐助也有一个“我的”功能页面。这里对“…

Flink2.0未来趋势中需要注意的一些问题

手机打字&#xff0c;篇幅不长&#xff0c;主要讲一下FFA中关于Flink2.0的未来趋势&#xff0c;直接看重点。 Flink Forward Asia 2024主会场有一场关于Flink2.0的演讲&#xff0c;很精彩&#xff0c;官方也发布了一些关于Flink2.0的展望和要解决的问题。 1.0时代和2.0时代避免…

《深入浅出Apache Spark》系列⑤:Spark SQL的表达式优化

导读&#xff1a;随着数据量的快速增长&#xff0c;传统的数据处理方法难以满足对计算速度、资源利用率以及查询响应时间的要求。为了应对这些挑战&#xff0c;Spark SQL 引入了多种优化技术&#xff0c;以提高查询效率&#xff0c;降低计算开销。本文从表达式层面探讨了 Spark…

在Tomcat中部署应用时,如何通过域名访问而不加端口号

--江上往来人&#xff0c;但爱鲈鱼美。 --君看一叶舟&#xff0c;出没风波里。 在Tomcat中部署应用时&#xff0c;如果你希望通过域名访问而不加端口号&#xff08;默认HTTP端口80或HTTPS端口443&#xff09;&#xff0c;你通常需要在前端使用一个反向代理服务器&#xff08;如…

如何测量分辨率

一、什么是分辨率&#xff1f; 分辨率指的是分清物体细节的能力。分辨率是一个成像系统还原空间频率的能力。一些人只是简单的用分辨率去描述极限分辨率&#xff0c;但是相机在在不同的对比度的情况下还原低&#xff0c;中和高频率的能力&#xff0c;也可以显示全面综合的信息。…

Leetcode分隔链表

java 实现 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(int val, ListNode next) { this.val val; this.next next; }* }*/ class …

maui开发成生安卓apk,运行提示该应用与此设备的CPU不兼容

在生成.NET MAUI安卓应用时遇到“该应用与此设备的CPU不兼容”的问题&#xff0c;确保你的.NET MAUI应用支持的Android目标框架与设备CPU架构相匹配。例如&#xff0c;如果你的应用是为ARM64架构编译的&#xff0c;而你的设备是x86架构&#xff0c;就会出现不兼容的问题。 一、…

在 Unity 6 中使用APV为您的世界创建全局照明的新方法(一)

Unity 6 中推出的新照明功能让您能够更快速、更高效的完成对烘焙场景的照明工作&#xff0c;在本文中我们将与大家详细分享在 Unity 6 中应用自适应探针卷创建快速全局光照的更多细节与具体应用方法。由于内容比较丰富&#xff0c;我们将把内容分为三篇文章&#xff0c;以便大家…

深度学习之超分辨率算法——FRCNN

– 对之前SRCNN算法的改进 输出层采用转置卷积层放大尺寸&#xff0c;这样可以直接将低分辨率图片输入模型中&#xff0c;解决了输入尺度问题。改变特征维数&#xff0c;使用更小的卷积核和使用更多的映射层。卷积核更小&#xff0c;加入了更多的激活层。共享其中的映射层&…

VSCode 搭建Python编程环境 2024新版图文安装教程(Python环境搭建+VSCode安装+运行测试+背景图设置)

名人说&#xff1a;一点浩然气&#xff0c;千里快哉风。—— 苏轼《水调歌头》 创作者&#xff1a;Code_流苏(CSDN) 目录 一、Python环境安装二、VScode下载及安装三、VSCode配置Python环境四、运行测试五、背景图设置 很高兴你打开了这篇博客&#xff0c;更多详细的安装教程&…

使用Docker启用MySQL8.0.11

目录 一、Docker减小镜像大小的方式 1、基础镜像选择 2、减少镜像层数 3、清理无用文件和缓存 4、优化文件复制&#xff08;COPY和ADD指令&#xff09; 二、Docker镜像多阶段构建 1、什么是dockers镜像多阶段构建 1.1 概念介绍 1.2 构建过程和优势 2、怎样在Dockerfil…

Windows安全中心(病毒和威胁防护)的注册

文章目录 Windows安全中心&#xff08;病毒和威胁防护&#xff09;的注册1. 简介2. WSC注册初探3. WSC注册原理分析4. 关于AMPPL5. 参考 Windows安全中心&#xff08;病毒和威胁防护&#xff09;的注册 本文我们来分析一下Windows安全中心&#xff08;Windows Security Center…