分布式系统下的认证与授权

news2024/11/20 2:32:59

在软件系统设计中,如何让应用能够在各种环境中安全高效的访问是个复杂的问题,这个问题的背后是一系列软件设计时需要考虑的架构安全问题:架构安全性 | 凤凰架构

  • 认证:系统如何识别合法用户,也就是解决 你是谁 的问题;
  • 授权:系统在识别合法用户后,还需要解决 你能做什么 的问题;
  • 凭证:系统如何保证它与用户之间的承诺是双方真实意图的体现,是准确、完整且不可抵赖的;
  • 保密:如何安全的持久化用户的账户信息,确保不会被任何人窃取与滥用;
  • 传输:在复杂的用户环境中,如何安全的传递用户信息,保证不被第三方窃听、篡改和冒充。

在漫长的架构演进历史中,业界对这些问题已经有很成熟的解决方案。在架构安全这块,最好的是遵循技术标准与最佳实践,尽可能不重复造轮子或“创新”。下面这个思维导图就是针对这些问题的常见的技术标准及方案:

架构安全思维导图

在研究分布式系统的认证和授权问题前,让我们回到单体架构的时代,看看在单体架构上这些问题是如何被解决的。

单体系统

单体系统

认证

认证主要解决 你是谁 的问题,从方式上来看有以下三种:认证 | 凤凰架构

  • 基于通信信道:建立通信信道之前需要证明 你是谁。在网络传输(Network)场景中的典型是基于 SSL/TLS 传输安全层的认证。
  • 基于通信协议:在获取资源之前需要证明 你是谁。在互联网(Internet)场景中的典型是基于 HTTP 协议的认证。
  • 基于通信内容:在提供服务之前需要证明 你是谁。在万维网(World Wide Web)场景中的典型是基于 Web 内容的认证。

在单体系统时代,认证方式一般是在通信信道上开启 HTTPS,在通信协议上利用 HTTP Basic/Digest/Bearer/HOBA/OCRA 等方式并在通信内容上结合表单或 TOTP 等的认证组合方式。这样可以从通信的不同阶段获得相应的安全保证。

如果想对基于 HTTP 协议的认证方式做进一步的了解,可以参考这两篇文章:

  1. 认证 | 凤凰架构
  2. 细说API - 认证、授权和凭证 - Thoughtworks洞见

单点登录(SSO

认证的一个常见应用场景是单点登录。单点登录主要解决了一个一次登录访问多个独立应用的问题。在单点登录方案出现之前,每个应用都需要独立登录维持各自的会话。相关的技术方案已经很成熟,主要有以下:

  • Kerberos-based:MIT 设计的 SSO 协议,基于对称密码学,并需要一个值得信赖的第三方。其广泛用于操作系统认证,如被 Windows 2000 和后续的操作系统作为默认的认证方法。
  • CAS:Yale 设计的 SSO 协议,基于浏览器的 SSO 方案,部署简单,适用于简单的应用场景。
  • SAML:基于 XML 标记语言的认证断言方案,适用的场景众多,但技术较复杂。
  • OIDC:在 OAuth2 的基础上额外加一个 JWT 来传递用户信息。功能全面强大,是目前很流行的 SSO 方案。

授权

授权主要解决 你能做什么 的问题,从方案上来说有以下几种:

  • ACL:访问控制列表(Access-control list)广泛用于操作系统内部的文件系统、网络及进程权限控制方面。如在 Linux 中,可通过 getfacl 获取目录的默认 ACL 设置。
  • RBAC:RBAC 通过将权限属性从 ACL 方案中的单个用户抽取成更为抽象的角色(Role),通过给角色一组权限属性,再将多个角色赋予某个用户,实现了比 ACL 更为灵活强大的权限控制方案。实际上大部分系统的授权方案采用 RBAC 就足够了。但 RBAC 在面临复杂的权限控制需求时可能面临角色爆炸的问题,这时可以考虑采用更细粒度的 ABAC 方案。
  • ABAC:ABAC 是比 RBAC 更细粒度的权限控制方案。通过引入一组称为“属性”的特征,包括用户属性、环境属性和资源属性。例如,ABAC 可以对用户的访问做进一步的控制,如只允许在特定的时间或与相关员工相关的某些分支机构进行访问员工信息的操作,而不是让某部门的人员总是能够访问员工信息。但 ABAC 的问题在于初始设置需要定义大量的属性,工作量比 RBAC 要大。
  • OAuth2:OAuth2 是为了解决应用系统给第三方系统授权的问题而设计的授权框架。传统的客户端服务器交互模式中,客户端持有资源访问凭证(如用户名密码),服务端验证成功后放行。而在给第三方系统提供资源时,如果给第三方系统资源凭证,可能会带来未知的安全问题,比如凭证泄漏,凭证回收等问题。当应用系统面向第三方系统提供服务时,需要使用此方案。同时因为 OAuth2 做授权的时候一般需要用户登录,也能实现单点登录的功能。

如果想对授权做进一步的了解,可以参考这篇文章:

  1. 授权 | 凤凰架构

凭证

凭证是为了解决在认证授权后如何承载认证授权信息的问题。在单体应用时代,主流的解决方案是基于 HTTP 协议的 Cookie-Session 机制为代表的服务端状态存储技术。

由于 HTTP 协议本身是无状态的,要维持一个会话(Session),而不是每次访问都重新认证授权,需要客户端也就是浏览器通过 Cookie 来存储服务器端返回的一个凭证信息,这个凭证信息一般是一串随机的字符串,用来代表用户此次的会话标识。每次请求浏览器都会在 HTTP Header 中携带这个 Cookie 信息,应用拿到这个会话标识后从内存或缓存(Cache)中查询出用户的信息,这样就定位到了具体的用户,实现了会话的维持。

这套古老的方案存在以下先天优势:凭证 | 凤凰架构

  • 状态信息都存储于服务器,只要依靠客户端的 同源策略 和 HTTPS 的传输层安全,保证 Cookie 中的键值不被窃取而出现被冒认身份的情况,就能完全规避掉上下文信息在传输过程中被泄漏和篡改的风险(但 Cookie 方案容易受到 CSRF 攻击,这种可通过 CSRF Token 技术防御);
  • 另一大优点是服务端有主动的状态管理能力,可根据自己的意愿随时修改、清除任意上下文信息,譬如很轻易就能实现强制某用户下线的这样功能;
  • 服务端也很容易实现如统计用户在线这类功能;

一切都很美好,直到我们来到了分布式系统时代。

分布式系统

分布式系统与单体系统的一大区别就是状态管理。分布式系统通过把单体系统中有状态的部分转移到中间件中去管理,从而很容易做到水平扩容,提高系统峰值处理能力。在架构认证和授权部分,分布式和单体并没有什么不同,唯独有变化的在持有状态的凭证部分。

我们知道单体应用在服务端管理用户会话信息,客户端只持有会话标识。如果服务端要将此用户会话状态转移出去有两种处理思路:

  • 将用户会话信息继续托管至服务端。此时有几种服务端方案可以选择:

    • 中心化存储:转移到中间件如 Redis 中去。利用 Redis 极高的并发处理能力,也可以做到弹性横行扩容。不过可能会带来中间件高可用性维护难的问题,通过租赁云服务商的托管中间件是降低中间件 单点故障(SPOF) 的一种方式;
    • 会话复制(Session replication):让各个节点之间采用复制式的 Session,每一个节点中的 Session 变动都会发送到组播地址的其他服务器上,这样某个节点崩溃了,不会中断该节点用户的服务。但 Session 之间组播复制的同步代价高昂,节点越多时,同步成本越高。
    • 会话粘滞(Sticky session):通过负载均衡算法如 Nginx 的 IP Hash 算法将来自同一 IP 的请求转发至同一服务。每个服务节点都不重复地保存着一部分用户的状态,如果这个服务崩溃了,里面的用户状态便完全丢失。
  • 为什么在分布式系统中共享状态就这么困难?这是因为分布式系统中有一个不可能三角的理论:CAP。这个理论简单地理解就是因为在分布式系统中,因为网络无法做到绝对的可靠(分区容错性:Partition Tolerance),只能在一致性(Consistency)和可用性(Availability)间选择一个。 比如上述的三种服务端方案其实都是牺牲了 CAP 的某个方面。比如第一种中心化存储方案我们放弃了中心化存储的分区容错性,一旦其网络分区,整个集群都会不可用。第二种会话复制方案我们牺牲了可用性,当节点在同步会话数据时,整个服务会短暂的不可用。第三种会话粘滞方案我们牺牲了一致性,一旦某个节点宕机,整个集群的数据会因该节点的数据丢失而达到不一致的状态。

  • 将状态从服务端转移到客户端。Cookie-Session 是一种引用令牌(Reference tokens),也就是客户端持有的是服务端存储的会话引用标识。还有一种自包含令牌(Self-contained tokens),如 JWT 就是这种客户端保存会话信息的技术,服务端只是去校验会话信息是否合法。

JWT

如果你对 JWT 不了解,可以先看这两篇:

  1. JWT | 凤凰架构
  2. The Hard Parts of JWT Security Nobody Talks About

由于 JWT 的 Payload 并未做过多限制,所以很容易产生滥用的问题,并且带来很多误解。比如下面的一些问题:

  • 误把 JWT 当作 Cookie-Session 使用(把 JWT 当作引用令牌使用),会带来未知的隐患。遵循不重复造轮子和“创新”的指导原则,尽可能不要这么做;
  • 认为 JWT 更安全。虽然 JWT 采用了一定的加密算法签名,使其具备了抗篡改的能力。但其 Payload 大部分都只是采用 base64UrlEncode 编码,数据并不是加密的。攻击者可以通过 会话劫持(Session hijacking) 技术拿到 JWT 会话信息,之后通过 会话重放攻击(Session Replay Attack) 获取用户资源,所以最佳实践是通过启用 TLS/SSL 来加密通信信道。
  • 把 JWT 存储到浏览器的 Local Storage 中。此方式很容易受到 XSS 攻击导致 JWT 泄漏。可通过服务端启用 内容安全策略(CSP) 来防御这种攻击。
  • 采用对称加密方式签名(Signature)。对称加密密钥一旦泄漏,会让整个服务的基础设施遭受安全威胁。JWT 支持非对称加密算法,只有签名的服务需要私钥,其他验证 JWT 信息的服务只需要使用公钥即可。
  • 不校验 JWT 的签名算法。这篇 Critical vulnerabilities in JSON Web Token libraries 文章提到 JWT 的一种漏洞,通过 none 算法规避令牌验证。所以最好每次都验证 JWT header 中的签名算法是否是期望的。

相信看了上述的一些问题,你对 JWT 的“简单、安全”有了新的理解。这还没完,JWT 还有以下一些 Cookie-Session 没有的问题:

  • 令牌难以主动失效:JWT 中虽然有 expnbfiat 这些和时间相关的属性,但很难在令牌到期之前让令牌失效,比如很难在用户退出登录时立刻让签发的令牌全部失效。虽然可能通过一些“黑名单”的技术解决这个问题,不过相比 Cookie-Session 来说,引入了一定的复杂性;
  • 令牌数据老旧:很难把签发的令牌全部更新成最新的数据。比如把用户的权限信息(Role)放在 JWT Payload 中,当用户的角色发生变化时,很难把之前签发的令牌信息更新成最新的数据;
  • 令牌存储:存储在客户端意味着有多种选择:Cookie?Local Storage?如果放在 Cookie 中,为了安全,一般会给 Cookie 设置 http-onlysecure 的属性。但这也会带来一定的不便性,比如客户端要读取 JWT Payload 的内容只能借助服务端 API 接口。如果将 JWT 存储至浏览器 Local Storage,虽然方便了客户端读取,但可能会带来 XSS 攻击的威胁,又需要去设置 CSP 来防御这种威胁;
  • 令牌大小:JWT 相比 Cookie-Session 还是大不少,尤其是要在 Payload 中存储一些额外的权限信息。一般服务端都有对 HTTP Header 的大小限制;
  • 网络开销:更大的文本意味着更高的网络开销,进一步会需要更复杂的基础设施,也会产生复杂的运维问题等;
  • 难以统计:服务端无状态意味着很难做诸如统计用户在线数量的功能;

JWT 解决了 Cookie-Session 方案在分布式系统中因 CAP 的限制而带来的问题,但同时也带来了一些新的问题。所以并不能说 JWT 就是 Cookie-Session 在分布式系统中的完美替代。

那么 JWT 的最佳使用场景到底是什么?这篇 Stop using JWT for sessions 给出了以下的结论:JWT 更适合作分布式系统中的一次性令牌使用。分布式系统继续使用 Cookie-Session 做会话管理,但可以在认证鉴权后生成 JWT 做分布式系统内部服务调用间的一次性令牌。

让我们通过一个例子来理解下在分布式系统下的认证授权场景。

一个例子

分布式系统下的认证授权场景

  • 此处Auth服务承担的是授权(Authorization)的职责,而不是认证(Authentication)的职责;
  • OAuth2在协议中是做授权框架的,但是其一般需要登录授权,也能实现SSO的功能。
  1. 用户通过 HTTPS 访问我们的应用。当请求发送至微服务网关层(Gateway),网关检测 HTTP Header 中的 Cookie 发现没有 SESSIONID 这个键值对,重定向至 SSO 登录页面。
  2. 用户通过 SSO 登录我们的应用。
  3. 用户信息存放至 AD/LDAP 等系统中。管理员提前给用户配置好角色权限。
  4. SSO 集成方案我们选择 OIDC。OIDC 集成了 AD/LDAP,当用户提供正确的用户名和密码后,SSO 重定向至网关。
  5. 网关生成了 SESSIONID 键值对并通过 HTTP Set-Cookie 响应给用户浏览器设置了此 Cookie。
  6. 浏览器重新发起带 SESSIONID Cookie 的请求。网关经过查询其缓存或中间件(如将会话信息存放至 Redis)中的 Session 信息确认了用户的身份信息。之后网关请求 Auth 服务利用其私钥签名生成 JWT 凭证,JWT Payload 中可以存放一部分用户信息和角色信息,这些信息可以从中间件中或 AD/LDAP 中查询出。
  7. 网关之后将此 JWT 凭证通过反向代理转发至内部的 BFF 服务,之后请求到达内部的领域微服务。
  8. 各领域微服务接受到请求后,先从 HTTP Header 中拿出 JWT 凭证。
  9. 在执行真正的业务逻辑前,先利用之前定时从 Auth 服务中同步获取的公钥。
    1. Auth 服务通过一个类似 https://<your_domain>/.well-known/jwks.json 的 API 提供 JWT 公钥的分发。关于 .well-known 前缀,可阅读 RFC 5785 做进一步了解。在 jwks.json 文件中,我们可以找到 JWK 或 JSON Web Key,这是我们用来验证签名的公钥。
    2. 校验 JWT 这块逻辑属于微服务共有的部分,一般可以开发一个 SDK 包来做这个通用的工作。为了提高性能,可使用缓存技术,定时从 Auth 中同步公钥。
  10. 获取到公钥后验证成功后拿出 JWT Payload 即可获取到用户信息和角色权限。

全部流程就是这样,我们得到了以下的一些好处:

  • 这个流程里我们并没有将 JWT 返回给用户,只是在认证授权过后生成一个一次性的 JWT 令牌凭证用于微服务内部服务间的调用。因为用户的权限信息存放至 JWT Payload 中,内部的服务并不需要从 AD/LDAP 中获取用户权限信息。可能有人觉得内部服务直接从中间件中获取用户会话信息也可以,但这又让我们的应用进一步耦合了中间件,同时也让一个请求链路中产生更多的子请求,不如直接在请求头中存放用户信息的方式高效。
  • 在微服务内部间传递的是经过非对称加密算法签名的 JWT 凭证,并不是一个 JWT Payload 信息。就算我们的微服务内部被入侵,攻击者也并不能通过篡改凭证中用户的权限信息来搞破坏。这也满足了分布式系统中 零信任网络(Zero Trust) 的部分要求。
  • 与外部第三方应用的通讯(M2M),可以采用 OAuth2 的方式或 Personal Access Token 这种方式来集成。
  • 通过引入 SDK 与定时同步公钥的机制,我们引入了一定的复杂度。比如 SDK 在异构编程语言的项目中开发复杂的问题。不过这个问题在云原生系统时代有了不同的解法,让我们之后讨论这个问题。

架构总是在演进,也许分布式系统中很多问题我们还没完全解决,就来到了云原生时代。

云原生系统

如果你对云原生应用开发还不了解的话,可以先看看我这篇 K8S 云原生应用开发小记。云原生系统其实并不是什么后分布式系统时代。它们两者都是为了解决不同场景的问题而出现的解决方案。

在认证授权这块,云原生系统的优势在于可以通过 服务网格(Service Mesh) 做一些业务系统中通用的切面工作,比如我们在分布式系统中遇到的校验 JWT 的 SDK 其实就可以放入服务网格中的边车(Sidecar)去实现,让业务应用更专注特定领域的业务。

由于这篇文章并不主要讨论云原生,对这部分感兴趣的可以参考以下两篇文章做进一步了解:

  1. Service Mesh架构下的认证与授权
  2. 微服务下的身份认证和令牌管理

总结

由于篇幅及能力限制,这篇文章我只能从高层次梳理在不同架构演进中认证、授权及凭证这些和架构安全相关的技术的发展过程。由于这些技术涉及了大量的技术标准及实践,很难在一篇文章中对这些技术做详尽的分享,更无法去分享如何实现。但有了这些理论支持和最佳实践,希望能让你在实现的过程中多了一个指引。如果你想进一步了解,可参考文章中的参考文章链接。

最后,技术总是在不断的发展,但并不是新技术总比老技术“先进”。正如文章中对 Cookie-Session 与 JWT 的分析对比,技术方案总是充满了各种 Trade-off。而作为一个工程师,我们能做的就是认清这些技术的历史背景及局限性,选择最适合项目需求的技术方案。


文/Thoughtworks 马大伟
原文链接:分布式系统下的认证与授权

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

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

相关文章

2022年全球气候金融产品研究报告

第一章 全球气候金融概述 气候变化既是环境问题也是发展问题,需要大量气候资金的投入,金融作为推动经济发展的核心要素,在应对天气变化中能够发挥重要作用。气候金融是与应对气候变化相关的创新金融,是利用多渠道资金来源、运用多…

redhat9安装卸载mysql

文章目录一.仓库安装1.1、下载rpm包1.2、挂载1.3、安装mysql1.4、启动mysql服务1.5、查看临时密码1.6、登录mysql二.本地安装2.1、复制链接2.2、下载解压2.3、安装需要的包2.4、启动服务2.5、登录mysql三.容器安装3.1、安装docker3.2、run镜像3.3、登录mysql四.源码安装4.1、复…

STM32MP157驱动开发——多点电容触摸屏驱动

STM32MP157驱动开发——多点电容触摸屏驱动一、简介二、电容触摸屏驱动框架简介多点触摸(MT)协议详解三、驱动开发1.添加 FT5426 设备节点2.FT5426 节点配置3.驱动编写4.运行测试5.将驱动添加到内核中1)将驱动文件放到合适的位置2)修改Makefile6.tslib 移…

Xillinx的设计约束阅读整理

《适用于FPGA和SOC的UlteraFast设计方法指南》(UG949) 《Vivado Design Suite 用户指南:设计分析与收敛技巧》(UG906) 《Vivado Design Suite 用户指南:使用约束》(UG903) 《Vivado Design Suite Tcl 命令参考指南》(UG835) 约束文…

【java基础】关于线程的一些基础知识点

1.线程的概念: 在java的应用中,线程更多情况下指的是Thread,更精细一点,执行线程就是执行Thread实体下面的run方法,java通过cpu调试,交替进行这些thread,就达到了共同进行这种效果;…

【尚硅谷】SpringBoot2核心技术-1-基础入门

【尚硅谷】SpringBoot2核心技术-1-基础入门一、Spring与SpringBoot1、Spring能做什么1.1、Spring的能力1.2、Spring的生态【没写完】二、SpringBoot2入门1、系统要求1.1、maven设置2、HelloWorld2.1、创建maven工程2.2、引入依赖2.3、创建主程序2.4、编写业务2.5、测试2.6、简化…

DM8开发技能

DM8开发技能 基础学习笔记005 文章目录DM8开发技能1、DMSQL程序设计1.1 概念1.2 数据类型1.3 程序定义1.3.1 存储过程1.3.2 存储函数1.3.3 客户端DMSQL程序1.3.4 参数1.3.5 控制结构(1)顺序结构(2)分支结构(3&#xf…

Doo Prime 德璞资本:道琼斯期货投资前必看的入门知识

美国道琼工业指数是全球最受关注的股指之一,而道琼斯期货则是典型的衍生性金融商品,交易的标的是道琼指数本身,属于期货投资的范畴,适合短线进出、波段交易。想要参与美国的期货投资市场,却不知道期货该如何开始吗&…

C# XPath的概念

一 XPath的概念 1 XPath是对XML进行查询的表达式 ① Axes(路径) / 及 //; ② 第几个子节点[1] 等; ③ 属性 ④ 条件 [] ⑤ 例如 /books/book/title //price para[type“warning”][5] 2 使用XPath ① XmlDocument docnew XmlDocument(); ② doc.LoadXml(strXml)…

通过idea打包java Maven项目 架包与全包

1 仅架包 架包定义:指仅将代码打包到jar中,在运行的平台必须保证依赖。 方法:maven —> Lifecyle —> Clean —> Package 2 架包与全包(推荐) 全包定义:将maven项目中的依赖于代码都打为一个包。 方法:mave…

RK3568平台开发系列讲解(Linux系统篇)Linux 管道的使用

🚀返回专栏总目录 文章目录 一、 管道1.1、单向管道1.2、双向管道沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将介绍管道的使用。 一、 管道 在 fork() 成功创建子进程之后,已经打开的文件描述符在父子进程间是共享的,管道就是利用这一特性来工作的。 创建…

C++:设计一个文本行编辑程序,先从输入文件中读取数据,然后根据行编辑命令处理,将结果写到输出文件中。

3.1题目: 设计一个文本行编辑程序 对文本文件按行进行编辑:先从输入文件中读取数据,然后根据行编辑命令处理,将结果写到输出文件中。行编辑命令包括:序号 行编辑命令格式 功能 1 *L m,n …

ts概述、ts环境准备和编译、ts类型声明

文章目录1. ts概述2. ts环境准备和编译3. ts类型声明3.1 布尔值3.2 数字类型3.3 字符串类型3.4 any和unknown3.5 void、null、undefined3.6 never类型3.7 字面量类型3.8 枚举类型3.9 object对象类型3.10 数组3.11 元组3.12 自定义类型type3.13 联合类型3.14 交叉类型3.15 类型断…

《深入理解计算机系统》学习笔记 —— 虚拟内存详解

文章目录虚拟内存物理内存、物理地址、虚拟地址虚拟地址空间虚拟内存缓存页表分配页面页命中缺页虚拟内存的好处简化链接mmap虚拟内存的私有性地址翻译我们先看一下使用页表进行地址翻译有哪些东西:虚拟地址到物理地址处理过程页面大小和虚拟地址物理地址关系TLB翻译…

2022年,我45岁,一息尚存不落征帆,静稳前行未来可期

2022年,我45岁,一息尚存不落征帆,静稳前行未来可期, 关键词:模式固定,回顾与审视,不间断地阅读 模式固定 本年的52周,每逢周五我会把还在更新的15册讲书各讲一期。每期讲20分钟左…

nodejs mp2 姿势启动

以前运行 nodejs 代码都是 node xxx.js; 但是很容易就关掉了, 或者你想看跟详细的数据 是看不到的。 可以试试 pm2的方式 运行你的代码;学习新的姿势! pm2的安装: 1: npm install pm2 -g C:\Users\Admini…

数据治理:数据治理框架和标准

参考《一本书讲透数据治理》、《数据治理》等 数据治理并不是新概念,在国内外都有实践,这里重点介绍下国内外对数据治理的主流框架和标准 国际数据治理框架 国际上,主流的数据治理框架主要有:ISO数据治理标准、GDI数据治理框架、…

深入浅出scala之函数(匿名函数)(P41-45)

文章目录1.函数的定义2.匿名函数3.递归函数4.无参函数5.方法和函数的区别联系1.函数的定义 package MethodDemoobject FunctionDefinition {// 实现加法的功能,省略写法,把函数体写在返回值的位置val f1 ((a: Int, b: Int) > { a b })val f2 (a: …

Charles - 配置抓Chrome、iOS、Android包环境

官网下载地址:https://www.charlesproxy.com/。 1、设置代理http端口 路径:Proxy > Proxy Settings > Proxies > HTTP proxy > Prot 2、设置代理https端口 路径:SSL Proxying Settings > SSL Proxyin 3、Mac证书配置 …

谷粒商城-基础篇-Day06-属性分组

属性分组 抽取出一个tree组件放到modules下的common下的category.vue <template><el-tree :data"menus" :props"defaultProps" node-key"catId"ref"menu"></el-tree> </template><script> //这里可以…