JWT学习总结

文章目录

  • 前置知识
      • Authorization头部和 Cookie
      • CRSF攻击
  • JWT概念
  • JWT认证流程
  • 使用
      • Springboot整合JWT
      • JwtUtil
  • JWT案例
      • 控制器
      • JWT拦截器
      • 注册拦截器
      • 结果
  • session VS Jwt

前置知识

Authorization头部和 Cookie

Authorization 头部和 Cookie 是 HTTP 协议中两种不同的身份认证 / 信息传递机制.

  • Authorization 头部
    是 HTTP 协议中专门用于传递认证信息的请求头,通常格式为:

    Authorization: <认证方案> <凭证>
    

    常见的认证方案有 Bearer(用于 JWT、OAuth2.0 令牌)、Basic(基础认证)等。
    核心用途:向服务器证明客户端的身份(如 “我是已登录的用户 XXX”),仅在需要身份验证的请求中使用。

  • Cookie
    是服务器通过 Set-Cookie 响应头下发给客户端的小型数据片段,客户端(如浏览器)会在后续请求中自动附加到请求头中发送给服务器。
    核心用途:不仅用于身份认证(如 Session ID),还可存储其他状态信息(如用户偏好、购物车数据等),是客户端与服务器之间维护 “状态” 的主要方式。

  1. 自动性Cookie 由客户端自动携带,Authorization 需手动设置,这是两者最根本的区别,也导致了 CSRF 风险的差异。
  2. 安全性Cookie 有内置安全属性(HttpOnly 等),Authorization 依赖令牌本身和传输层安全(HTTPS)。
  3. 灵活性Authorization 更适合跨域、长令牌场景,Cookie 适合传统状态维护和轻量数据存储。

CRSF攻击

  1. 用户登录目标网站 A:用户在浏览器中登录网站 A(如银行网站),网站 A 验证通过后,会在用户的浏览器中生成并存储身份凭证(通常是 Cookie),用于后续请求的身份识别。
  2. 攻击者诱导用户访问恶意网站 B:用户在未退出网站 A 的情况下,被诱导点击了攻击者精心构造的恶意链接(如邮件、聊天消息中的链接),访问了攻击者控制的网站 B。
  3. 恶意网站 B 发送伪造请求:网站 B 的页面中包含一段代码(如 JavaScript),会自动向网站 A 的服务器发送一个请求(如转账请求)。由于用户的浏览器中仍保存着网站 A 的登录 Cookie,这个请求会自动携带该 Cookie,让网站 A 误以为是用户本人发起的操作。
  4. 网站 A 执行未授权操作:网站 A 验证请求中的 Cookie 有效,且未对请求的来源进行严格校验,从而执行了攻击者伪造的操作(如转账给攻击者的账户)。

CSRF 攻击的关键条件

  • 用户必须已登录目标网站(即浏览器中存在有效的身份凭证,如 Cookie)。
  • 攻击者必须诱导用户在登录状态下访问恶意网站
  • 目标网站未对请求的合法性进行严格校验(如未验证请求来源、未使用 CSRF Token 等防御机制)。****

JWT概念

  • 概念:

    Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

  • 构成:

    第一部分我们称它为头部(header),

    第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),

    第三部分是签证(signature).

  • header

    jwt的头部承载两部分信息:

    • 声明类型,这里是jwt
    • 声明加密的算法 通常直接使用 HMAC SHA256
  • playload

    载荷就是存放有效信息的地方。这些有效信息包含三个部分

    • 标准中注册的声明
    • 公共的声明
    • 私有的声明

    标准中注册的声明 (建议但不强制使用) :

    • iss: jwt签发者
    • sub: jwt所面向的用户
    • aud: 接收jwt的一方
    • exp: jwt的过期时间,这个过期时间必须要大于签发时间
    • nbf: 定义在什么时间之前,该jwt都是不可用的.
    • iat: jwt的签发时间
    • jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

    公共的声明 : 公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.

    私有的声明 : 私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。

  • signature

    jwt的第三部分是一个签证信息,这个签证信息由三部分组成:

    • header (base64后的)
    • payload (base64后的)
    • secret

    这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。

    如对称加密:

    # 伪代码
    signature = HMAC-SHA256(key=secret,message=header_encoded + "." + payload_encoded
    )
    
  • 注意事项

    将这三部分用.连接成一个完整的字符串,构成了最终的jwt

    注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,**在任何场景都不应该流露出去。**一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。

JWT认证流程

在这里插入图片描述

  1. 用户登录
    用户提交用户名和密码 → 服务器验证成功 → 服务器生成 JWT(包含用户信息和签名) → 返回 JWT 给客户端。
  2. 客户端存储
    客户端(如浏览器)将 JWT 存储在 localStorageCookie 等中。
  3. 后续请求
    客户端每次请求时,在请求头中携带 JWT(如 Authorization: Bearer <token>) → 服务器验证签名有效性 → 解析用户信息 → 处理请求并返回结果。

使用

Springboot整合JWT

  • JWT的引入:

    <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
    <dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
    </dependency>
    

在这里插入图片描述

  • 具体说明:

    • token是通过荷载Claims或playholder两者之一构造的,两者不能同时提供,否则compact()将报异常。

    • token构建是荷载一般必须两个属性:sub和exp

      • sub:即token中保存的必要信息。
      • exp:即token的过期时间,当token过了过期时间时,解析token时会抛出ExpiredJwtException异常。
    • 将token转换成Claims的方法是:Jwts类中的如下方法完成。

       public static JwtParser parser() {return new DefaultJwtParser();}
      

      具体实现如下:

      public Claims getClaimsByToken(String token) throws ExpiredJwtException{if(null == token)return null;return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();}
      
  • 解析token。

    • 解析过程:

      • 第一步:将token转换成Claims对象
      • 第二步:通过Claims对象的getSubject()方法获取token中保存的信息。
    • 将token转换成Claims的方法是:Jwts类中的如下方法完成。

       public static JwtParser parser() {return new DefaultJwtParser();}
      
    • 具体实现如下:

      public Claims getClaimsByToken(String token) throws ExpiredJwtException{if(null == token)return null;return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();}
      
    • 将token转换成Claims过程中将抛出如下异常

      • UnsupportedJwtException:当token不是通过Claims对象构建的token时。
      • ExpiredJwtException:当token已过期时。
      • MalformedJwtException:当token不是有效的Claims对象构建的token时。
      • SignatureException:当token的Signature验证失败时。
      • IllegalArgumentException:当token为null或token是空字符串或token中只有空字符时。
    • 通过Claims的方法获取token中保存的信息。

      • 具体实现如下:

        /*2.通过token获取构建时的信息*/public String getUserNameFromToken(String token) throws Exception{Claims claims = getClaimsByToken(token);return claims.getSubject();}
        

JwtUtil

/*** JwtToken生成的工具类* JWT token的格式:header.payload.signature* header的格式(算法、token的类型):* {"alg": "HS512","typ": "JWT"}* payload的格式(用户名、创建时间、生成时间):* {"sub":"wang","created":1489079981393,"exp":1489684781}* signature的生成算法:* HMACSHA512(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)* Created on 2018/4/26.*/
@Component
@Getter
public class JwtTokenUtil {private static final Logger LOGGER = LoggerFactory.getLogger(JwtTokenUtil.class);private static final String CLAIM_KEY_USERNAME = "user_name";private static final String CLAIM_KEY_CREATED = "created";@Value("${jwt.secret}")private String secret;@Value("${jwt.expiration}")private Long expiration;@Value("${jwt.tokenHead}")private String tokenHead;/*** 根据负责生成JWT的token*/private String generateToken(Map<String, Object> claims) {return Jwts.builder().setClaims(claims).setExpiration(generateExpirationDate()).signWith(SignatureAlgorithm.HS512, secret).compact();}/*** 从token中获取JWT中的负载*/private Claims getClaimsFromToken(String token) {Claims claims = null;try {claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();} catch (Exception e) {LOGGER.info("JWT格式验证失败:{}", token);}return claims;}/*** 生成token的过期时间*/private Date generateExpirationDate() {return new Date(System.currentTimeMillis() + expiration * 1000);}/*** 解密:从token中获取登录用户名(项目使用)*/public String getUserNameFromToken(String token) {String username;try {Claims claims = getClaimsFromToken(token);username = claims.get(CLAIM_KEY_USERNAME,String.class);} catch (Exception e) {username = null;}return username;}/*** 加密: 根据用户名生成token(项目使用)*/public  String generateUserNameStr(String username) {Map<String, Object> claims = new HashMap<>();claims.put(CLAIM_KEY_USERNAME,username);claims.put(CLAIM_KEY_CREATED, new Date());return generateToken(claims);}/*** 判断token是否已经失效*/private boolean isTokenExpired(String token) {Date expiredDate = getExpiredDateFromToken(token);return expiredDate.before(new Date());}/*** 从token中获取过期时间*/private Date getExpiredDateFromToken(String token) {Claims claims = getClaimsFromToken(token);return claims.getExpiration();}/*** 当原来的token没过期时是可以刷新的** @param oldToken 带tokenHead的token*/public String refreshHeadToken(String oldToken) {if(StrUtil.isEmpty(oldToken)){return null;}String token = oldToken.substring(tokenHead.length());if(StrUtil.isEmpty(token)){return null;}//token校验不通过Claims claims = getClaimsFromToken(token);if(claims==null){return null;}//如果token已经过期,不支持刷新if(isTokenExpired(token)){return null;}//如果token在30分钟之内刚刷新过,返回原tokenif(tokenRefreshJustBefore(token,30*60)){return token;}else{claims.put(CLAIM_KEY_CREATED, new Date());return generateToken(claims);}}/*** 判断token在指定时间内是否刚刚刷新过* @param token 原token* @param time 指定时间(秒)*/private boolean tokenRefreshJustBefore(String token, int time) {Claims claims = getClaimsFromToken(token);Date created = claims.get(CLAIM_KEY_CREATED, Date.class);Date refreshDate = new Date();//刷新时间在创建时间的指定时间内if(refreshDate.after(created)&&refreshDate.before(DateUtil.offsetSecond(created,time))){return true;}return false;}// 验证令牌有效性//没有使用 Spring Security,就不需要依赖其提供的 UserDetails 类,也无需遵循它的用户认证流程。// 此时验证 JWT 令牌并获取用户信息的思路会更简洁,核心是从 JWT 中解析出用户标识(如用户名、ID 等),// 再通过自己的业务逻辑验证用户合法性。public Boolean validateToken(String token) {// 解析令牌(自动验证签名和过期时间)Jwts.parser().setSigningKey(secret).parseClaimsJws(token);return true;}}

JWT案例

这里将在springboot中展示jwt,通过拦截器的方式。(只展示后端代码,可以使用postman测试,如果token是本地存储localStorage,会存到postman的相应地方,和浏览器一样)

大体流程如下:

  1. 第一次登录,传入用户名和密码
  2. 数据库检验用户名和密码是否正确,如果正确,根据用户信息(这里使用用户名)生成token。封装token和其他信息返回给前端。
  3. 前端拿到token,并且存到本地客户端(如localstorage)。以后每次发送请求都会在请求头中带上 Authorization: Bearer <token>
  4. 再次向服务端发送请求时就会经过Jwt的拦截器,拿到请求头中的token,解析token是否合法,如果合法即可证明用户身份并放行。

控制器

@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate JwtTokenUtil jwtTokenUtil;//简单登录接口@PostMapping("/login")public Result<LoginVO> login(@RequestBody LoginDTO loginDTO) {boolean auth = userService.authenticate(loginDTO);if (!auth){return Result.error(40101, "用户名或密码错误");}// 生成tokenString token = jwtTokenUtil.generateUserNameStr(loginDTO.getUsername());String authToken = "Bearer " + token;return Result.success(new LoginVO(loginDTO.getUsername(), authToken,jwtTokenUtil.getExpiration()*1000 + System.currentTimeMillis()));}//测试接口@GetMapping("/info")public Result<String> info() {return Result.success("info");}
}

JWT拦截器

public class JwtInceptor implements HandlerInterceptor {private final JwtTokenUtil jwtTokenUtil;public JwtInceptor(JwtTokenUtil jwtTokenUtil) {this.jwtTokenUtil = jwtTokenUtil;}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//获取请求头中令牌String token = request.getHeader("Authorization");if(token != null && token.startsWith("Bearer ")){token = token.substring(7);//验证令牌if(jwtTokenUtil.validateToken(token)){//验证通过,放行,提取用户信息病传递到后续处理String username = jwtTokenUtil.getUserNameFromToken(token);request.setAttribute("username",username);return true;}}//验证失败,返回401response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid JWT");return false;}
}

注册拦截器

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Autowiredprivate JwtTokenUtil jwtTokenUtil;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(jwtInceptor()).addPathPatterns("/**").excludePathPatterns("/user/login");}@Beanpublic JwtInceptor jwtInceptor() {return new JwtInceptor(jwtTokenUtil);}
}

结果

登录:http://localhost:8080/user/login

{"code": 200,"msg": "操作成功","data": {"username": "saber","token": "Bearer eyJhbGciOiJIUzUxMiJ9.eyJ1c2VyX25hbWUiOiJzYWJlciIsImNyZWF0ZWQiOjE3NTEyNzE4NjY5NTEsImV4cCI6MTc1MTM1ODI2Nn0.TF2_XwhON3H-Jn_fdG5xacATxu_4lvJqY19C1JUCKkQjWYeW2vRdh5lwlgoCjw-nqTEPbJyRrC7Hg3TBOyuCjw","expireTime": 1751358267094}
}

测试:http://localhost:8080/user/info

{"code": 200,"msg": "操作成功","data": "info"
}

session VS Jwt

  1. 服务器存储压力大,扩展性差,有性能开销:认证信息(用户ID,权限等)存储在服务器端(通常是内存中),客户端通过session ID与服务器端关联

    • 当用户量激增时,服务器需要存储大量的session,会占用大量的内存/存储资源
    • 在分布式系统中(如多台服务器负载均衡),需要保证session在多台服务器间同步,复杂度高,维护成本大
    • 根据 Session ID 在内存中查找对应的 Session 对象,有性能开销,如果存储在redis或数据库,性能开销较高。
    • 如果存储在内存中,重启系统后用户需要重新登录,影响用户体验。
  2. 依赖cookie,存在安全风险:通常依赖 Cookie 传递 Session ID,而 Cookie 存在以下风险:

    • CSRF(跨站请求伪造):攻击者可能利用用户的 Cookie 在其他网站发起恶意请求(如转账),因为 Session ID 会随 Cookie 自动发送。

    • Cookie 劫持:如果 Session ID 通过 HTTP 明文传输,可能被窃听;即使使用 HTTPS,也可能通过 XSS 攻击获取 Cookie 中的 Session ID,进而伪造身份。

    • JWT 对比
      可通过 HTTP Header(如Authorization: Bearer <token>)传递,不依赖 Cookie,从根源上避免了 CSRF 风险。

      即使 Token 被存储在 LocalStorage,虽仍可能面临 XSS 攻击,但可通过设置 Token 有效期较短、配合 HTTPS 等方式降低风险,且 JWT 的签名机制能防止 Token 被篡改。

  3. 难以实现跨域认证

    • 传统 Session
      由于 Cookie 的同源策略限制,跨域请求(如前后端分离架构中,前端域名与后端 API 域名不同)时,Session ID 可能无法正常传递(需额外配置CORS和 Cookie 跨域属性),实现复杂且兼容性差。
    • JWT 对比
      基于 Header 传递的 JWT 不受同源策略限制,可轻松支持跨域认证(如不同域名的前端应用调用同一后端 API),只需在请求头中携带 Token 即可,更适合前后端分离、微服务等分布式架构。
  4. Token 有效期管理灵活度低

    • Session

      Session 的有效期通常在服务器端设置(如 30 分钟),若需提前失效 (如用户登出、密码修改、账号异常),需在服务器端主动删除对应的 Session 数据。服务端可控性强。

    • JWT

      无法修改已生成的token,其exp无法更新,但可以通过token的刷新机制,但短期 Token(如 15 分钟)配合刷新 Token(Refresh Token)的机制,可兼顾安全性和用户体验,且无需服务器存储全量认证数据。

场景JWT传统 Session
分布式 / 微服务架构✅ 无状态,无需共享 Session❌ 需要 Session 共享机制
跨域认证✅ 支持跨域(Header 传递)❌ 依赖 Cookie,需额外配置
移动端应用✅ 轻量,易于客户端管理❌ 依赖 Cookie,移动端支持差
高并发场景✅ 验证快(本地计算),无需 IO❌ 频繁查询存储,性能瓶颈
安全性要求极高❌ Token 一旦泄露风险大✅ 服务端可控(如强制登出)

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

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

相关文章

阿里云消息队列 Apache RocketMQ 创新论文入选顶会 ACM FSE 2025

近日&#xff0c;由阿里云消息团队发表的 Apache RocketMQ 创新论文被 CCF-A 类软件工程顶级会议 FSE 2025 Industry Track 录用。 ACM FSE&#xff08;The ACM International Conference on the Foundations of Software Engineering&#xff09;是享有盛誉的国际学术会议&…

定制WordPress管理后台

WordPress作为全球最流行的建站工具&#xff0c;因其灵活性和易用性受到广泛欢迎。许多服务器提供商都支持一键安装WordPress&#xff0c;例如Hostease&#xff0c;使新手用户也能轻松搭建属于自己的网站。然而&#xff0c;后台的默认设置可能无法完全满足不同用户的需求。定制…

REST API设计与Swagger:构建高效、易用的Web服务

引言 在现代Web开发中&#xff0c;REST API已成为不同系统间通信的标准方式。一个设计良好的REST API不仅能提高开发效率&#xff0c;还能改善用户体验。而Swagger&#xff08;现称为OpenAPI&#xff09;作为API文档和测试的强大工具&#xff0c;已经成为API开发中不可或缺的一…

一个非对齐访问的问题

1、引言 最近在编写代码时&#xff0c;出现了这样一个 bug。程序一跑&#xff0c;系统就崩溃了&#xff0c;报错是 bus error。 目标平台&#xff1a;ARM32 最终定位到出错的代码片段&#xff1a; *((uint32_t *)ptr) id;这里的 ptr 是一个非 4 字节对齐的地址&#xff01;&a…

【构造】P8976 「DTOI-4」排列|普及+

本文涉及知识点 构造 P8976 「DTOI-4」排列 题目背景 Update on 2023.2.1&#xff1a;新增一组针对 yuanjiabao 的 Hack 数据&#xff0c;放置于 #21。 Update on 2023.2.2&#xff1a;新增一组针对 CourtesyWei 和 bizhidaojiaosha 的 Hack 数据&#xff0c;放置于 #22。…

多路I/O转接服务器(select、poll、epoll)

多路IO转接服务器也叫做多任务IO服务器。该类服务器实现的主旨思想是&#xff0c;不再由应用程序自己监视客户端连接&#xff0c;取而代之由内核替应用程序监视文件。 IO 多路转接方式比较&#xff1a; 常见的 IO 多路转接方式有&#xff1a;select、poll、epoll&#xff0c;他…

最新临时文件快传系统源码 轻量化 带后台

简介&#xff1a; 最新临时文件快传系统源码 轻量化 带后台 首发 轻松上传文件并生成提取码分享给他人&#xff0c;无需注册&#xff0c;方便快捷。 图片&#xff1a;

MyBatis多数据源动态连接工具类实现

这个DatabaseService工具类提供了动态创建MyBatis SqlSession的能力&#xff0c;可以灵活地连接到不同的数据库&#xff0c;非常适合需要动态切换数据源的场景。 package com.cmes.immp.device.utils;import lombok.SneakyThrows; import org.apache.commons.dbcp2.BasicDataS…

用亮数据 MCP 驱动 Trae 智能体:打造高效亚马逊商品采集与分析助手

本文适合希望快速构建数据驱动型智能体的开发者、数据工程师及 AI 产品设计者阅读 并非广告&#xff0c;希望本文可以帮助有需求的同学&#xff0c;祝大家天天开心 在数字时代&#xff0c;数据是决策与洞察趋势的关键。但移动互联网数据获取不易&#xff0c;传统爬虫技术面对复…

如何降低AIGC生成内容的重复率?五种免费降AI率的方法 (25年更新)

随着AI生成内容&#xff08;AIGC&#xff09;的普及&#xff0c;越来越多的学术写作依赖AI工具来生成论文和文章。然而&#xff0c;AI生成内容的查重率常常偏高&#xff0c;导致很多论文无法通过学术查重系统。为了解决这一问题&#xff0c;以下是五种有效的免费降AIGC率的方法…

小米YU7使用UWB技术,厘米级定位精准迎宾,安全防破解无感控车

当您双手抱着快递走向爱车时&#xff0c;车门自动解锁&#xff1b;当您站在前备箱前稍作停留&#xff0c;箱盖优雅升起——这不是科幻电影&#xff0c;而是小米YU7搭载UWB技术带来的真实体验。在2025年5月的小米15周年战略新品发布会上&#xff0c;雷军揭晓了这项革命性技术&am…

WPF学习(动画)

文章目录 一、图像变换 RenderTransform1、常见变换类型2、RenderTransform 的核心作用3、RenderTransform 的使用方式4、与 LayoutTransform 的对比5、在动画中的应用 二、 滚动的椭圆三、Storyboard放置位置1. **元素的 Resources 集合**2. **控件模板&#xff08;ControlTem…

Crossbar结构的排队策略

目录 一、概述 二、排队策略 三、输入排队结构(IQ) 3.1 结构特点 3.2 改进方案 四、输出排队结构&#xff08;OQ&#xff09; 五、输入输出联合排队结构(CIOQ) 六、输入交叉节点联合排队结构(CICQ) 一、概述 Crossbar是一种全连接的交换结构&#xff0c;由 MN 个交叉…

状态模式 - Flutter中的状态变身术,让对象随“状态“自由切换行为!

订单状态流转/播放器控制/游戏角色行为…一个模式搞定所有状态驱动型逻辑&#xff01; 经典场景&#xff1a;订单状态管理 假设你在开发一个外卖App&#xff0c;订单有以下状态&#xff1a; 等待接单已接单配送中已完成已取消 每个状态下&#xff1a; 显示的UI不同可执行的…

数据库9:数据库字符编码调整与校队(排序)规则

一.常用字符编码 1.ASCII编码 用一个字节表示一个字符 2.ANSI编码 每个国家为了显示本国的语言而对ASCII码进行了拓展 用两个字节表示一个汉字&#xff0c;中国的ANSI编码是GB2312编码&#xff08;简体&#xff09;&#xff0c;日本的ANSI编码是JIS编码&#xff0c;台湾的A…

人脸活体识别4:Android实现人脸眨眼 张嘴 点头 摇头识别(可实时检测)

人脸活体识别4&#xff1a;Android实现人脸眨眼 张嘴 点头 摇头识别(可实时检测) 目录 人脸活体识别4&#xff1a;Android实现人脸眨眼 张嘴 点头 摇头识别(可实时检测) 1. 前言 2.人脸活体识别方法 &#xff08;1&#xff09;基于人脸动作的检测​​ &#xff08;2&…

DAY1-Linux操作系统1

文章参考【黑马程序员Python教程_600集Python从入门到精通教程&#xff08;懂中文就能学会&#xff09;】 https://www.bilibili.com/video/BV1ex411x7Em/?p40&share_sourcecopy_web&vd_source263bbee2ddeb835c3ab6d9d3c80e0f7c 一.常用命令简单介绍 使用软件 虚拟机…

第十二节:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入门 - 两种权限控制方式(附前后端代码)

Vben5 系列文章目录 💻 基础篇 ✅ 第一节:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入门 ✅ 第二节:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入门 - Python Flask 后端开发详解(附源码) ✅ 第三节:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入…

华为云Flexus+DeepSeek征文 | 华为云 ModelArts Studio 赋能 AI 法务:合同审查与法律文件生成系统

一、引言 在法律行业数字化转型的浪潮中&#xff0c;AI 技术正重塑法律服务的流程与效率。本文介绍如何利用华为云 ModelArts Studio 构建一套完整的 AI 法务系统&#xff0c;实现合同审查、法律文件生成、法律咨询与风险识别的智能化解决方案。 二、系统架构设计 &#xff0…

SQL的底层逻辑解析

SQL的底层逻辑涉及数据库管理系统(DBMS)如何解析、优化和执行SQL查询&#xff0c;主要包括以下几个层面&#xff1a; ​查询处理流程​ 解析器(Parser)&#xff1a;将SQL语句转换为语法树查询优化器(Optimizer)&#xff1a;基于统计信息和成本模型生成最优执行计划执行引擎(Exe…