Go - 用户服务和Web服务

文章目录

  • go日志库之zap
    • 1. 安装和基本使用
    • 2. 写入日志文件
  • go的配置文件管理-viper
    • 1. 介绍
    • 2. yaml教程
    • 3. 安装
    • 4. 将配置文件映射成struct
    • 5. 使用
  • 自定义验证器
    • 1. 手机号码正则表达式
    • 2. 自定义翻译的问题
  • JWT
    • 1. json web token是什么?
    • 2. 什么时候你应该用JSON Web Tokens
    • 3. JSON Web Token的结构是什么样的
    • 4. JSON Web Tokens是如何工作的
    • 5. 基于Token的身份认证 与 基于服务器的身份认证
  • 浏览器的跨域请求问题
    • 浏览器在什么情况下会发起options预检请求?
    • 阿里云发送短信

go日志库之zap

地址

Zap提供了两种类型的日志记录器— Sugared Logger 和 Logger 。
在性能很好但不是很关键的上下文中,使用 SugaredLogger 。它比其他结构化日志记录包快4-10倍,并且支持结构化和printf风格的日志记录。在每一微秒和每一次内存分配都很重要的上下文中,使用 Logger 。它甚至比 SugaredLogger 更快,内存分配次数也更少,但它只支持强类型的结构化日志记录

1. 安装和基本使用

go get -u go.uber.org/zap 
package main
	import (
		"go.uber.org/zap"
	)
	func main() {
		logger, _ := zap.NewProduction()
		defer logger.Sync() // flushes buffer, if any
		url := "https://imooc.com"
		sugar := logger.Sugar()
		sugar.Infow("failed to fetch URL",
			// Structured context as loosely typed key-value pairs.
			"url", url,
			"attempt", 3,
	)
	sugar.Infof("Failed to fetch URL: %s", url)
}

2. 写入日志文件

package main
	import (
		"go.uber.org/zap"
		"time"
	)
	func NewLogger() (*zap.Logger, error) {
		cfg := zap.NewProductionConfig()
		cfg.OutputPaths = []string{
		"./myproject.log",
		}
		return cfg.Build()
	}
	func main() {
	//logger, _ := zap.NewProduction()
	logger, err := NewLogger()
	if err != nil {
		panic(err)
		//panic("初始化logger失败")
	}
	su := logger.Sugar()
	defer su.Sync()
		url := "https://imooc.com"
		su.Info("failed to fetch URL",
		// Structured context as strongly typed Field values.
		zap.String("url", url),
		zap.Int("attempt", 3),
		zap.Duration("backoff", time.Second),
	)
}

go的配置文件管理-viper

1. 介绍

Viper是适用于Go应用程序的完整配置解决方案。它被设计用于在应用程序中工作,并且可以处理所有类型的配置需求和格式。它支持以下特性:

  • 设置默认值
  • 从 JSON 、 TOML 、 YAML 、 HCL 、 envfile 和 Java properties 格式的配置文件读取配置信息
  • 实时监控和重新读取配置文件(可选)
  • 从环境变量中读取
  • 从远程配置系统(etcd或Consul)读取并监控配置变化
  • 从命令行参数读取配置
  • 从buffer读取配置
  • 显式配置值

2. yaml教程

教程地址

3. 安装

go get github.com/spf13/viper 

4. 将配置文件映射成struct

package main
	import (
		"fmt"
		"github.com/spf13/viper"
	)
	type ServerConfig struct{
		ServiceName string `mapstructure:"name"`
		Port int `mapstructure:"port"`
	}
	func main(){
	v := viper.New()
	//⽂件的路径如何设置
	v.SetConfigFile("viper_test/ch01/config.yaml")
	if err := v.ReadInConfig(); err != nil{
		panic(err)
	}
	serverConfig := ServerConfig{}
	if err := v.Unmarshal(&serverConfig); err != nil{
		panic(err)
	}
	fmt.Println(serverConfig)
	fmt.Printf("%V", v.Get("name"))
}

配置文件config.yaml

name: 'user-web'
port: 8021

5. 使用

package main
	import (
		"fmt"
		"github.com/fsnotify/fsnotify"
		"github.com/spf13/viper"
		"time"
	)
	type MysqlConfig struct {
		Host string `mapstructure:"host"`
		Port int `mapstructure:"port"`
	}
	type ServerConfig struct{
		Name string `mapstructure:"name"`
		MysqlInfo MysqlConfig `mapstructure:"mysql"`
	}
	func GetEnvInfo(env string) string {
		viper.AutomaticEnv()
		return viper.GetString(env)
	}
	func main(){
		data := GetEnvInfo("Debug")
		var configFileName string
		configFileNamePrefix := "config"
		if data == "true" {
			configFileName = fmt.Sprintf("viper_test/%s-debug.yaml", configFileNamePr
		}else{
			configFileName = fmt.Sprintf("viper_test/%s-pro.yaml", configFileNamePref
		}
		serverConfig := ServerConfig{}
		fmt.Println(data)
		 v := viper.New()
		v.SetConfigFile(configFileName)
		err := v.ReadInConfig()
		if err != nil {
			panic(err)
		}
		if err := v.Unmarshal(&serverConfig); err != nil {
			panic(err)
		}
		fmt.Println(serverConfig)
		go func() {
			v.WatchConfig()
			v.OnConfigChange(func(e fsnotify.Event) {
			fmt.Println("Config file changed:", e.Name)
			_ = v.ReadInConfig() // 读取配置数据
			_ = v.Unmarshal(&serverConfig)
			fmt.Println(serverConfig)
		})
	}()
	time.Sleep(time.Second*3000)
}

配置文件内容

name: 'user-web'
mysql:
host: '127.0.0.1'
port: 3306

自定义验证器

1. 手机号码正则表达式

^1([38][0-9]|14[579]|5[^4]|16[6]|7[1-35-8]|9[189])\d{8}$ 

2. 自定义翻译的问题

//注册验证器
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
		_ = v.RegisterValidation("mobile", myvalidator.ValidateMobile)
		_ = v.RegisterTranslation("mobile", global.Trans, func(ut ut.Translator)
		return ut.Add("mobile", "{0} ⾮法的⼿机号码!", true) // see universal-t
		}, func(ut ut.Translator, fe validator.FieldError) string {
		t, _ := ut.T("mobile", fe.Field())
		return t
	})
}

JWT

1. json web token是什么?

JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。

2. 什么时候你应该用JSON Web Tokens

下列场景中使用JSON Web Token是很有用的:
Authorization (授权) : 这是使用JWT的最常见场景。一旦用户登录,后续每个请求都将包含JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录是现在广泛使用的JWT的一个特性,因为它的开销很小,并且可以轻松地跨域使用。
**Information Exchange (信息交换) : **对于安全的在各方之间传输信息而言,JSON Web Tokens无疑是一种很好的方式。因为JWTs可以被签名,例如,用公钥/私钥对,你可以确定发送人就是它们所说的那个人。另外,由于签名是使用头和有效负载计算的,您还可以验证内容没有被篡改。

3. JSON Web Token的结构是什么样的

JSON Web Token由三部分组成,它们之间用圆点(.)连接。这三部分分别是:

  • Header
  • Payload
  • Signature
    因此,一个典型的JWT看起来是这个样子的:
    xxxxx.yyyyy.zzzzz

Header
header典型的由两部分组成:token的类型(“JWT”)和算法名称(比如:HMAC SHA256或者RSA等等)。
然后,用Base64对这个JSON编码就得到JWT的第一部分

Payload
JWT的第二部分是payload,它包含声明(要求)。声明是关于实体(通常是用户)和其他数据的声明。声明有三种类型: registered, public 和 private。

Signature
为了得到签名部分,你必须有编码过的header、编码过的payload、一个秘钥,签名算法是header中指定的那个,然对它们签名即可。

4. JSON Web Tokens是如何工作的

在认证的时候,当用户用他们的凭证成功登录以后,一个JSON Web Token将会被返回。此后,token就是用户凭证了,你必须非常小心以防止出现安全问题。一般而言,你保存令牌的时候不应该超过你所需要它的时间。
无论何时用户想要访问受保护的路由或者资源的时候,用户代理(通常是浏览器)都应该带上JWT,典型的,通常放在Authorization header中,用Bearer schema。
header应该看起来是这样的:Authorization: Bearer
服务器上的受保护的路由将会检查Authorization header中的JWT是否有效,如果有效,则用户可以访问受保护的资源。如果JWT包含足够多的必需的数据,那么就可以减少对某些操作的数据库查询的需要,尽管可能并不总是如此。如果token是在授权头(Authorization header)中发送的,那么跨源资源共享(CORS)将不会成为问题,

下面这张图显示了如何获取JWT以及使用它来访问APIs或者资源:

image.png

5. 基于Token的身份认证 与 基于服务器的身份认证

5.1. 基于服务器的身份认证
在讨论基于Token的身份认证是如何工作的以及它的好处之前,我们先来看一下以前我们是怎么做的:HTTP协议是无状态的,也就是说,如果我们已经认证了一个用户,那么他下一次请求的时候,服务器不知道我是谁,我们必须再次认证。传统的做法是将已经认证过的用户信息存储在服务器上,比如Session。用户下次请求的时候带着Session ID,然后服务器以此检查用户是否认证过。
这种基于服务器的身份认证方式存在一些问题:
Sessions : 每次用户认证通过以后,服务器需要创建一条记录保存用户信息,通常是在内存中,随着认证通过的用户越来越多,服务器的在这里的开销就会越来越大。

Scalability : 由于Session是在内存中的,这就带来一些扩展性的问题。
CORS : 当我们想要扩展我们的应用,让我们的数据被多个移动设备使用时,我们必须考虑跨资源共
享问题。当使用AJAX调用从另一个域名下获取资源时,我们可能会遇到禁止请求的问题。
CSRF : 用户很容易受到CSRF攻击。

5.2. JWT与Session的差异
相同点是,它们都是存储用户信息;然而,Session是在服务器端的,而JWT是在客户端的。
Session方式存储用户信息的最大问题在于要占用大量服务器内存,增加服务器的开销。而JWT方式将用户状态分散到了客户端中,可以明显减轻服务端的内存压力。Session的状态是存储在服务器端,客户端只有session id;而Token的状态是存储在客户端。

5.3. 基于Token的身份认证是如何工作的
基于Token的身份认证是无状态的,服务器或者Session中不会存储任何用户信息。
没有会话信息意味着应用程序可以根据需要扩展和添加更多的机器,而不必担心用户登录的位置。

虽然这一实现可能会有所不同,但其主要流程如下:

  • 用户携带用户名和密码请求访问
  • 服务器校验用户凭据
  • 应用提供一个token给客户端
  • 客户端存储token,并且在随后的每一次请求中都带着它
  • 服务器校验token并返回数据

注意:

  • 每一次请求都需要token
  • Token应该放在请求header中
  • 我们还需要将服务器设置为接受来自所有域的请求,用 Access-Control-Allow-Origin: *

5.4. 用Token的好处
无状态和可扩展性 Tokens存储在客户端。完全无状态,可扩展。我们的负载均衡器可以将用户传递到任意服务器,因为在任何地方都没有状态或会话信息。
安全 Token不是Cookie。(The token, not a cookie.)每次请求的时候Token都会被发送。而且,由于没有Cookie被发送,还有助于防止CSRF攻击。即使在你的实现中将token存储到客户端的Cookie中,这个Cookie也只是一种存储机制,而非身份认证机制。没有基于会话的信息可以操作,因为我们没有会话!还有一点,token在一段时间以后会过期,这个时候用户需要重新登录。这有助于我们保持安全。还有一个概念叫token撤销,它允许我们根据相同的授权许可使特定的token甚至一组token无效。

5.5. JWT与OAuth的区别

  • OAuth2是一种授权框架 ,JWT是一种认证协议
  • 无论使用哪种方式切记用HTTPS来保证数据的安全性
  • OAuth2用在使用第三方账号登录的情况(比如使用weibo, qq, github登录某个app),而JWT是用在前后端分离, 需要简单的对后台API进行保护时使用。

浏览器的跨域请求问题

浏览器在什么情况下会发起options预检请求?

在非简单请求且跨域的情况下,浏览器会发起options预检请求。
Preflighted Requests是CORS中一种透明服务器验证机制。预检请求首先需要向另外一个域名的资源发送一个 HTTP OPTIONS 请求头,其目的就是为了判断实际发送的请求是否是安全的。
下面的情况需要进行预检

关于简单请求和复杂请求:
1 简单请求
简单请求需满足以下两个条件

  1. 请求方法是以下三种方法之一:
  • HEAD
  • GET
  • POST
  1. HTTP 的头信息不超出以下几种字段
  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type: 只限于 (application/x-www-form-urlencoded、multipart/form-data、text/plain)

2 复杂请求
非简单请求即是复杂请求
常见的复杂请求有:

  1. 请求方法为 PUT 或 DELETE
  2. Content-Type 字段类型为 application/json
  3. 添加额外的http header 比如access_token
    在跨域的情况下,非简单请求会先发起一次空body的OPTIONS请求,称为"预检"请求,用于向服务器请求权限信息,等预检请求被成功响应后,才发起真正的http请求。
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Title</title>
	<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
</head>
<body>
<button type="button" id="query">请求数据</button>
<div id="content" style="background-color: aquamarine; width: 300px;height: 5
</body>
<script type="text/javascript">
	$("#query").click(function () {
		$.ajax(
		{
			url:"http://127.0.0.1:8021/u/v1/user/list",
			dataType: "json",
			type: "get",
			beforeSend: function(request) {
			request.setRequestHeader("x-token", "eyJhbGciOiJIUzI1NiIsInR5cC
		},
			success: function (result) {
				console.log(result.data);
				$("#content").text(result.data)
			},
		error: function (data) {
			alert("请求出错")
			}
		}
		);
	});
</script>
</html>

阿里云发送短信

package main
import (
	"fmt"
	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
	"github.com/aliyun/alibaba-cloud-sdk-go/services/dysmsapi"
)
func main(){
	client, err := dysmsapi.NewClientWithAccessKey("cn-beijing", "xxxx", "xxx")
	if err != nil {
		panic(err)
	}
	request := requests.NewCommonRequest()
	request.Method = "POST"
	request.Scheme = "https" // https | http
	request.Domain = "dysmsapi.aliyuncs.com"
	request.Version = "2017-05-25"
	request.ApiName = "SendSms"
	request.QueryParams["RegionId"] = "cn-beijing"
	request.QueryParams["PhoneNumbers"] = "xxx" //⼿机号
	request.QueryParams["SignName"] = "xxx" //阿⾥云
	request.QueryParams["TemplateCode"] = "xxx" //阿⾥云的短信模板号 ⾃⼰设置
	request.QueryParams["TemplateParam"] = "{\"code\":" + "777777" + "}" //短信模板
	response, err := client.ProcessCommonRequest(request)
	fmt.Print( client.DoAction(request, response))
	// fmt.Print(response)
	if err != nil {
		fmt.Print(err.Error())
	}
	fmt.Printf("response is %#v\n", response)
	//json数据解析
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

虚幻引擎:如何在工程里面添加插件

1.在自己的项目中安装插件 在content目录下创建一个Plugins的文件,将插件文件放进去即可 2.在软件上安装,这样所有创建的项目都会带有此插件 将插件放在自己软件的这个目录下就好了

mediapipe流水线分析 二

目标检测 Graph 一 流水线上游输入处理 1 TfLiteConverterCalculator 将输入的数据转换成tensorflow api 支持的Tensor TfLiteTensor 并初始化相关输入输出节点 &#xff0c;该类的业务主要通过 interpreter std::unique_ptrtflite::Interpreter interpreter_ nullptr; 实现…

【漏洞复现】Apache_Shiro_1.2.4_反序列化漏洞(CVE-2016-4437)

感谢互联网提供分享知识与智慧&#xff0c;在法治的社会里&#xff0c;请遵守有关法律法规 文章目录 1.1、漏洞描述1.2、漏洞等级1.3、影响版本1.4、漏洞复现1、基础环境2、漏洞分析3、漏洞验证 说明内容漏洞编号CVE-2016-4437漏洞名称Apache_Shiro_1.2.4_反序列化漏洞漏洞评级…

Xmake v2.8.5 发布,支持链接排序和单元测试

Xmake 是一个基于 Lua 的轻量级跨平台构建工具。 它非常的轻量&#xff0c;没有任何依赖&#xff0c;因为它内置了 Lua 运行时。 它使用 xmake.lua 维护项目构建&#xff0c;相比 makefile/CMakeLists.txt&#xff0c;配置语法更加简洁直观&#xff0c;对新手非常友好&#x…

linux下IO模及其特点及select

ftp实现 模拟FTP核心原理&#xff1a;客户端连接服务器后&#xff0c;向服务器发送一个文件。文件名可以通过参数指定&#xff0c;服务器端接收客户端传来的文件&#xff08;文件名随意&#xff09;&#xff0c;如果文件不存在自动创建文件&#xff0c;如果文件存在&#xff0c…

Discourse 如何在 header 上添加 HTML

虽然现在大部分网站都开始支持使用 CDN 的网站校验了。 但还有些网站在你需要他们提供服务的时候要求使用 header 的 meta 数据校验。 Discourse 是可以轻松的实现上面的功能的。 添加方法 选择你的 Discourse 网站下的自定义。 然后在左侧选择你需要添加的主题。 为了方便…

AD9371 官方例程 NO-OS 主函数 headless 梳理(一)

AD9371 系列快速入口 AD9371ZCU102 移植到 ZCU106 &#xff1a; AD9371 官方例程构建及单音信号收发 ad9371_tx_jesd -->util_ad9371_xcvr接口映射&#xff1a; AD9371 官方例程之 tx_jesd 与 xcvr接口映射 AD9371 官方例程 时钟间的关系与生成 &#xff1a; AD9371 官方…

【Java 进阶篇】JSTL 详解

Java JSTL&#xff08;JavaServer Pages Standard Tag Library&#xff09;是用于简化在 JSP 页面上的开发工作的 Java 标签库。它提供了在 JSP 页面上使用的标准标签&#xff0c;可以帮助开发人员更轻松地访问和操作数据&#xff0c;而无需编写大量的 Java 代码。Java JSTL 是…

工业相机基本知识理解:工业相机IO接口,功耗和供电方式

I-input 相机接收外部信号&#xff0c;可用于触发相机&#xff08;硬触发&#xff09;&#xff0c;也可用于定制不同的 功能&#xff0c;例如使用不同信号宽度来改变相机的曝光时间。主要用于现场设 备控制相机使用&#xff0c;常常配合各种传感器使用 O-output 相机输出信号&a…

antd-vue + vue3 实现a-table动态增减行,通过a-from实现a-table行内输入验证

一、效果图 图一&#xff1a;校验效果 二、主要代码 注意&#xff1a; 1、form 与 table 绑定的是同一个数据 tableSource 并且是一个数据&#xff08;ElementUI 需要 对象包数组&#xff09; 2、form用的是 name 绑定 -> :name"[index, vlan_id]" 3、form-i…

【分布式事务】深入探索 Seata 的四种分布式事务解决方案的原理,优缺点以及在微服务中的实现

文章目录 前言一、XA 模式1.1 XA 模式原理1.2 XA 模式的优缺点及应用场景1.3 Seata XA 模式在微服务中的实现 二、AT 模式2.1 Seata AT 模式原理2.2 AT 模式的脏写问题和写隔离3.3 AT 模式的优缺点3.4 Seata AT 模式在微服务中的实现 三、TCC 模式3.1 TCC 模式原理3.2 Seata 的…

内窥镜项目

★ 手持pad内窥镜项目 项目描述&#xff1a;3D电子内窥镜软件项目是一个基于BS&#xff08;浏览器服务器&#xff09;架构的项目&#xff0c;旨在实现对内窥镜设备的远程控制和高级功能操作。该项目允许操作员使用平板电脑手动触摸屏上的按钮、外部按键或脚踏板 来控制内窥镜设…

初阶JavaEE(15)(Cookie 和 Session、理解会话机制 (Session)、实现用户登录网页、上传文件网页、常用的代码片段)

接上次博客&#xff1a;初阶JavaEE&#xff08;14&#xff09;表白墙程序-CSDN博客 Cookie 和 Session 你还记得我们之前提到的Cookie吗&#xff1f; Cookie是HTTP请求header中的一个属性&#xff0c;是一种用于在浏览器和服务器之间持久存储数据的机制&#xff0c;允许网站…

【C++】类和对象(一):什么是面向对象,访问限定符有哪些,类定义细节,结构体和类的关系。

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

机组 指令系统

机器指令 机器指令&#xff1a;每一条机器语言的语句 指令系统&#xff1a;全部机器指令的集合 指令的一般格式 指令由操作码和地址码两部分组成 操作码 作用&#xff1a;指明该指令要完成的操作 位数&#xff1a;反映机器的操作种类&#xff0c;即机器允许的指令条数 …

瞅瞅 Opencv:扫描图像

扫描图像查询表 一、概述二、图像矩阵如何存储在内存中?三、高效的方式四、迭代器(安全)方法五、带引用返回的动态地址计算六、核心功能七、性能差异 一、概述 让我们考虑一种简单的色彩还原方法。通过使用unsigned char C和c类型进行矩阵项存储&#xff0c;一个像素通道可以…

音视频技术开发周刊 | 318

每周一期&#xff0c;纵览音视频技术领域的干货。 新闻投稿&#xff1a;contributelivevideostack.com。 日程揭晓&#xff01;速览深圳站大会专题议程详解 LiveVideoStackCon 2023 音视频技术大会深圳站&#xff0c;保持着往届强大的讲师阵容以及高水准的演讲质量。两天的参会…

git commit规范提交

Git每次提交代码时&#xff0c;都要写Commit Message&#xff08;提交说明&#xff09;&#xff0c;通常情况下&#xff0c;Commit Message应该清晰明了&#xff0c;说明本次提交的目的和具体操作等。然而笔者工作多年来发现&#xff0c;有些公司对Commit Message没有明确的要求…

wpf Grid布局详解 `Auto` 和 `*` 是两种常见的设置方式 行或列占多个单元格,有点像excel里的合并单元格。使其余的列平均分配剩余的空间

比如只有行的界面 <Window x:Class"GenerateTokenApp.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schemas.microsoft.com/exp…

SpringCloudAlibaba——Sentinel

Sentinel也就是我们之前的Hystrix&#xff0c;而且比Hystrix功能更加的强大。Sentinel是分布式系统的流量防卫兵&#xff0c;以流量为切入点&#xff0c;从流量控制、流量路由、熔断降级等多个维度保护服务的稳定性。 Sentinel采用的是懒加载&#xff0c;这个接口被访问一次&a…