Auth微服务开发记录

Auth服务 这里先写我们的初步规划,最终的实现放在最后写。这实际上也是我们的开发思路。 初步规划的API /api/v1/auth/login ​ 登录接口允许用户输入用户名和密码进行登录,服务器验证成功后,会返回一个JWT。JWT会存储在客户端的本地存储中 /api/v1/auth/register ​ 用户注册,填写用户的基本信息,在服务器的数据库上进行注册 /api/v1/auth/verify ​ 用户在拿着JWT去访问别的微服务的时候,我们要先验证这个JWT的合法性。确保用户合法。具体的实现就是去检查这个JWT是否过期,用户名是否正确。 /api/v1/auth/refresh ​ JWT有一个Expire过期时间,当用户还在使用的时候,JWT需要刷新。就使用刷新令牌进行刷新,经过服务器验证之后,返回一个新的刷新令牌。 /api/v1/auth/logout ​ 退出登录,需要在客户端本地删除token,并且把刷新令牌revoke 查阅资料:刷新Token的策略 刷新令牌(Refresh Token) 定义: 刷新令牌是一种用于获取新的访问令牌(Access Token)的凭证,通常在访问令牌过期后使用,以避免用户频繁重新登录。 工作原理: 用户首次登录时,服务器颁发一个访问令牌和一个刷新令牌。 访问令牌用于访问受保护的资源,具有较短的有效期。 当访问令牌过期时,客户端使用刷新令牌向服务器请求新的访问令牌。 服务器验证刷新令牌的有效性,如果有效,则颁发新的访问令牌,并可能同时颁发新的刷新令牌。 优点: 提高用户体验,减少频繁登录的需求。 访问令牌具有较短的有效期,降低安全风险。 缺点: 需要妥善保护刷新令牌,因为刷新令牌的泄露可能导致长期的安全问题。 实现强制注销或更改密码后立即失效所有令牌比较困难。 缓存令牌(Cached Token) 定义: 缓存令牌是指将令牌存储在缓存系统(如Redis)中,以便快速验证和撤销令牌。 工作原理: 用户登录后,服务器生成一个令牌并将其存储在缓存系统中。 客户端在访问受保护的资源时,携带令牌。 服务器从缓存系统中验证令牌的有效性。 如果需要撤销令牌,服务器可以从缓存系统中删除该令牌。 优点: 快速验证和撤销令牌,提高系统的响应速度。 灵活的令牌管理,可以随时撤销某个令牌。 缺点: 增加了系统的复杂性,需要维护缓存系统。 依赖外部服务,如果缓存系统出现故障,会影响整个系统的正常运行。 双令牌机制(Dual Token Mechanism) 定义: 双令牌机制是指使用两种不同类型的令牌来实现更复杂的授权和身份验证流程。 工作原理: 用户通过身份验证后,服务器颁发一个身份验证令牌(例如JWT)和一个授权令牌(例如OAuth 2.0的访问令牌)。 身份验证令牌用于证明用户的身份,通常具有较长的有效期。 授权令牌用于访问受保护的资源,通常具有较短的有效期。 当授权令牌过期时,客户端可以使用身份验证令牌向服务器请求新的授权令牌。 优点: 身份验证令牌具有较长的有效期,减少用户频繁登录的需求。 授权令牌具有较短的有效期,降低安全风险。 可以实现更复杂的授权策略。 缺点: 实现和管理双令牌机制比单一令牌机制更复杂。 需要妥善保护身份验证令牌,因为身份验证令牌的泄露可能导致长期的安全问题。 总结 刷新令牌主要用于在访问令牌过期后获取新的访问令牌,减少用户频繁登录的需求。 缓存令牌通过将令牌存储在缓存系统中,实现快速验证和撤销令牌。 双令牌机制使用两种不同类型的令牌来实现更复杂的身份验证和授权流程。 每种机制都有其适用的场景和优缺点,选择合适的机制需要根据具体的安全需求和业务场景来决定。...

June 18, 2024 · 1 min · 94 words · sirius1y

Protobuf与gRPC初次使用

在项目aorb中能够使用了微服务架构,然后引入了RPC,现在目前开发中,晚点再来完善这篇文章。现在先记录一些主要的概念。 IDL 接口定义语言 IDL(Interface Definition Language,接口定义语言)是一种用于定义软件组件之间接口的语言。IDL允许开发人员定义程序模块之间的接口,使得不同语言、平台和系统能够通过统一的接口进行通信。IDL的主要作用是定义数据类型和RPC(Remote Procedure Call,远程过程调用)的接口。 Proto接口定义的意义 Proto接口定义是指使用Protocol Buffers(protobuf)来定义数据结构和服务接口。protobuf是由Google开发的一种高效的二进制序列化格式,常用于配置文件、数据存储格式和通信协议。 跨语言支持:proto文件可以生成多种语言的代码,包括C++、Java、Python等,确保不同语言的系统可以互相通信。 高效传输:protobuf序列化后的数据体积小,解析速度快,适合网络传输。 版本兼容:proto文件可以通过增加新字段来实现向后兼容,不影响旧的客户端和服务器。 RPC(Remote Procedure Call,远程过程调用) RPC是一种通过网络从远程计算机程序上执行子程序的协议,仿佛是在本地执行一样。RPC隐藏了底层的网络通信细节,使得开发者可以像调用本地方法一样调用远程方法。 IDL和RPC的关系 IDL用于定义RPC接口,指定远程调用所需的参数和返回值类型。通过IDL定义的接口,可以自动生成客户端和服务器的桩代码(stub),这些代码负责处理序列化和反序列化、网络通信等底层细节,使得开发者可以专注于业务逻辑。 RESTful和gRPC的关系 RESTful和gRPC是两种不同的网络通信风格和框架,它们各自服务于不同的应用场景和需求。下面是它们之间的关系和区别: RESTful (Representational State Transfer): RESTful是一种基于HTTP协议的设计风格,它利用HTTP的方法(如GET、POST、PUT、DELETE等)来操作资源。 RESTful服务通常使用JSON或XML作为数据交换格式。 RESTful API设计简单,易于理解和使用,适合于跨平台和跨语言的场景。 由于基于HTTP,RESTful服务天然支持浏览器和各种HTTP客户端,易于缓存和负载均衡。 gRPC (Google Remote Procedure Call): gRPC是由Google开发的高性能、开源的通用RPC框架。 gRPC使用Protocol Buffers(protobuf)作为接口定义语言(IDL)和数据序列化格式。 gRPC支持多种语言,并提供了跨语言的接口调用能力。 gRPC支持双向流式传输,适合于需要高性能和低延迟的场景,如微服务架构。 gRPC默认使用HTTP/2作为传输协议,支持多路复用和服务端推送等特性。 关系: RESTful和gRPC都是用于构建分布式系统和微服务的通信协议,但它们的设计理念和使用场景有所不同。 RESTful更多地依赖于HTTP协议的特性,而gRPC则是一个独立的RPC框架,虽然它也使用了HTTP/2协议,但其核心在于protobuf的序列化和高效的RPC调用。 在实际应用中,选择RESTful还是gRPC取决于具体的需求,如性能要求、开发语言、团队熟悉度、生态系统支持等。 总结: RESTful和gRPC是两种互补的技术,它们各自在不同的领域和场景中发挥作用。开发者可以根据项目的具体需求和约束来选择最合适的通信方式。 .pb.go和_grpc.pb.go文件 在Go语言中使用Protocol Buffers (protobuf) 时,通常会生成两个主要的Go文件,分别是 auth_grpc.pb.go 和 auth.pb.go。这两个文件的作用如下: auth.pb.go: 这个文件是由protobuf编译器根据.proto文件中的消息定义生成的。它包含了所有在.proto文件中定义的消息(messages)、枚举(enums)和任何其他非RPC相关的数据结构的Go语言实现。 auth.pb.go 文件主要负责序列化和反序列化数据,以及提供对消息结构的访问。例如,如果你在.proto文件中定义了一个名为 Token 的消息,auth.pb.go 将包含一个名为 Token 的Go结构体以及用于操作这个结构体的函数,如 Marshal、Unmarshal、New 等。 auth_grpc.pb.go: 这个文件是由protobuf编译器根据.proto文件中的服务定义(service definitions)生成的,特别是当.proto文件中包含了gRPC服务定义时。 auth_grpc....

June 18, 2024 · 1 min · 205 words · sirius1y

golang八股文

Golang goroutine内存泄漏 slice导致 获取长字符串中的一段,导致字符串未释放; 获取长slice中的一段导致长slice未释放; 在长切片中新建sllice导致泄漏 channel导致 发送不接受,接收不发送,nil channel 从 channel 里读,但是同时没有写入操作 向 无缓冲 channel 里写,但是同时没有读操作 向已满的 有缓冲 channel 里写,但是同时没有读操作 select操作在所有case上都阻塞() goroutine进入死循环,一直结束不了 向 nil channel 发送和接收数据都将会导致阻塞。这种情况可能在我们定义 channel 时忘记初始化的时候发生。 可见,很多都是因为channel使用不当造成阻塞,从而导致goroutine也一直阻塞无法退出导致的。 传统同步方式sync.mutex,sync.waitgroup导致 用了mutex加lock之后忘记unlock; 在一开始设置了具体数目的wg.wait(n),但是有没有写够足够数量n的wg.Done(),导致wg.Wait()一直等待下去。(正确方式可以使用wg.Add(1)配合wg.Done使用) Go调度器的GMP 在Go语言中,GPM通常指的是Goroutine、Processor和Machine,这是Go调度器(scheduler)的核心组成部分。下面是对每个部分的详细介绍: Goroutine (G): Goroutine是Go语言中的轻量级线程,由Go运行时管理。它们是并发的基本单位,可以被创建和销毁,而无需操作系统级别的线程开销。Goroutine的创建和销毁非常快速,因此可以轻松地创建成千上万个Goroutine。 Goroutine的调度是协作式的,这意味着一个Goroutine在执行时会自愿放弃CPU,让其他Goroutine有机会执行。这种协作式调度使得Go语言能够高效地利用多核处理器。 Processor (P): Processor是Go调度器中的一个抽象概念,代表一个逻辑处理器。每个P都有一个本地运行队列,用于存储待执行的Goroutine。P的数量可以通过环境变量或运行时设置来调整,通常设置为CPU的核心数。 P的主要作用是管理Goroutine的执行。当一个Goroutine被调度到P上时,P会将其分配给一个可用的Machine(M)来执行。 Machine (M): Machine代表一个操作系统线程。M与P关联,负责执行Goroutine。一个M可以与多个P关联,但在任何给定时间,一个M只能执行一个P的Goroutine。 M的主要作用是执行Goroutine的代码。当一个Goroutine被调度到M上时,M会执行该Goroutine的代码,直到该Goroutine自愿放弃CPU或被抢占。 Go调度器的工作原理是将Goroutine(G)分配到Processor(P)上,然后由Machine(M)执行。这种设计使得Go语言能够高效地利用多核处理器,并实现高并发。 在 Go 语言的运行时系统中,Goroutine(简称 G)有多种状态,用于描述它在不同时间点的执行情况。这些状态在 Go 的调度器(GMP 模型)中扮演重要角色。GMP 模型由 Goroutine(G)、工作线程(M)和处理器(P)三部分组成。以下是 G 的主要状态及其转变过程,以及它们与 GMP 模型的关系。 G 的状态 _Gidle:空闲状态。Goroutine 尚未被使用或已经完成执行,等待被分配新任务。 _Grunnable:可运行状态。Goroutine 已经准备好运行,等待被调度器选中运行。 _Grunning:运行状态。Goroutine 正在运行中。 _Gsyscall:系统调用状态。Goroutine 正在执行系统调用,处于阻塞状态,不会被调度器调度。 _Gwaiting:等待状态。Goroutine 在等待某个条件(例如通道操作、定时器、网络 I/O 等)完成。 _Gdead:死亡状态。Goroutine 已经完成执行,无法再被重新使用。 _Gcopystack:堆栈复制状态。Goroutine 的堆栈正在被复制,以调整其大小。 状态转变及其与 GMP 的关系 创建 Goroutine _Gidle -> _Grunnable 创建一个新的 Goroutine,并将其状态设置为 _Grunnable,表示该 Goroutine 准备好运行。 由 P 将新的 Goroutine 添加到其本地运行队列或全局运行队列中。 g := newGoroutine() g....

June 12, 2024 · 3 min · 498 words · sirius1y

system-design-prime

system-design-prime 可用性模式 有两种支持高可用性的模式: 故障切换(fail-over)和复制(replication)。 故障切换 工作到备用切换(Active-passive) 关于工作到备用的故障切换流程是,工作服务器发送周期信号给待机中的备用服务器。如果周期信号中断,备用服务器切换成工作服务器的 IP 地址并恢复服务。 宕机时间取决于备用服务器处于“热”待机状态还是需要从“冷”待机状态进行启动。只有工作服务器处理流量。 工作到备用的故障切换也被称为主从切换。 双工作切换(Active-active) 在双工作切换中,双方都在管控流量,在它们之间分散负载。 如果是外网服务器,DNS 将需要对两方都了解。如果是内网服务器,应用程序逻辑将需要对两方都了解。 双工作切换也可以称为主主切换。 缺陷:故障切换 故障切换需要添加额外硬件并增加复杂性。 如果新写入数据在能被复制到备用系统之前,工作系统出现了故障,则有可能会丢失数据。 复制 主─从复制和主─主复制 这个主题进一步探讨了数据库部分: 主─从复制 主─主复制 CDN 内容分发网络 内容分发网络 CDN(英语:Content Delivery Network或Content Distribution Network)是一个全球性的代理服务器分布式网络,它从靠近用户的位置提供内容。通常,HTML/CSS/JS,图片和视频等静态内容由 CDN 提供,虽然亚马逊 CloudFront 等也支持动态内容。CDN 的 DNS 解析会告知客户端连接哪台服务器。 CDN 的分类 Pull CDN 当用户第一次访问CDN的时候,CDN上是没有资源的,这时候CDN会去向服务器拉取资源。之后的访问就直接在CDN服务器中返回就可以。 push CDN 服务器可以在用户访问资源之前,把资源push给CDN服务器。 如何选择哪种CDN? 关于使用哪种 CDN 类型的决定在很大程度上取决于流量和下载量。从长远来看,托管视频和播客(又名大量下载)的旅游博客会发现推送 CDN 更便宜、更高效,因为在您主动将其推送到 CDN 之前,CDN 不会重新下载内容。拉式 CDN 可以通过在 CDN 服务器上保留最受欢迎的内容来帮助高流量小下载的网站。内容的后续更新(或“拉取”)频率不足以使成本超过推送 CDN 的成本。 LoadBlancer 负载均衡器 负载均衡器将传入的请求分发到应用服务器和数据库等计算资源。无论哪种情况,负载均衡器将从计算资源来的响应返回给恰当的客户端。负载均衡器的效用在于: 防止请求进入不好的服务器 防止资源过载 帮助消除单一的故障点 通常会设置采用工作─备用 或 双工作 模式的多个负载均衡器,以免发生故障。...

June 12, 2024 · 1 min · 106 words · sirius1y

MongoDB快速上手

MongoDB安装 MongoDB官方的安装指南 Navicat客户端使用 可以在navicat上连上本地的mongodb使用,直观简单 Easy use (Terminal) 在终端中启动mongodb终端: mongosh 以下是一些 MongoDB 的简单常用命令,可以帮助你快速上手并管理 MongoDB 数据库: 启动 MongoDB shell mongo 基本数据库操作 列出所有数据库 show dbs 切换到指定数据库(如果数据库不存在则创建新数据库) use mydatabase 显示当前数据库 db 删除当前数据库 db.dropDatabase() 集合操作 创建集合 db.createCollection('mycollection') 列出所有集合 show collections 删除集合 db.mycollection.drop() 文档操作 插入文档 db.mycollection.insertOne({name: "John", age: 30}) db.mycollection.insertMany([{name: "Alice", age: 25}, {name: "Bob", age: 27}]) 查找文档 db.mycollection.find() db.mycollection.find({name: "John"}) 查找并格式化输出 db.mycollection.find().pretty() 更新文档 db.mycollection.updateOne({name: "John"}, {$set: {age: 31}}) db.mycollection.updateMany({name: "Alice"}, {$set: {age: 26}}) 替换文档 db.mycollection.replaceOne({name: "John"}, {name: "John", age: 32, city: "New York"}) 删除文档 db....

June 6, 2024 · 1 min · 98 words · sirius1y