JWT的原理及实际使用

news2024/11/20 0:28:57

                                                       🎬 艳艳耶✌️:个人主页

                                                       🔥 个人专栏 :《Spring与Mybatis集成整合》《Vue.js使用》

                ⛺️ 生活的理想,为了不断更新自己 ! 

 

目录

1.JWT是什么?

2. jwt工具类介绍

3. jwt集成spa项目


1.JWT是什么?

         JWT全称为JSON Web Token,是一种用于身份验证和授权的开放标准。它是一个紧凑且安全的方式,通过在不同系统之间传递可信任的信息来实现用户身份验证。JWT由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。


2. jwt工具类介绍

JWT工具类是一个用于生成、解析和验证JSON Web Token的辅助类。它提供了一系列方法来简化JWT的处理过程,使得开发者可以方便地在应用中使用JWT进行身份验证和授权。

JWT工具类通常包括以下功能:

  • 生成JWT:提供方法用于生成JWT,传入有效载荷和加密密钥等参数,生成符合规范的JWT字符串。
  • 解析JWT:提供方法用于解析JWT,将JWT字符串解析成头部和载荷的JSON对象,并对签名进行验证。
  • 验证JWT:提供方法用于验证JWT的有效性,包括验证签名是否正确、验证令牌是否过期等。
  • 获取载荷信息:提供方法用于获取JWT中的载荷信息,比如用户ID、角色等。
  • 刷新JWT:提供方法用于刷新JWT,生成新的JWT并返回给客户端,用于延长认证的有效期。
  • 配置参数:提供方法用于配置JWT的相关参数,比如加密算法、密钥、过期时间等。

使用JWT工具类可以简化JWT的处理逻辑,减少代码重复性,并增加系统的安全性。通过封装好的方法,开发者可以方便地在不同的场景中使用JWT进行身份验证和授权,提高开发效率。但需要注意,在使用JWT工具类时,应确保密钥的安全性,避免泄露导致令牌被篡改或伪造。

代码展示:

package com.sy.ssm.util;
 
import java.util.Date;
import java.util.Map;
import java.util.UUID;
 
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
 
import org.apache.commons.codec.binary.Base64;
 
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
 
/**
 * JWT验证过滤器:配置顺序 CorsFilte->JwtUtilsr-->StrutsPrepareAndExecuteFilter
 *
 */
public class JwtUtils {
	/**
	 * JWT_WEB_TTL:WEBAPP应用中token的有效时间,默认30分钟
	 */
	public static final long JWT_WEB_TTL = 30 * 60 * 1000;
 
	/**
	 * 将jwt令牌保存到header中的key
	 */
	public static final String JWT_HEADER_KEY = "jwt";
 
	// 指定签名的时候使用的签名算法,也就是header那部分,jwt已经将这部分内容封装好了。
	private static final SignatureAlgorithm SIGNATURE_ALGORITHM = SignatureAlgorithm.HS256;
	private static final String JWT_SECRET = "f356cdce935c42328ad2001d7e9552a3";// JWT密匙
	private static final SecretKey JWT_KEY;// 使用JWT密匙生成的加密key
 
	static {
		byte[] encodedKey = Base64.decodeBase64(JWT_SECRET);
		JWT_KEY = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
	}
 
	private JwtUtils() {
	}
 
	/**
	 * 解密jwt,获得所有声明(包括标准和私有声明)
	 * 
	 * @param jwt
	 * @return
	 * @throws Exception
	 */
	public static Claims parseJwt(String jwt) {
		Claims claims = Jwts.parser()
				.setSigningKey(JWT_KEY)
				.parseClaimsJws(jwt)
				.getBody();
		return claims;
	}
 
	/**
	 * 创建JWT令牌,签发时间为当前时间
	 * 
	 * @param claims
	 *            创建payload的私有声明(根据特定的业务需要添加,如果要拿这个做验证,一般是需要和jwt的接收方提前沟通好验证方式的)
	 * @param ttlMillis
	 *            JWT的有效时间(单位毫秒),当前时间+有效时间=过期时间
	 * @return jwt令牌
	 */
	public static String createJwt(Map<String, Object> claims, 
			long ttlMillis) {
		// 生成JWT的时间,即签发时间 2021-10-30 10:02:00 -> 30 10:32:00
	
		long nowMillis = System.currentTimeMillis();
 
		
		//链式语法:
		// 下面就是在为payload添加各种标准声明和私有声明了
		// 这里其实就是new一个JwtBuilder,设置jwt的body
		JwtBuilder builder = Jwts.builder()
				// 如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的
				.setClaims(claims)
				// 设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为一次性token,从而回避重放攻击。
				// 可以在未登陆前作为身份标识使用
				.setId(UUID.randomUUID().toString().replace("-", ""))
				// iss(Issuser)签发者,写死
				.setIssuer("zking")
				// iat: jwt的签发时间
				.setIssuedAt(new Date(nowMillis))
				// 代表这个JWT的主体,即它的所有人,这个是一个json格式的字符串,可放数据{"uid":"zs"}。此处没放
				// .setSubject("{}")
				// 设置签名使用的签名算法和签名使用的秘钥
				.signWith(SIGNATURE_ALGORITHM, JWT_KEY)
				// 设置JWT的过期时间
				.setExpiration(new Date(nowMillis + ttlMillis));
 
		return builder.compact();
	}
 
	/**
	 * 复制jwt,并重新设置签发时间(为当前时间)和失效时间
	 * 
	 * @param jwt
	 *            被复制的jwt令牌
	 * @param ttlMillis
	 *            jwt的有效时间(单位毫秒),当前时间+有效时间=过期时间
	 * @return
	 */
	public static String copyJwt(String jwt, Long ttlMillis) {
		//解密JWT,获取所有的声明(私有和标准)
		//old
		Claims claims = parseJwt(jwt);
 
		// 生成JWT的时间,即签发时间
		long nowMillis = System.currentTimeMillis();
 
		// 下面就是在为payload添加各种标准声明和私有声明了
		// 这里其实就是new一个JwtBuilder,设置jwt的body
		JwtBuilder builder = Jwts.builder()
				// 如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的
				.setClaims(claims)
				// 设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为一次性token,从而回避重放攻击。
				// 可以在未登陆前作为身份标识使用
				//.setId(UUID.randomUUID().toString().replace("-", ""))
				// iss(Issuser)签发者,写死
				// .setIssuer("zking")
				// iat: jwt的签发时间
				.setIssuedAt(new Date(nowMillis))
				// 代表这个JWT的主体,即它的所有人,这个是一个json格式的字符串,可放数据{"uid":"zs"}。此处没放
				// .setSubject("{}")
				// 设置签名使用的签名算法和签名使用的秘钥
				.signWith(SIGNATURE_ALGORITHM, JWT_KEY)
				// 设置JWT的过期时间
				.setExpiration(new Date(nowMillis + ttlMillis));
		return builder.compact();
	}
}
 
 
 
 

3. jwt集成spa项目

后台代码:

 用户登录方法,放开用户信息生成jwt串保存到响应头中

 代码展示:

package com.sy.ssm.controller;

import com.sy.ssm.service.IUserService;
import com.sy.ssm.util.JsonResponseBody;
import com.sy.ssm.util.PageBean;
import com.sy.ssm.vo.UserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.sy.ssm.jwt.*;

@Controller
@RequestMapping("/user")
public class UserController {

    @Autowired
    private IUserService userService;

    @RequestMapping("/userLogin")
    @ResponseBody
    public JsonResponseBody<?> userLogin(UserVo userVo, HttpServletResponse response){
        if(userVo.getUsername().equals("admin")&&userVo.getPassword().equals("123")){
            //私有要求claim
//            Map<String,Object> json=new HashMap<String,Object>();
//            json.put("username", userVo.getUsername());
            //生成JWT,并设置到response响应头中
//            String jwt=JwtUtils.createJwt(json, JwtUtils.JWT_WEB_TTL);
//            response.setHeader(JwtUtils.JWT_HEADER_KEY, jwt);
            return new JsonResponseBody<>("用户登陆成功!",true,0,null);
        }else{
            return new JsonResponseBody<>("用户名或密码错误!",false,0,null);
        }
    }

    @RequestMapping("/userRegister")
    @ResponseBody
    public JsonResponseBody<?> userRegister(UserVo userVo, HttpServletResponse response){
        //状态新注册默认为0
        userVo.setStatus("0");
        //因为ID为String类型需要手动设置,当然可以根据自己的需要改为Int类型
        userVo.setId("15");
        int i = userService.insertSelective(userVo);
        if(i>0){
            return new JsonResponseBody<>("用户注册完成!快去登入吧!",true,0,null);
        }else{
            return new JsonResponseBody<>("用户注册失败!重新输入。",false,0,null);
        }
    }

    @RequestMapping("/queryUserPager")
    @ResponseBody
    public JsonResponseBody<List<Map<String,Object>>>
            queryUserPager(UserVo userVo, HttpServletRequest request){
        try {
            PageBean pageBean=new PageBean();
            pageBean.setRequest(request);
            List<Map<String, Object>> users = userService.queryUserPager(userVo, pageBean);
            return new JsonResponseBody<>("OK",true,pageBean.getTotal(),users);
        } catch (Exception e) {
            e.printStackTrace();
            return new JsonResponseBody<>("分页查询用户信息失败!",false,0,null);
        }

    }
}

关闭JwtFilter中的OFF开关,开启jwt验证

代码展示:

package com.sy.ssm.jwt;

import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import io.jsonwebtoken.Claims;

/**
 * * JWT验证过滤器,配置顺序 :CorsFilter-->JwtFilter-->struts2中央控制器
 * 
 * @author Administrator
 *
 */

public class JwtFilter implements Filter {

	// 排除的URL,一般为登陆的URL(请改成自己登陆的URL)
	private static String EXCLUDE = "^/user/userLogin?.*$";

	private static Pattern PATTERN = Pattern.compile(EXCLUDE);

	private boolean OFF = true;// true关闭jwt令牌验证功能

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
	}

	@Override
	public void destroy() {
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse resp = (HttpServletResponse) response;
		//获取当前请求路径。只有登录的请求路径不进行校验之外,其他的URL请求路径必须进行JWT令牌校验
		//http://localhost:8080/ssh2/bookAction_queryBookPager.action
		//req.getServletPath()==/bookAction_queryBookPager.action
		String path = req.getServletPath();
		if (OFF || isExcludeUrl(path)) {// 登陆直接放行
				chain.doFilter(request, response);
				return;
		}

		// 从客户端请求头中获得令牌并验证
		//token=头.载荷.签名
		String jwt = req.getHeader(JwtUtils.JWT_HEADER_KEY);
		Claims claims = this.validateJwtToken(jwt);
		//在这里请各位大哥大姐从JWT令牌中提取payload中的声明部分
		//从声明部分中获取私有声明
		//获取私有声明中的User对象 -> Modules
		Boolean flag=false;
		if (null == claims) {
			// resp.setCharacterEncoding("UTF-8");
			resp.sendError(403, "JWT令牌已过期或已失效");
			return;
		} else {
			
			//1.获取已经解析后的payload(私有声明)
			//2.从私有声明中当前用户所对应的权限集合List<String>或者List<Module>
			//3.循环权限(Module[id,url])
			// OK,放行请求 chain.doFilter(request, response);
			// NO,发送错误信息的JSON
			// ObjectMapper mapper=new ObjectMapper()
			// mapper.writeValue(response.getOutputStream(),json)
			
			String newJwt = JwtUtils.copyJwt(jwt, JwtUtils.JWT_WEB_TTL);
			resp.setHeader(JwtUtils.JWT_HEADER_KEY, newJwt);
			chain.doFilter(request, response);
		}
	}

	/**
	 * 验证jwt令牌,验证通过返回声明(包括公有和私有),返回null则表示验证失败
	 */
	private Claims validateJwtToken(String jwt) {
		Claims claims = null;
		try {
			if (null != jwt) {
				//该解析方法会验证:1)是否过期 2)签名是否成功
				claims = JwtUtils.parseJwt(jwt);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return claims;
	}

	/**
	 * 是否为排除的URL
	 * 
	 * @param path
	 * @return
	 */
	private boolean isExcludeUrl(String path) {
		Matcher matcher = PATTERN.matcher(path);
		return matcher.matches();
	}

	// public static void main(String[] args) {
	// String path = "/sys/userAction_doLogin.action?username=zs&password=123";
	// Matcher matcher = PATTERN.matcher(path);
	// boolean b = matcher.matches();
	// System.out.println(b);
	// }

}

web.xml中要配置corsfilter,允许jwt使用请求头及响应头

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         id="WebApp_ID" version="3.0">
  <display-name>Archetype Created Web Application</display-name>
 
  <!--1.实现Spring与Web集成,实现Spring上下文的初始化工作-->
  <!-- spring上下文配置文件 -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring.xml</param-value>
  </context-param>
  <!-- 读取Spring上下文的监听器 -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
 
  <!--2.配置中文乱码过滤器,使用Spring自带的过滤器-->
  <filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <async-supported>true</async-supported>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
 
  <!--CrosFilter跨域过滤器-->
  <filter>
    <filter-name>corsFilter</filter-name>
    <filter-class>com.zking.ssm.util.CorsFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>corsFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
 
  <!--JwtFilter-->
  <filter>
    <filter-name>jwtFilter</filter-name>
    <filter-class>com.zking.ssm.jwt.JwtFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>jwtFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
 
  <!--Spring MVC核心控制器-->
  <servlet>
    <servlet-name>SpringMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--此参数可以不配置,默认值为:/WEB-INF/springmvc-servlet.xml-->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    <!--web.xml 3.0的新特性,是否支持异步-->
    <async-supported>true</async-supported>
  </servlet>
  <servlet-mapping>
    <servlet-name>SpringMVC</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

前端代码:

state.js

export default {
  eduName: '米西米西花不垃圾',
  jwt: ''
}

mutations.js

export default {
  // type(事件类型): 其值为setEduName
  // payload:官方给它还取了一个高大上的名字:载荷,其实就是一个保存要传递参数的容器
  setEduName: (state, payload) => {
    state.eduName = payload.eduName;
  },
  setJwt: (state, payload) => {
    state.jwt = payload.jwt;
  }
}

getters.js

export default{
  getedName:(state)=>{
    return state.edName;
  },
  getJwt:(state)=>{
    return state.jwt;
  }
}

在spa项目中找到main.js文件 : 

/* eslint-disable no-new */
window.mm = new Vue({
  el: '#app',
  router,
  store,
  data() {
    return {
      bus: new Vue()
    }
  },
  components: {
    App
  },
  template: '<App/>'
})

在spa项目中找到http.js文件 ( src/api/http.js)进行编写请求拦截器 & 响应拦截器  :

// 请求拦截器
axios.interceptors.request.use(function(config) {
  let jwt = window.mm.$store.getters.getJwt;
  if(jwt){
    config.headers['jwt'] = jwt;
  }
  return config;
}, function(error) {
  return Promise.reject(error);
});
 
// 响应拦截器
axios.interceptors.response.use(function(response) {
  //将响应头中的jwt字符串放入state.js中
  let jwt = response.headers['jwt'];
  if (jwt) {
    window.mm.$store.commit('setJwt', {
      jwt: jwt
    });
  }
  return response;
}, function(error) {
  return Promise.reject(error);
});

效果展示:

                                             今日分享到此结束!!!  

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

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

相关文章

MS5611的ZYNQ驱动试验之二 控制器功能考虑

上一篇BLOG简单介绍了MS5611的基本情况。这里我们考虑一下如何在ZYNQ里面实现&#xff0c;也就是规划PS和PL如何分工实现。 一般这种有一定简单时序的外设控制器我们可以采用两个方式编写&#xff1a; 1&#xff0c;用PL构造时序&#xff0c;做成所谓的加速器。 2&#xff0…

鲜花植物配送商城小程序的作用是什么

鲜花植物的市场需求非常高&#xff0c;尤其节假日或装饰/采购等需求更大&#xff0c;除了线下经销商外&#xff0c;还有鲜花植物供应商批发等&#xff0c;但其市场高需求的同时&#xff0c;经营痛点也比较明显。 通过【雨科】平台搭建鲜花植物商城&#xff0c;实现全产品线上展…

pg 字符相关操作

1. 字符串连接 1.1使用concat_ws&#xff08;a&#xff0c;b&#xff0c;c&#xff09; 语义&#xff1a;按a分隔bc 2.使用||连接 2.字符编码转换 3.获取字符串长度 4.大小写转换 5.替换

CentOS 7系统安装配置Zabbix 5.0LTS 步骤

目录 一、查看Zabbix官方教程&#xff08;重点&#xff09; 二、安装 Docker 创建 Mysql 容器 安装 Docker 依赖包 添加 Docker 官方仓库 安装 Docker 引擎 启动 Docker 服务并设置开机自启 验证 Docker 是否成功安装 拉取 MySQL 镜像 查看本地镜像 运行容器 停止和启…

Linux进程概念(二)--进程状态进程优先级

继上回书Linux进程概念&#xff08;一&#xff09;&#xff0c;我们初步了解了进程的一些相关概念以及如何创建和查看进程&#xff0c;对其原理和一些进程现象进行了分析和解释&#xff0c;那么今天&#xff0c;我们学习下一个进程知识-进程概念。 目录 1.操作系统的进程状态 …

vue3 新特性(defineOptions defineModel)

Vue3.3 新特性-defineOptions 背景说明&#xff1a; 有 <script setup> 之前&#xff0c;如果要定义 props, emits 可以轻而易举地添加一个与 setup 平级的属性。 但是用了 <script setup> 后&#xff0c;就没法这么干了 setup 属性已经没有了&#xff0c;自然无法…

发布vue3组件到npm

目录 准备你的组件 创建项目 创建步骤 创建组件 封装我们要得组件 导出组件 打包 使用组件 发布包 创建npm账户 登录npm 切换npm源 发布到npm package.json package.json字段 确定版本号 版本号格式 版本号递增逻辑 vite 打包库模式 库模式配置 build配…

【数据结构】王道强化冲刺课

自用冲刺课复查 考点1 时间与空间复杂度 考点2 线性表 顺序表 链表 考点4567 栈和队列 矩阵 树 图 查找 排序

R实现动态条件相关模型与GARCH模型结合研究中美股市动态相关性(DCC-GARCH模型)

大家好&#xff0c;我是带我去滑雪&#xff01; 中美两国是全球最大的经济体&#xff0c;其经济活动对全球产业链和贸易体系都具有巨大影响。中美之间的经济互动包括大规模的贸易、投资和金融往来。这些互动不仅仅反映在经济数据上&#xff0c;还体现在股市上。中美股市的联动关…

使用任务定时执行软件的定时关机功能,控制电脑可用时间段

目录 定时关机功能可以设置有效的时间段 控制电脑可用时间段的意义 定时执行软件介绍 - 定时执行专家 定时关机设置方法 不可用时间段设置方法 注意事项 总结 在现代社会&#xff0c;电脑已经成为人们生活和工作中不可或缺的一部分。但是&#xff0c;长时间使用电脑也会对…

展会预告丨中国海洋装备博览会盛大开幕!箱讯科技亮相1T18展位

2023年10月12日-15日 中国海洋装备博览会暨2023世界航海装备大会 即将在福州海峡国际会展中心盛大开幕 箱讯科技携手上海虹口区工商联航运商会 亮相本次博览会 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 关于“中国海洋装备博览会” 中国海洋装…

DytanVO 代码复现(服务器端复现rtx3090)

源码地址 代码地址&#xff1a;https://github.com/castacks/DytanVO 环境配置 1.克隆github项目&#xff1a; git clone https://github.com/castacks/DytanVO.git2.利用yaml创建conda 环境&#xff1a; 修改yaml文件 name: dytanvo channels:- pytorch- conda-forge de…

PDM篇 | SOLIDWORKS 2024新功能

改进的视觉内容 优点 重要数据和系统信息一目了然。 • 通过装配体可视化功能&#xff0c;在 SOLIDWORKS 中以图形方式查看零部件数据&#xff0c;如工作流程状态。 • 使用特定图标迅速识别焊件切割清单零部件。 增强的数据保护和跟踪功能 优点 通过附加的审计跟踪信息&am…

Handler-ThreadLocal分析

ThreadLocal 源码分析 在 Android 的 Handler 机制下&#xff0c;ThreadLocal 提供了对不同线程本地变量的副本的保存&#xff0c;并且实现了线程数据的隔离&#xff0c;不同线程的数据不会产生错乱。且在一个线程结束后&#xff0c;其对应在 ThreadLocal 内的数据会被释放&am…

Win10 系统中用户环境变量和系统环境变量是什么作用和区别?

环境&#xff1a; Win10专业版 问题描述&#xff1a; Win10 系统中用户环境变量和系统环境变量是什么作用和区别&#xff1f; 解答&#xff1a; 在Windows 10系统中&#xff0c;用户环境变量和系统环境变量是两个不同的环境变量&#xff0c;它们具有不同的作用和区别 1.用…

数字化转型的环境中,MES管理系统的发展趋势如何

近年来&#xff0c;随着数字化技术的飞速发展&#xff0c;数字化转型以及成为企业发展的必然趋势。在这个过程中&#xff0c;制造业作为国民经济的重要支柱&#xff0c;也面临这前所未有的挑战和机遇。数字化转型下&#xff0c;制造业需要什么样的MES管理系统来应对这些挑战和机…

Domain_audit是一款基于渗透测试角度的域审计工具

关于Domain_audit 该工具是PowerView、Impacket、PowerUpSQL、BloodHound、Ldaprelayscan和Crackmapexec的包装器&#xff0c;用于自动执行枚举和在On-Prem Active Directory渗透测试期间执行的大量检查。 检查项目 Invoke-AD CheckAll将按顺序执行以下操作&#xff1a; 收…

竞赛选题 深度学习+python+opencv实现动物识别 - 图像识别

文章目录 0 前言1 课题背景2 实现效果3 卷积神经网络3.1卷积层3.2 池化层3.3 激活函数&#xff1a;3.4 全连接层3.5 使用tensorflow中keras模块实现卷积神经网络 4 inception_v3网络5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; *…

音视频开发岗位,2023年为何持续增加?如何应聘音视频岗位

随着基础设施的完善&#xff08;光纤入户、wifi覆盖、5G普及&#xff09;&#xff0c;加之2020年疫情的影响&#xff0c;将短视频、直播、视频会议、在线教育、在线医疗瞬间推到了顶峰&#xff0c;人们对音视频的需求和要求也越来越强烈。音视频开发是指利用计算机技术和相关编…

殡葬用品商城小程序的作用是什么

随着互联网电商发展&#xff0c;很多东西由线下被搬到了线上&#xff0c;尤其是围绕生活服务的行业更是线上布局经营增长&#xff0c;而随着消费升级&#xff0c;人们购买商品的方式也由以前单一的线上转为线上。 殡葬用品包括寿盒、寿衣、纸钱等产品虽然几乎每个家庭一辈子也…