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

jwt认证课件讲解

JWT

基本概念

在用户登录后,我们需要在不同请求之间记录用户的登录状态,常用方式一般有三种:Cookie,Session和Token。

这里我们使用第三种Token令牌方式来实现认证鉴权,采用Json Web Token认证机制(简称:jwt)。

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

jwt官网:https://jwt.io/

jwt规范:https://datatracker.ietf.org/doc/html/draft-ietf-oauth-json-web-token

JWT的构成

在这里插入图片描述

JWT就一段由三段信息构成的字符串,将这三段信息文本用.拼接一起就构成的。就像这样:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).

jwtToken = f"{header}.{payload}.{signature}"
header

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

  • typ: type的缩写,声明token的类型,值一般可以是 JWT Bear
  • alg: algorithm的缩写,声明token的第三方部分(签证)的加密算法,通常直接使用 HMAC SHA256

完整的头部就像下面这样的JSON:

{"typ": "Bear","alg": "HS256"
}

然后将头部进行base64.b64urlencode()编码,构成了第一部分头部。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

python代码实现过程:

import base64,json
data = {'typ': 'JWT','alg': 'HS256'
}header = base64.b64encode(json.dumps(data).encode()).decode()# 各个语言中都有base64加密解密的功能,所以我们jwt为了安全,需要配合第三段加密
payload

载荷(payload)就是jwt存放有效信息的部分。这个名字像是特指飞机上承载的货仓,这些有效信息包含三种不同类型的数据:

  • 标准声明
  • 公共声明
  • 私有声明

标准声明 (官方提出建议但不强制使用) :

  • iss: jwt签发者

  • sub: jwt所面向的用户

  • aud: 接收jwt的一方

  • exp: jwt的过期时间,这个过期时间必须要大于签发时间

  • nbf: 定义在什么时间之后,该jwt可以正常使用。

  • iat: jwt的签发时间

  • jti: jwt的唯一身份标识,主要用来作为一次性token,往往采用UUID字符串或随机字符串来充当。

    以上是JWT规范中提供的7个官方字段,开发者根据自己的业务进行选用。

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

私有声明:私有声明是服务端和客户端所共同定义的声明,一般使用类似ace算法进行非对称加密和解密的,意味着该部分信息可以归类为明文信息。

定义一个payload,json格式的数据:

{"sub": "1234567890",  // 时间戳"exp": "3422335555",  // 时间戳"name": "John Doe","admin": true,
}

然后将其进行base64.b64encode() 编码,得到JWT的第二部分。

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

python代码实现过程:

import base64,json
data = {"sub": "1234567890","exp": "3422335555","name": "John Doe","admin": True,"info": "232323ssdgerere3335dssss"
}payload = base64.b64encode(json.dumps(data).encode()).decode()# 各个语言中都有base64编码和解码,所以我们jwt为了安全,需要配合第三段签证来进行加密保证jwt不会被人篡改。
signature

JWT的第三部分叫签证信息,主要用于辨真伪,防篡改。签证信息使用加密算法生成,公式:

secret_key = "秘钥" # 只保存服务端,不能外泄
signature = SHA256(base64.b64encode(header) + "." +base64.b64encode(payload),secret_key) 

python代码实现过程:

import sys, json, base64, time, hmacif __name__ == '__main__':# 头部data = {'typ': 'JWT', 'alg': 'HS256'}header = base64.b64encode(json.dumps(data).encode()).decode()# 载荷data = {"sub": "1234567890", "exp": "3422335555", "name": "John Doe", "admin": True,"info": "232323ssdgerere3335dssss"}payload = base64.b64encode(json.dumps(data).encode()).decode()# 签证,生成jwt token 提供给客户端# from django.conf import settings# secret = settings.SECRET_KEYsecret = 'django-insecure-(_+qtd5edmhm%2rdsg+qc3wi@s_k*3cbk-+k2gpg3@qx)z6r+p'sign = base64.b64encode(f"{header}.{payload}".encode())signature = base64.b64encode(hmac.digest(secret.encode(), sign, digest="sha256")).decode()jwt = f"f{header}.{payload}.{signature}"print(jwt)# 将这三部分用`.`连接成一个完整的字符串,构成了最终的jwt:# feyJ0eXAiOiAiSldUIiwgImFsZyI6ICJIUzI1NiJ9.eyJzdWIiOiAiMTIzNDU2Nzg5MCIsICJleHAiOiAiMzQyMjMzNTU1NSIsICJuYW1lIjogIkpvaG4gRG9lIiwgImFkbWluIjogdHJ1ZSwgImluZm8iOiAiMjMyMzIzc3NkZ2VyZXJlMzMzNWRzc3NzIn0=.3OnGXAx5wWA5AjxyewICSn5Hirz1tXfzxOc4tns4elM=

注意:

secret是保存在服务器端的,jwt的签发生成代码也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,

所以它应该是服务端的私钥,在任何场景下都不应该流露出去,而且应该在每次服务端更新维护后及时更新。

一旦第三方得知这个secret, 那就意味着他们绕过服务端伪造jwt了。

优缺点

优点:

  1. 实现分布式集群的单点登陆非常方便
  2. Token实际保存在客户端,所以我们可以分担服务端的存储压力。
  3. jwt不仅可用于认证,还可用于信息交换。善用JWT有助于减少服务器请求数据库的次数,jwt的构成非常简单,字节占用很小,所以它是非常便于传输的。

缺点:

  1. jwt保存在客户端,我们服务端只认jwt,不识别客户端。
    • 解决方案1. 设置客户端唯一登陆
    • 解决方案2. 绑定客户端的标记符和IP,机器码
  2. jwt可以设置过期时间,但是因为jwt保存在了客户端,所以对于过期时间不好调整,一旦签发不可控。
    • 解决方案1:设置短有效期,例如:30分、15分钟、10分钟之类。
    • 解决方案2:生成jwt的时候,提供给客户端之前先在内存(一般使用内存数据库redis,而不是变量)备份jwt,每次用户访问需要登录身份数据时,把token去内存中验证一样。
使用jwt实现认证流程

所谓的认证流程,实际上就是用户登录的过程。

在这里插入图片描述

python代码实现认证流程,代码:

import sys, json, base64, time, hmacif __name__ == '__main__':# 模拟客户端提交的tokenclient_token = "feyJ0eXAiOiAiSldUIiwgImFsZyI6ICJIUzI1NiJ9.eyJzdWIiOiAiMTIzNDU2Nzg5MCIsICJleHAiOiAiMzQyMjMzNTU1NSIsICJuYW1lIjogIkpvaG4gRG9lIiwgImFkbWluIjogdHJ1ZSwgImluZm8iOiAiMjMyMzIzc3NkZ2VyZXJlMzMzNWRzc3NzIn0=.3OnGXAx5wWA5AjxyewICSn5Hirz1tXfzxOc4tns4elM="# 把客户端提交的token分割成三段:头部、载荷、签证header, payload, signature = client_token.split(".")# 验证是否过期了,先基于base64,接着使用json解码,提供载荷中的过期时间进行比较payload_data = json.loads(base64.b64decode(payload.encode()))exp = int(payload_data.get("exp", 0))now = int(time.time())if exp < now:print("token已经过期!")sys.exit()  # 退出程序,实际开发中,应该时响应代码给客户端,不会继续往下执行了。secret = "django-insecure-(_+qtd5edmhm%2rdsg+qc3wi@s_k*3cbk-+k2gpg3@qx)z6r+p"# 与生成token时一样的秘钥和数据,再次生成一个签证new_signature = hmac.digest(secret.encode(), sign, digest="sha256")# 拿客户端提交上面的token中的签证进行base64解码得到原始的签证signature = base64.b64decode(signature)# 通过compare_digest比较两者是否吻合if hmac.compare_digest(signature, new_signature):print("认证通过")else:print("认证失败,token被串改!")
基本使用

开发中除非找不到,否则我们可以直接使用第三方已经开源的模块来完成相关的功能。大部分要求使用第三方模块是必须star数量>150。

依赖库安装
# python-jose 用于生成和检验JWT令牌
pip install jwt
pip install python-jose
JWT基本使用

生成一个随机的密钥,用于对JWT令牌进行签名加密的。终端执行命令如下:

openssl rand -hex 32
# eac77e4e9a9a767b792779132e84ea37b1f4c31bec56714607f617a3fbdfbd53

创建JWT需要的相关配置项,settings.py,代码:

# 加密数据所使用的秘钥[盐值]
SECRET_KEY = "eac77e4e9a9a767b792779132e84ea37b1f4c31bec56714607f617a3fbdfbd53"
# 设定JWT令牌签名算法
ALGORITHM = "HS256"
# 设置令牌过期时间变量(单位:秒)
ACCESS_TOKEN_EXPIRE_MINUTES = 30 * 60

创建JWT工具类,utils.py,代码:

from typing import Optional
from datetime import timedelta, datetime
import settings
from jose import jwt
import uuidclass JWT(object):JWTError = jwt.JWTErrorExpiredSignatureError = jwt.ExpiredSignatureErrordef create_token(self, data: dict, expire_time: Optional[timedelta] = None):"""生成Token:param data: 需要进行JWT令牌加密的用户信息(解密的时候会用到):param expire_time: 令牌有效期,单位:秒:return: token"""now_time = datetime.utcnow()if expire_time:expire = now_time + timedelta(seconds=expire_time)else:expire = now_time + timedelta(seconds=settings.ACCESS_TOKEN_EXPIRE_TIME)payload = {"exp": expire,"iat": now_time,"nbf": now_time,"jti": str(uuid.uuid4())}payload.update(data)token = jwt.encode(payload, settings.SECRET_KEY, algorithm=settings.ALGORITHM)return tokendef verify_token(self, token: str) -> dict:"""验证token:param token: 客户端发送过来的token:return: 返回用户信息"""payload = jwt.decode(token, settings.SECRET_KEY, algorithms=settings.ALGORITHM)return payloadif __name__ == '__main__':"""密码加密与验证"""# hashing = Hashing()# hashed_pwd = hashing.hash("123456")# print(hashed_pwd) # 加密后要保存到数据库中的哈希串# # 把原密码和加密后的哈希串进行配对,验证通过则返回结果为True# ret = hashing.verify("123456", hashed_pwd)# print(ret)"""JWT"""jwt_tool = JWT()try:# 正确使用token = jwt_tool.create_token({'username': 'admin', 'sex': True})print(token)data = jwt_tool.verify_token(token)print(data)# # 因为Token过期导致验证失败# token = jwt_tool.create_token({'username': 'admin', 'sex': True}, -300)# print(token)# data = jwt_tool.verify_token(token)# print(data)# # 因为Token被串改导致验证失败# token = jwt_tool.create_token({'username': 'admin', 'sex': True})# print(token)# data = jwt_tool.verify_token(token[:-1])# print(data)except (jwt_tool.ExpiredSignatureError, jwt_tool.JWTError) as e:print("验证失败,", e)

基于自定义中间件创建JWT中间件实现用户身份认证

async def jwt_middleware(request: Request, call_next):try:token: str = request.headers["Authorization"].split()[1]payload = jwt_took.verify(token)id: str = payload.get("id")# 查询数据库,是否存在当前用户user = await models.User.filter(id=id).first(id)if user is None:raise HTTPException(status_code=HTTP_401_UNAUTHORIZED, detail="Invalid authentication credentials")request.user = userexcept (jwt_tool.ExpiredSignatureError, jwt_tool.JWTError):raise HTTPException(status_code=HTTP_401_UNAUTHORIZED, detail="Invalid authentication credentials")response = await call_next(request)return response

注册JWT中间件,代码:

app.add_middleware(jwt_middleware)

相关文章:

jwt认证课件讲解

JWT 基本概念 在用户登录后&#xff0c;我们需要在不同请求之间记录用户的登录状态&#xff0c;常用方式一般有三种&#xff1a;Cookie&#xff0c;Session和Token。 这里我们使用第三种Token令牌方式来实现认证鉴权&#xff0c;采用Json Web Token认证机制&#xff08;简称…...

【判断推理】逻辑基础

1.1 命题 用语言、符号或者式子表达的&#xff0c;可以判断真假的陈述句称为命题&#xff0c;一般写为 若p&#xff0c;则q 真命题&#xff1a;判断为真的语句假命题&#xff1a;判断为假的语句 eg1&#xff1a;小张是中国人&#xff08;若是小张&#xff0c;则是中国人&#…...

AcWing 655:天数转换 ← 整除、求余

【题目来源】https://www.acwing.com/problem/content/657/【题目描述】 读取对应于一个人的年龄&#xff08;以天为单位&#xff09;的整数值&#xff0c;并转化为年&#xff0c;月和日表示方式输出&#xff0c;年、月、日分别对应 ano(s), mes(es), dia(s)。 注意&#xff1a…...

【解决办法】git clone报错unable to access ‘xxx‘: SSL certificate problem:

使用git clone 时报错unable to access xxx: SSL certificate problem: 这个报错通常是由于SSL证书问题引起的。通常可以按照以下步骤进行排查&#xff1a; 检查网络连接&#xff1a;确保你的网络连接正常&#xff0c;可以访问互联网。尝试使用其他网站或工具测试网络连接是否正…...

算法笔记(十三)——BFS 解决最短路问题

文章目录 迷宫中离入口最近的出口最小基因变化单词接龙为高尔夫比赛砍树 BFS 解决最短路问题 BFS(广度优先搜索) 是解决最短路径问题的一种常见算法。在这种情况下&#xff0c;我们通常使用BFS来查找从一个起始点到目标点的最短路径。 迷宫中离入口最近的出口 题目&#xff1a;…...

Android 简单实现联系人列表+字母索引联动效果

效果如上图。 Main Ideas 左右两个列表左列表展示人员数据&#xff0c;含有姓氏首字母的 header item右列表是一个全由姓氏首字母组成的索引列表&#xff0c;点击某个item&#xff0c;展示一个气泡组件(它会自动延时关闭)&#xff0c; 左列表滚动并显示与点击的索引列表item …...

自动驾驶-问题笔记-待解决

参考线的平滑方法 参考线平滑算法主要有三种&#xff1a; 离散点平滑&#xff1b;螺旋曲线平滑&#xff1b;多项式平滑&#xff1b; 参考链接&#xff1a;参考线平滑 对于平滑方法&#xff0c;一直不太理解平滑、拟合以及滤波三者的作用与区别&#xff1b; 规划的起点&#x…...

在掌控板中加载人教版信息科技教学指南中的educore库

掌控板中加载educore库 人教信息科技数字资源平台&#xff08;https://ebook.mypep.cn/free&#xff09;中的《信息科技教学指南硬件编程代码说明》文件中提到“本程序说明主要供教学参考。需要可编程主控板须支持运行MicroPython 脚本程序。希望有更多的主控板在固件中支持ed…...

关于CSS Grid布局

关于CSS Grid布局 实际效果参考 参考代码 <template><view class"baseInfo"><up-image class"cover" height"160rpx" width"120rpx" :src"bookInfo.cover"><template #error><view style"…...

初始爬虫12(反爬与反反爬)

学到这里&#xff0c;已经可以开始实战项目了&#xff0c;多去爬虫&#xff0c;了解熟悉反爬&#xff0c;然后自己总结出一套方法怎么做。 1.服务器反爬的原因 服务器反爬的原因 总结&#xff1a; 1.爬虫占总PV较高&#xff0c;浪费资源 2.资源被批量抓走&#xff0c;丧失竞争力…...

成像基础 -- 最大对焦清晰的物距计算

最大对焦清晰的物距计算 1. 基本概念 最大对焦清晰的物距通常与景深&#xff08;Depth of Field, DOF&#xff09;相关&#xff0c;尤其是无穷远处的物体可以被清晰对焦到的距离&#xff0c;称为超焦距&#xff08;Hyperfocal Distance&#xff09;。通过计算超焦距&#xff…...

win10服务器启动且未登录时自动启动程序

场景&#xff1a;公司服务器安装了几个程序&#xff0c;当服务器断电重启之后希望程序能自动打开&#xff0c;而不需要手动登录服务器打开。 因为软件是自己开发的所以安全方面这里没有考虑。 1.打开服务器管理器&#xff0c;点击工具&#xff0c;选择任务计划程序 2.在任务计…...

算法专题四: 前缀和

目录 1. 前缀和2. 二维前缀和3. 寻找数组的中心下标4. 除自身以外数组的乘积5. 和为k的子数组6. 和可被K整除的子数组7. 连续数组8. 矩阵区域和 博客主页:酷酷学!!! 感谢关注~ 1. 前缀和 算法思路: 根据题意, 创建一个前缀和数组, dp[i] dp[i -1] arr[i], 再使用前缀和数组,…...

【Linux】基础IO(文件描述符、缓冲区、重定向)

&#x1f308;个人主页&#xff1a;秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343&#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/qinjh_/category_12625432.html 目录 前言 C文件IO相关操作 系统文件I/O open open函数返回值 文件描述符fd re…...

一篇文章快速学会docker容器技术

目录 一、Docker简介及部署方法 1.1Docker简介 1.1.1什么是docker 1.1.2 docker在企业中的应用场景 1.1.3 docker与虚拟化的对比 1.1.4 docker的优势 二 、部署docker 2.1 容器工作方法 2.2 部署第一个容器 2.2.1 配置软件仓库 2.2.2 安装docker-ce并启动服务 2.2.…...

【MySQL】使用 JDBC 连接数据库

文章目录 前言1. 认识 JDBC1.1 概念1.2 好处 2. 使用 JDBC2.1 安装数据驱动包2.2 把 jar 包导入到项目中2.3 代码编写2.4 测试结果 3. 代码优化4. 源码展示结语 前言 在 MySQL 系列中&#xff0c;我们介绍了很多内容&#xff0c;包括但不限于建库建表&#xff0c;增删查改等等…...

数据结构与算法笔记:概念与leetcode练习题

1、数组Array 时间复杂度 数组访问&#xff1a;O(1) 数组搜索&#xff1a;O(N) 数组插入&#xff1a;O(N) 数组删除&#xff1a;O(N) 特点 适合读&#xff0c;不适合写 数组常用操作 # 1、创建数组 a [] # 2、尾部添加元素 a.append(1) a.append(2) a.append(3) # 3、…...

十大时间序列预测模型

目录 1. 自回归模型 原理 核心公式 推导过程: 完整案例 2. 移动平均模型 原理 核心公式 推导过程: 完整案例 3. 自回归移动平均模型 原理 核心公式 推导过程: 完整案例 4. 自回归积分移动平均模型 原理 核心公式 推导过程 完整案例 5. 季节性自回归积分…...

G2O 通过工厂函数类 OptimizationAlgorithmFactory 来生成固定搭配的优化算法

OptimizationAlgorithmFactory 类位于 optimization_algorithm_factory.h //***g2o源码 g2o/g2o/core/optimization_algorithm_factory.h ***// /*** \brief create solvers based on their short name** Factory to allocate solvers based on their short name.* The Factor…...

手机USB连接不显示内部设备,设备管理器显示“MTP”感叹号,解决方案

进入小米驱动下载界面&#xff0c;等小米驱动下载完成后&#xff0c;解压此驱动文件压缩包。 5、小米USB驱动安装方法&#xff1a;右击“计算机”&#xff0c;从弹出的右键菜单中选择“管理”项进入。 6、在打开的“计算机管理”界面中&#xff0c;展开“设备管理器”项&…...

如何在Windows上高效使用酷安社区:UWP桌面客户端完全指南

如何在Windows上高效使用酷安社区&#xff1a;UWP桌面客户端完全指南 【免费下载链接】Coolapk-UWP 一个基于 UWP 平台的第三方酷安客户端 项目地址: https://gitcode.com/gh_mirrors/co/Coolapk-UWP 你是否经常在手机小屏幕上刷酷安&#xff0c;眼睛酸痛却停不下来&…...

Svelte动态光标实现:状态驱动与Spring动画的交互设计

1. 项目概述&#xff1a;一个会“思考”的鼠标指针如果你在开发一个需要高度沉浸感和交互反馈的Web应用&#xff0c;比如一个设计工具、一个游戏界面&#xff0c;或者一个希望用户能“感受”到页面元素质感的网站&#xff0c;那么一个静态的、系统默认的鼠标指针就显得有些格格…...

到底如何?大跨度“玻璃肋”幕墙,安全吗?

到底如何?大跨度“玻璃肋”幕墙,安全吗? 1 概述 自玻璃诞生之日起,这种无色透明的物质便与建筑结下了不解之缘。随着“苹果店”的火热,通透、纯净的全玻结构系统使玻璃的材料特性发挥到了极致。当我们乐见于越来越大的玻璃幅面、越来越高的幕墙跨度时,全玻结构所具有的…...

为什么你的Midjourney胶片图总像数码后期?——从光子散射模型到显影时间算法的底层差异解析

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;胶片质感的视觉直觉与认知偏差 胶片质感并非单纯的技术残留&#xff0c;而是一种经由人类视觉系统长期训练形成的感知锚点——它将颗粒噪点、色偏渐变、边缘晕影等非理想光学特征&#xff0c;编码为“真…...

Sunshine游戏串流终极指南:5步搭建你的私人云游戏服务器

Sunshine游戏串流终极指南&#xff1a;5步搭建你的私人云游戏服务器 【免费下载链接】Sunshine Self-hosted game stream host for Moonlight. 项目地址: https://gitcode.com/GitHub_Trending/su/Sunshine Sunshine是一款功能强大的开源游戏串流服务器&#xff0c;专为…...

Python开发者三步完成Taotoken API密钥配置与调用

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 Python开发者三步完成Taotoken API密钥配置与调用 对于希望快速接入大模型能力的Python开发者而言&#xff0c;Taotoken平台提供的…...

基于大语言模型的学术论文AI阅读助手:从PDF解析到智能问答全流程解析

1. 项目概述&#xff1a;一个为学术论文阅读而生的AI助手 如果你经常需要阅读海量的学术论文&#xff0c;尤其是计算机科学、人工智能领域的英文PDF文献&#xff0c;那你一定对那种“打开一篇新论文&#xff0c;面对几十页的陌生术语和复杂公式&#xff0c;不知从何读起”的无…...

Fast-GitHub终极指南:如何将GitHub下载速度从KB/s提升到MB/s

Fast-GitHub终极指南&#xff1a;如何将GitHub下载速度从KB/s提升到MB/s 【免费下载链接】Fast-GitHub 国内Github下载很慢&#xff0c;用上了这个插件后&#xff0c;下载速度嗖嗖嗖的~&#xff01; 项目地址: https://gitcode.com/gh_mirrors/fa/Fast-GitHub 你是否曾因…...

GPT-Image 2 对标竞争者研发?——理性看待“对手传闻”的技术路径(2026 观察)

深度观察&#xff1a;OpenAI 是否在暗中加速 GPT-Image 2 对标竞争者研发&#xff1f;——理性看待“对手传闻”的技术路径&#xff08;2026 观察&#xff09;“竞争对手是否在秘密被研发&#xff1f;”“OpenAI 背后是不是在悄悄做某种 GPT-Image 2 的替代方案&#xff1f;”这…...

解密Ryujinx:5个核心技术原理让你理解现代游戏模拟器的设计哲学

解密Ryujinx&#xff1a;5个核心技术原理让你理解现代游戏模拟器的设计哲学 【免费下载链接】Ryujinx 用 C# 编写的实验性 Nintendo Switch 模拟器 项目地址: https://gitcode.com/GitHub_Trending/ry/Ryujinx Ryujinx作为一款基于C#开发的Nintendo Switch模拟器&#x…...