跳转到主要内容

标签(标签)

资源精选(342) Go开发(108) Go语言(103) Go(99) angular(82) LLM(75) 大语言模型(63) 人工智能(53) 前端开发(50) LangChain(43) golang(43) 机器学习(39) Go工程师(38) Go程序员(38) Go开发者(36) React(33) Go基础(29) Python(24) Vue(22) Web开发(20) Web技术(19) 精选资源(19) 深度学习(19) Java(18) ChatGTP(17) Cookie(16) android(16) 前端框架(13) JavaScript(13) Next.js(12) 安卓(11) 聊天机器人(10) typescript(10) 资料精选(10) NLP(10) 第三方Cookie(9) Redwoodjs(9) LLMOps(9) Go语言中级开发(9) 自然语言处理(9) PostgreSQL(9) 区块链(9) mlops(9) 安全(9) 全栈开发(8) ChatGPT(8) OpenAI(8) Linux(8) AI(8) GraphQL(8) iOS(8) 软件架构(7) Go语言高级开发(7) AWS(7) C++(7) 数据科学(7) whisper(6) Prisma(6) 隐私保护(6) RAG(6) JSON(6) DevOps(6) 数据可视化(6) wasm(6) 计算机视觉(6) 算法(6) Rust(6) 微服务(6) 隐私沙盒(5) FedCM(5) 语音识别(5) Angular开发(5) 快速应用开发(5) 提示工程(5) Agent(5) LLaMA(5) 低代码开发(5) Go测试(5) gorm(5) REST API(5) 推荐系统(5) WebAssembly(5) GameDev(5) CMS(5) CSS(5) machine-learning(5) 机器人(5) 游戏开发(5) Blockchain(5) Web安全(5) Kotlin(5) 低代码平台(5) 机器学习资源(5) Go资源(5) Nodejs(5) PHP(5) Swift(5) 智能体(4) devin(4) Blitz(4) javascript框架(4) Redwood(4) GDPR(4) 生成式人工智能(4) Angular16(4) Alpaca(4) 编程语言(4) SAML(4) JWT(4) JSON处理(4) Go并发(4) kafka(4) 移动开发(4) 移动应用(4) security(4) 隐私(4) spring-boot(4) 物联网(4) nextjs(4) 网络安全(4) API(4) Ruby(4) 信息安全(4) flutter(4) 专家智能体(3) Chrome(3) CHIPS(3) 3PC(3) SSE(3) 人工智能软件工程师(3) LLM Agent(3) Remix(3) Ubuntu(3) GPT4All(3) 软件开发(3) 问答系统(3) 开发工具(3) 最佳实践(3) RxJS(3) SSR(3) Node.js(3) Dolly(3) 移动应用开发(3) 低代码(3) IAM(3) Web框架(3) CORS(3) 基准测试(3) Go语言数据库开发(3) Oauth2(3) 并发(3) 主题(3) Theme(3) earth(3) nginx(3) 软件工程(3) azure(3) keycloak(3) 生产力工具(3) gpt3(3) 工作流(3) C(3) jupyter(3) 认证(3) prometheus(3) GAN(3) Spring(3) 逆向工程(3) 应用安全(3) Docker(3) Django(3) R(3) .NET(3) 大数据(3) Hacking(3) 渗透测试(3) C++资源(3) Mac(3) 微信小程序(3) Python资源(3) JHipster(3) 大型语言模型(2) 语言模型(2) 可穿戴设备(2) JDK(2) SQL(2) Apache(2) Hashicorp Vault(2) Spring Cloud Vault(2) Go语言Web开发(2) Go测试工程师(2) WebSocket(2) 容器化(2) AES(2) 加密(2) 输入验证(2) ORM(2) Fiber(2) Postgres(2) Gorilla Mux(2) Go数据库开发(2) 模块(2) 泛型(2) 指针(2) HTTP(2) PostgreSQL开发(2) Vault(2) K8s(2) Spring boot(2) R语言(2) 深度学习资源(2) 半监督学习(2) semi-supervised-learning(2) architecture(2) 普罗米修斯(2) 嵌入模型(2) productivity(2) 编码(2) Qt(2) 前端(2) Rust语言(2) NeRF(2) 神经辐射场(2) 元宇宙(2) CPP(2) 数据分析(2) spark(2) 流处理(2) Ionic(2) 人体姿势估计(2) human-pose-estimation(2) 视频处理(2) deep-learning(2) kotlin语言(2) kotlin开发(2) burp(2) Chatbot(2) npm(2) quantum(2) OCR(2) 游戏(2) game(2) 内容管理系统(2) MySQL(2) python-books(2) pentest(2) opengl(2) IDE(2) 漏洞赏金(2) Web(2) 知识图谱(2) PyTorch(2) 数据库(2) reverse-engineering(2) 数据工程(2) swift开发(2) rest(2) robotics(2) ios-animation(2) 知识蒸馏(2) 安卓开发(2) nestjs(2) solidity(2) 爬虫(2) 面试(2) 容器(2) C++精选(2) 人工智能资源(2) Machine Learning(2) 备忘单(2) 编程书籍(2) angular资源(2) 速查表(2) cheatsheets(2) SecOps(2) mlops资源(2) R资源(2) DDD(2) 架构设计模式(2) 量化(2) Hacking资源(2) 强化学习(2) flask(2) 设计(2) 性能(2) Sysadmin(2) 系统管理员(2) Java资源(2) 机器学习精选(2) android资源(2) android-UI(2) Mac资源(2) iOS资源(2) Vue资源(2) flutter资源(2) JavaScript精选(2) JavaScript资源(2) Rust开发(2) deeplearning(2) RAD(2)

在选择您希望如何公开您的 Go 服务时,在 gRPC 和 HTTP 之间进行选择可能是一个相当困难的选择。 gRPC 为您提供了更高性能的网络传输,而围绕它的工具仍然落后于您更标准的基于 HTTP 的 API。

在本教程中,我们将研究如何利用 go-playground/validator 包来提高 API 和 UX 组件的安全性。

gRPC 服务中的验证


我喜欢 gRPC 服务开发的关键之一是通过 protobuf 定义对服务消费者施加的严格性。获得此设置的工具可以说更复杂一些,并且需要更长的时间,但一旦到位,它有助于确保消费者向您发送您期望的有效负载。

HTTP 替代方案


不过值得庆幸的是,有一种方法可以对传入 Go 服务的 HTTP JSON 请求实施某种程度的严格性。我们可以在我们的 HTTP 服务中使用一种称为 JSON 请求验证的技术,它可以有效地确保传入的请求在我们的服务处理之前通过一系列检查。

一个简单的例子


例如,让我们看一下处理诸如配置新用户帐户之类的任务的用户管理系统。我们通常会有一个看起来有点像这样的端点来创建新用户:

HTTP POST /api/v1/user
Content-Type application/json

{"username": "elliot", "email": "support@tutorialedge.net"}

我们传输层中的代码通常会接收这个 HTTP 请求的主体,并尝试将其解组为如下结构:

type User struct {
    Username string `json:"username"`
    Email string `json:"email"`
}

// server setup code

// PostUser - handles the provisioning of a new user account
func (h *Handler) PostUser(w http.ResponseWriter, r *http.Request) {
    var u User
    // ignoring errors is bad - this is just an example
    _ = json.Unmarshal([]byte(request.Body), &u)

    newUser, err := h.UserService.CreateUser(r.Context(), u)
    // handle any errors 
    // send responses back to the caller over the ResponseWriter 
}

现在这个流程可以工作了,但是我们可以改进它并在这个处理函数中添加验证规则,在我们将请求正文解组到我们的结构中之后,它会包含我们期望的所有字段。

事实上,我们不仅可以验证这些字段是否存在(如果需要),我们还可以对这些字段的内容进行额外的验证,并确保例如电子邮件字段实际上是有效的电子邮件。

使用 go-playground/validator 添加验证

GitHub Package Link - go-playground/validator

让我们扩展上面的示例代码以包含我们讨论的电子邮件验证。使用诸如 go-playground/validator 之类的包,我们可以在结构上添加额外的标签信息,并在我们解组后调用 validate:

import (
    // other imports
    "github.com/go-playground/validator/v10"
    //
)


type User struct {
    Username string `json:"username" validate:"required"`
    Email string `json:"email" validate:"email,required"`
}

// server setup code

// PostUser - handles the provisioning of a new user account
func (h *Handler) PostUser(w http.ResponseWriter, r *http.Request) {
    var u User
    _ = json.Unmarshal([]byte(request.Body), &u)


    validate := validator.New()
	err := validate.Struct(wh)
	if err != nil {
        // log out this error
        log.Error(err)
        // return a bad request and a helpful error message
        // if you wished, you could concat the validation error into this
        // message to help point your consumer in the right direction.
		http.Error(w, "failed to validate struct", 400)
        return
    }

    newUser, err := h.UserService.CreateUser(r.Context(), u)
}

在这个例子中,我们有效地实现了两件事:

  • 我们已经能够验证用户名和电子邮件字段都存在于未编组的 u User 结构中。
  • 我们在电子邮件字段中添加了验证,以尝试验证存在的任何字符串是否看起来像有效的电子邮件。

这有效地在我们的应用程序的入口点验证了我们的 API 的消费者不能向我们发送我们没有真正处理方式的数据。

其他类型的验证


现在,应该注意的是,我们不仅限于使用此包进行基本验证。这个项目的自述文件包含大量不同类型的验证,这些验证包含在包中,允许大量不同的用例。

如果您是构建基于基础设施的服务的网络工程师,那么您可以使用大量不同的基于网络的验证,例如 ipv4、ipv6、cidr、url 和 uri。

我们为什么要验证?


我们应该致力于在应用程序的入口点验证传入请求的最大原因之一是为了提高安全性。

使用这种方法,我们可以帮助保护服务的内部工作免受格式错误的数据或潜在的不良行为者将诸如 SQL 注入字符串之类的东西注入我们的服务中。

在这方面它当然不是灵丹妙药,您可能仍需要进一步提高应用程序的安全性,但这无疑是一个很好的开始。

这如何改善用户体验?


在开发 API 时,调用我们 API 的用户体验非常重要。如果您正在开发公共 API,情况尤其如此。

通过将此验证添加到我们的传输层,我们可以立即向 API 的使用者返回 400 Bad Request 状态,并通知他们缺少哪些字段,或者哪些字段可能未通过高级验证。

这使 API 的使用者可以立即了解给定请求失败的原因,然后采取措施解决任何问题。对于那些与返回诸如内部服务器错误或类似内容之类的无信息内容相反的用户而言,这是一种更好的用户体验。

更复杂的验证示例


应该注意的是,对于更复杂的验证用例,我们不限于已经包含在该包中的验证器列表。

如果您需要更复杂的验证,则可以选择编写自定义验证器并以与我们对烘焙品种所做的几乎相同的方式使用它们。

让我们看一下 repo 中给出的示例。它展示了我们如何定义一个相当随意的示例,但它表明我们对每个验证器实际检查的内容具有完全的灵活性。


   

   
package validators

import (
	"reflect"
	"strings"

	"github.com/go-playground/validator/v10"
)

// NotBlank is the validation function for validating if the current field
// has a value or length greater than zero, or is not a space only string.
func NotBlank(fl validator.FieldLevel) bool {
	field := fl.Field()

	switch field.Kind() {
	case reflect.String:
		return len(strings.TrimSpace(field.String())) > 0
	case reflect.Chan, reflect.Map, reflect.Slice, reflect.Array:
		return field.Len() > 0
	case reflect.Ptr, reflect.Interface, reflect.Func:
		return !field.IsNil()
	default:
		return field.IsValid() && field.Interface() != reflect.Zero(field.Type()).Interface()
	}
}

此示例的测试文件显示了我们如何注册此验证器:

v := validator.New()
err := v.RegisterValidation("notblank", NotBlank)


结论


因此,在本文中,我们讨论了如何使用 go-playground/validator 包在应用程序中实现 HTTP JSON 请求验证。我们已经讨论了一些关键优势,以及它最终如何帮助提高系统的安全性。

如果您有兴趣在更能代表真实应用程序的代码中看到这种验证,那么我建议您查看我的最新课程 - 在 Go 中构建生产就绪服务 - 第 2 版

文章链接