09-认证-自研微服务框架

认证

1. 开启https支持

func (e *Engine) RunTLS(addr, certFile, keyFile string) {
	err := http.ListenAndServeTLS(addr, certFile, keyFile, e.Handler())
	if err != nil {
		log.Fatal(err)
	}
}

1.1 测试

证书生成:

  • 安装openssl

    网站下载:http://slproweb.com/products/Win32OpenSSL.html

    (mac电脑 自行搜索安装)

  • 生成私钥文件

    ## 需要输入密码
    openssl genrsa -des3 -out ca.key 2048
    
  • 创建证书请求

    openssl req -new -key ca.key -out ca.csr
    
  • 生成ca.crt

    openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt
    

找到openssl.cnf 文件

  1. 打开copy_extensions = copy

  2. 打开 req_extensions = v3_req

  3. 找到[ v3_req ],添加 subjectAltName = @alt_names

  4. 添加新的标签 [ alt_names ] , 和标签字段

    [ alt_names ]
    IP.1 = 127.0.0.1
    DNS.1 = *.mszlu.com
    
  5. 生成证书私钥server.key

    openssl genpkey -algorithm RSA -out server.key
    
  6. 通过私钥server.key生成证书请求文件server.csr

    openssl req -new -nodes -key server.key -out server.csr -days 3650 -config ./openssl.cnf -extensions v3_req
    
  7. 生成SAN证书

    openssl x509 -req -days 365 -in server.csr -out server.pem -CA ca.crt -CAkey ca.key -CAcreateserial -extfile ./openssl.cnf -extensions v3_req
    
engine.RunTLS(":8118", "key/server.pem", "key/server.key")

postman测试

客户端需要生成对应的公钥和私钥

私钥:

openssl genpkey -algorithm RSA -out client.key

证书:

openssl req -new -nodes -key client.key -out client.csr -days 3650 -config ./openssl.cnf -extensions v3_req

SAN证书:

openssl x509 -req -days 365 -in client.csr -out client.pem -CA ca.crt -CAkey ca.key -CAcreateserial -extfile ./openssl.cnf -extensions v3_req

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

postman访问https://127.0.0.1:8118/user/jsonParam即可。

2. 认证支持

2.1 Basic认证

Basic 认证(基础认证),是最简单的认证方式。它简单地将用户名:密码进行 base64 编码后,放到 HTTP Authorization Header 中。HTTP 请求到达后端服务后,后端服务会解析出 Authorization Header 中的 base64 字符串,解码获取用户名和密码,并将用户名和密码跟数据库中记录的值进行比较,如果匹配则认证通过。
当然base64并不是加密技术,所以这种认证方式并不安全,即使密码进行加密,攻击者也可以进行重放攻击。

可以和SSL(可以理解为是HTTPS)一起使用保证其安全性

Authorization: Basic ${basic}
2.1.1 Context传递信息
type Context struct {
	W                     http.ResponseWriter
	R                     *http.Request
	engine                *Engine
	queryCache            url.Values
	formCache             url.Values
	DisallowUnknownFields bool
	IsValidate            bool
	StatusCode            int
	Logger                *msLog.Logger
	Keys                  map[string]any
	mu                    sync.RWMutex
}

func (c *Context) Set(key string, value string) {
	c.mu.Lock()
	if c.Keys == nil {
		c.Keys = make(map[string]any)
	}

	c.Keys[key] = value
	c.mu.Unlock()
}

func (c *Context) Get(key string) (value any, exists bool) {
	c.mu.RLock()
	value, exists = c.Keys[key]
	c.mu.RUnlock()
	return
}
2.1.2 实现

中间件:

package msgo

import (
	"encoding/base64"
	"net/http"
)

type Accounts struct {
	UnAuthHandler func(ctx *Context)
	Users         map[string]string
}

func (a *Accounts) BasicAuth(next HandlerFunc) HandlerFunc {
	return func(ctx *Context) {
		//判断请求中是否有Authorization的Header
		username, password, ok := ctx.R.BasicAuth()
		if !ok {
			a.UnAuthHandlers(ctx)
			return
		}
		pw, ok := a.Users[username]
		if !ok {
			a.UnAuthHandlers(ctx)
			return
		}
		if pw != password {
			a.UnAuthHandlers(ctx)
			return
		}
		ctx.Set("user", username)
		next(ctx)
	}
}

func (a *Accounts) UnAuthHandlers(ctx *Context) {
	if a.UnAuthHandler != nil {
		a.UnAuthHandler(ctx)
	} else {
		ctx.W.WriteHeader(http.StatusUnauthorized)
	}
}

func BasicAuth(username, password string) string {
	auth := username + ":" + password
	return base64.StdEncoding.EncodeToString([]byte(auth))
}

func (c *Context) SetBasicAuth(username, password string) {
	c.R.Header.Set("Authorization", "Basic "+basicAuth(username, password))
}

2.2 Digest认证

Digest 认证(摘要认证),是另一种 HTTP 认证协议,它与基本认证兼容,但修复了基本认证的严重缺陷。Digest 具有如下特点:

  • 绝不会用明文方式在网络上发送密码。
  • 可以有效防止恶意用户进行重放攻击。
  • 可以有选择地防止对报文内容的篡改。

完成摘要认证需要下面这四步:

  • 客户端请求服务端的资源。
  • 在客户端能够证明它知道密码从而确认其身份之前,服务端认证失败,返回401 Unauthorized,并返回WWW-Authenticate头,里面包含认证需要的信息。
  • 客户端根据WWW-Authenticate头中的信息,选择加密算法,并使用密码随机数 nonce,计算出密码摘要 response,并再次请求服务端。
  • 服务器将客户端提供的密码摘要与服务器内部计算出的摘要进行对比。如果匹配,就说明客户端知道密码,认证通过,并返回一些与授权会话相关的附加信息,放在 Authorization-Info 中。
    WWW-Authenticate头中包含的信息见下表:

在这里插入图片描述

虽然使用摘要可以避免密码以明文方式发送,一定程度上保护了密码的安全性,但是仅仅隐藏密码并不能保证请求是安全的。因为请求(包括密码摘要)仍然可以被截获,这样就可以重放给服务器,带来安全问题。

为了防止重放攻击,服务器向客户端发送了密码随机数 nonce,nonce 每次请求都会变化。客户端会根据 nonce 生成密码摘要,这种方式,可以使摘要随着随机数的变化而变化。服务端收到的密码摘要只对特定的随机数有效,而没有密码的话,攻击者就无法计算出正确的摘要,这样我们就可以防止重放攻击。

摘要认证可以保护密码,比基本认证安全很多。但摘要认证并不能保护内容,所以仍然要与 HTTPS 配合使用,来确保通信的安全。

2.3 Bearer 认证

Bearer 认证,也称为令牌认证,是一种 HTTP 身份验证方法。Bearer 认证的核心是 bearer token。bearer token 是一个加密字符串,通常由服务端根据密钥生成。客户端在请求服务端时,必须在请求头中包含Authorization: Bearer 。服务端收到请求后,解析出 ,并校验 的合法性,如果校验通过,则认证通过。跟Basic认证一样,Bearer 认证需要配合 HTTPS 一起使用,来保证认证安全性。

当前最流行的 token 编码方式是 JSON Web Token

2.3.1 JWT

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

简单点说就是一种认证机制。

JWT一般是这样一个字符串,分为三个部分,以"."隔开:

A.B.C

Header

A部分:

JWT第一部分是头部分,它是一个描述JWT元数据的Json对象

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

alg属性表示签名使用的算法,默认为HMAC SHA256(写为HS256),typ属性表示令牌的类型,JWT令牌统一写为JWT。

最后,使用Base64 URL算法将上述JSON对象转换为字符串保存。

Payload

B部分:

JWT第二部分是Payload,也是一个Json对象,除了包含需要传递的数据,还有七个默认的字段供选择。

分别是

iss:发行人exp:到期时间sub:主题aud:用户nbf:在此之前不可用iat:发布时间jti:JWT ID用于标识该JWT

{
    //默认字段
    "sub":"Go手写微服务框架教程",
    //自定义字段
    "name":"go框架",
    "isAdmin":"true",
    "loginTime":"2022-06-28 12:00:03"
}

这部分是可以被解密的,并不安全,所以不要存敏感信息。

使用Base64 URL算法转换为字符串保存

Signature

C部分:

JWT第三部分是签名。

首先需要指定一个secret,该secret仅仅保存在服务器中,保证不能让其他用户知道。然后使用Header指定的算法对Header和Payload进行计算,然后就得出一个签名哈希。也就是Signature。

那么Application Server如何进行验证呢?可以利用JWT前两段,用同一套哈希算法和同一个secret计算一个签名值,然后把计算出来的签名值和收到的JWT第三段比较,如果相同则认证通过。

使用JWT进行认证的步骤:

  • 客户端使用用户名和密码请求登录
  • 服务端收到请求后,会去验证用户名和密码。如果用户名和密码跟数据库记录不一致,则验证失败;如果一致则验证通过,服务端会签发一个 Token 返回给客户端
  • 客户端收到请求后会将 Token 缓存起来,比如放在浏览器 Cookie 中或者 LocalStorage 中,之后每次请求都会携带该 Token
  • 服务端收到请求后,会验证请求中的 Token,验证通过则进行业务逻辑处理,处理完后返回处理后的结果。
2.3.2 实现
go get -u github.com/golang-jwt/jwt/v4

func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool) {
	if path == "" {
		path = "/"
	}
	http.SetCookie(c.W, &http.Cookie{
		Name:     name,
		Value:    url.QueryEscape(value),
		MaxAge:   maxAge,
		Path:     path,
		Domain:   domain,
		SameSite: c.sameSite,
		Secure:   secure,
		HttpOnly: httpOnly,
	})
}

在这里插入图片描述

package token

import (
	"github.com/golang-jwt/jwt/v4"
	"github.com/mszlu521/msgo"
	"time"
)

type JwtHandler struct {
	//算法
	Alg string
	//登录认证
	Authenticator func(ctx *msgo.Context) (map[string]any, error)
	//过期时间 秒
	TimeOut time.Duration
	//时间函数 从此时开始计算过期
	TimeFuc func() time.Time
	//私钥
	PrivateKey string
	//key
	Key string
	//save cookie
	SendCookie     bool
	CookieName     string
	CookieMaxAge   int
	CookieDomain   string
	SecureCookie   bool
	CookieHTTPOnly bool
}

//登录处理,登录成功后,使用jwt生成token

func (j *JwtHandler) LoginHandler(ctx *msgo.Context) (string, error) {
	data, err := j.Authenticator(ctx)
	if err != nil {
		return "", err
	}
	if j.Alg == "" {
		j.Alg = "HS256"
	}
	signingMethod := jwt.GetSigningMethod(j.Alg)
	token := jwt.New(signingMethod)
	claims := token.Claims.(jwt.MapClaims)
	if data != nil {
		for key, value := range data {
			claims[key] = value
		}
	}
	if j.TimeFuc == nil {
		j.TimeFuc = func() time.Time {
			return time.Now()
		}
	}
	expire := j.TimeFuc().Add(j.TimeOut)
	claims["exp"] = expire.Unix()
	claims["iat"] = j.TimeFuc().Unix()
	var tokenString string
	var errToken error
	if j.usingPublicKeyAlgo() {
		tokenString, errToken = token.SignedString(j.PrivateKey)
	} else {
		tokenString, errToken = token.SignedString(j.Key)
	}
	if errToken != nil {
		return "", err
	}
	if j.SendCookie {
		if j.CookieName == "" {
			j.CookieName = "jwt_token"
		}
		if j.CookieMaxAge == 0 {
			j.CookieMaxAge = int(expire.Unix() - j.TimeFuc().Unix())
		}
		maxAge := j.CookieMaxAge
		ctx.SetCookie(j.CookieName, tokenString, maxAge, "/", j.CookieDomain, j.SecureCookie, j.CookieHTTPOnly)
	}
	return tokenString, nil
}

func (j *JwtHandler) usingPublicKeyAlgo() bool {
	switch j.Alg {
	case "RS256", "RS512", "RS384":
		return true
	}
	return false
}

退出登录

func (j *JwtHandler) LogoutHandler(ctx *msgo.Context) error {
	//清除cookie即可
	if j.SendCookie {
		if j.CookieName == "" {
			j.CookieName = JWTToken
		}
		ctx.SetCookie(j.CookieName, "", -1, "/", j.CookieDomain, j.SecureCookie, j.CookieHTTPOnly)
		return nil
	}
	return nil
}

刷新Token

package token

import (
	"github.com/golang-jwt/jwt/v4"
	"github.com/mszlu521/msgo"
	"time"
)

const JWTToken = "jwt_token"

type JwtHandler struct {
	//算法
	Alg string
	//登录认证
	Authenticator func(ctx *msgo.Context) (map[string]any, error)
	//过期时间 秒
	TimeOut        time.Duration
	RefreshTimeOut time.Duration
	//时间函数 从此时开始计算过期
	TimeFuc func() time.Time
	//私钥
	PrivateKey string
	//key
	Key string
	//save cookie
	SendCookie     bool
	CookieName     string
	CookieMaxAge   int
	CookieDomain   string
	SecureCookie   bool
	CookieHTTPOnly bool
}

type JWTResponse struct {
	Token        string
	RefreshToken string
}

//登录处理,登录成功后,使用jwt生成token

func (j *JwtHandler) LoginHandler(ctx *msgo.Context) (*JWTResponse, error) {
	data, err := j.Authenticator(ctx)
	if err != nil {
		return nil, err
	}
	if j.Alg == "" {
		j.Alg = "HS256"
	}
	signingMethod := jwt.GetSigningMethod(j.Alg)
	token := jwt.New(signingMethod)
	claims := token.Claims.(jwt.MapClaims)
	if data != nil {
		for key, value := range data {
			claims[key] = value
		}
	}
	if j.TimeFuc == nil {
		j.TimeFuc = func() time.Time {
			return time.Now()
		}
	}
	expire := j.TimeFuc().Add(j.TimeOut)
	claims["exp"] = expire.Unix()
	claims["iat"] = j.TimeFuc().Unix()
	var tokenString string
	var errToken error
	if j.usingPublicKeyAlgo() {
		tokenString, errToken = token.SignedString(j.PrivateKey)
	} else {
		tokenString, errToken = token.SignedString(j.Key)
	}
	if errToken != nil {
		return nil, errToken
	}
	if j.SendCookie {
		if j.CookieName == "" {
			j.CookieName = JWTToken
		}
		if j.CookieMaxAge == 0 {
			j.CookieMaxAge = int(expire.Unix() - j.TimeFuc().Unix())
		}
		maxAge := j.CookieMaxAge
		ctx.SetCookie(j.CookieName, tokenString, maxAge, "/", j.CookieDomain, j.SecureCookie, j.CookieHTTPOnly)
	}
	jr := &JWTResponse{}
	refreshToken, err := j.refreshToken(data)
	if err != nil {
		return nil, err
	}
	jr.Token = tokenString
	jr.RefreshToken = refreshToken
	return jr, nil
}

func (j *JwtHandler) LogoutHandler(ctx *msgo.Context) error {
	//清除cookie即可
	if j.SendCookie {
		if j.CookieName == "" {
			j.CookieName = JWTToken
		}
		ctx.SetCookie(j.CookieName, "", -1, "/", j.CookieDomain, j.SecureCookie, j.CookieHTTPOnly)
		return nil
	}
	return nil
}
func (j *JwtHandler) usingPublicKeyAlgo() bool {
	switch j.Alg {
	case "RS256", "RS512", "RS384":
		return true
	}
	return false
}

func (j *JwtHandler) refreshToken(data map[string]any) (string, error) {
	signingMethod := jwt.GetSigningMethod(j.Alg)
	token := jwt.New(signingMethod)
	claims := token.Claims.(jwt.MapClaims)
	if data != nil {
		for key, value := range data {
			claims[key] = value
		}
	}
	if j.TimeFuc == nil {
		j.TimeFuc = func() time.Time {
			return time.Now()
		}
	}
	expire := j.TimeFuc().Add(j.RefreshTimeOut)
	claims["exp"] = expire.Unix()
	claims["iat"] = j.TimeFuc().Unix()
	var tokenString string
	var errToken error
	if j.usingPublicKeyAlgo() {
		tokenString, errToken = token.SignedString(j.PrivateKey)
	} else {
		tokenString, errToken = token.SignedString(j.Key)
	}
	if errToken != nil {
		return "", errToken
	}
	return tokenString, nil
}

func (c *Context) GetCookie(name string) string {
	cookie, err := c.R.Cookie(name)
	if err != nil {
		return ""
	}
	if cookie != nil {
		return cookie.Value
	}
	return ""
}

func (j *JwtHandler) RefreshHandler(ctx *msgo.Context) (*JWTResponse, error) {
	var token string
	//检测refresh token是否过期
	storageToken, exists := ctx.Get(j.RefreshKey)
	if exists {
		token = storageToken.(string)
	}
	if token == "" {
		return nil, errors.New("token not exist")
	}
	t, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
		if j.usingPublicKeyAlgo() {
			return []byte(j.PrivateKey), nil
		}
		return []byte(j.Key), nil
	})
	if err != nil {
		return nil, err
	}
	claims := t.Claims.(jwt.MapClaims)
	//未过期的情况下 重新生成token和refreshToken
	if j.TimeFuc == nil {
		j.TimeFuc = func() time.Time {
			return time.Now()
		}
	}
	expire := j.TimeFuc().Add(j.RefreshTimeOut)
	claims["exp"] = expire.Unix()
	claims["iat"] = j.TimeFuc().Unix()

	var tokenString string
	var errToken error
	if j.usingPublicKeyAlgo() {
		tokenString, errToken = t.SignedString(j.PrivateKey)
	} else {
		tokenString, errToken = t.SignedString(j.Key)
	}
	if errToken != nil {
		return nil, errToken
	}
	if j.SendCookie {
		if j.CookieName == "" {
			j.CookieName = JWTToken
		}
		if j.CookieMaxAge == 0 {
			j.CookieMaxAge = int(expire.Unix() - j.TimeFuc().Unix())
		}
		maxAge := j.CookieMaxAge
		ctx.SetCookie(j.CookieName, tokenString, maxAge, "/", j.CookieDomain, j.SecureCookie, j.CookieHTTPOnly)
	}
	jr := &JWTResponse{}
	refreshToken, err := j.refreshToken(claims)
	if err != nil {
		return nil, err
	}
	jr.Token = tokenString
	jr.RefreshToken = refreshToken
	return jr, nil
}
2.3.3 测试

	g.Get("/login", func(ctx *msgo.Context) {

		jwt := &token.JwtHandler{}
		jwt.Key = []byte("123456")
		jwt.SendCookie = true
		jwt.TimeOut = 10 * time.Minute
		jwt.Authenticator = func(ctx *msgo.Context) (map[string]any, error) {
			data := make(map[string]any)
			data["userId"] = 1
			return data, nil
		}
		token, err := jwt.LoginHandler(ctx)
		if err != nil {
			log.Println(err)
			ctx.JSON(http.StatusOK, err.Error())
			return
		}
		ctx.JSON(http.StatusOK, token)
	})
2.3.4 实现jwt认证中间件

func (j *JwtHandler) AuthInterceptor(next msgo.HandlerFunc) msgo.HandlerFunc {
	return func(ctx *msgo.Context) {
		//
		if j.Header == "" {
			j.Header = "Authorization"
		}
		token := ctx.R.Header.Get(j.Header)
		if token == "" {
			if j.SendCookie {
				token = ctx.GetCookie(j.CookieName)
				if token == "" {
					if j.AuthHandler == nil {
						ctx.W.WriteHeader(http.StatusUnauthorized)
					} else {
						j.AuthHandler(ctx, nil)
					}
					return
				}
			}
		}
		t, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
			if j.usingPublicKeyAlgo() {
				return []byte(j.PrivateKey), nil
			}
			return []byte(j.Key), nil
		})
		if err != nil {
			if j.AuthHandler == nil {
				ctx.W.WriteHeader(http.StatusUnauthorized)
			} else {
				j.AuthHandler(ctx, err)
			}
			return
		}
		ctx.Set("claims", t.Claims.(jwt.MapClaims))
		next(ctx)
	}
}

jwt := token.JwtHandler{
		Key: []byte("123456"),
	}
	engine.Use(jwt.AuthInterceptor)

e {
token = ctx.GetCookie(j.CookieName)
if token == “” {
if j.AuthHandler == nil {
ctx.W.WriteHeader(http.StatusUnauthorized)
} else {
j.AuthHandler(ctx, nil)
}
return
}
}
}
t, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
if j.usingPublicKeyAlgo() {
return []byte(j.PrivateKey), nil
}
return []byte(j.Key), nil
})
if err != nil {
if j.AuthHandler == nil {
ctx.W.WriteHeader(http.StatusUnauthorized)
} else {
j.AuthHandler(ctx, err)
}
return
}
ctx.Set(“claims”, t.Claims.(jwt.MapClaims))
next(ctx)
}
}


~~~go
jwt := token.JwtHandler{
		Key: []byte("123456"),
	}
	engine.Use(jwt.AuthInterceptor)

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

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

相关文章

k8s.gcr.io/pause:3.2镜像丢失解决

文章目录 前言错误信息临时解决推荐解决onetwo 前言 使用Kubernetes(k8s)时遇到了镜像拉取的问题,导致Pod沙盒创建失败。错误显示在尝试从k8s.gcr.io拉取pause:3.2镜像时遇到了超时问题,这通常是因为网络问题或者镜像仓库服务器的…

【Go语言】Go语言中的指针

Go语言中的指针 变量的本质是对一块内存空间的命名,我们可以通过引用变量名来使用这块内存空间存储的值,而指针则是用来指向这些变量值所在内存地址的值。 注:变量值所在内存地址的值不等于该内存地址存储的变量值。 Go语言中,…

[CSS]文字旁边的竖线以及布局知识

场景:文字前面常见加竖线。 .center-title { 常见内容color: #FFF;font-family: "Source Han Sans CN";font-size: 50px;font-style: normal;font-weight: 700;line-height: normal;position: relative; 要定位left: 16px; 这里是想拉开间距margin-b…

vmware中Numlock和caplock一直闪烁(更新时间24/2/28)

问题复现: 分析原因是:宿主机和vm虚拟机的这两个键未同步导致的异常 解决方法:将鼠标移动到点击虚拟机窗口以外的地方,按这两个键将其设置为打开状态即可解决

科技赋能,MTW400A为农村饮水安全打通“最后一公里”

日前,山东省政府纵深推进国家省级水网先导区建设,持续深化“水网”行动,着力构筑水安全保障网、水民生服务网、水生态保护网,建设水美乡村示范带、内河航运示范带、文旅融合示范带、绿色发展示范带,推动形成“三网四带…

微服务架构 SpringCloud

单体应用架构 将项目所有模块(功能)打成jar或者war,然后部署一个进程--医院挂号系统; > 优点: > 1:部署简单:由于是完整的结构体,可以直接部署在一个服务器上即可。 > 2:技术单一:项目不需要复杂的技术栈,往往一套熟悉的…

目标检测——车辆数据集

一、背景介绍 VOC2005车辆数据集是PASCAL VOC挑战赛中的一个重要组成部分,该挑战赛始于2005年,旨在为计算机视觉领域的研究者和开发者提供一个统一的、标准化的评估平台。PASCAL VOC挑战赛不仅推动了图像识别、目标检测、图像分割等技术的发展&#xff…

textbox跨线程写入

实现实例1 实现效果 跨线程实现 // 委托,用于定义在UI线程上执行的方法签名 //public delegate void SetTextCallback(string text);public void textBoxText(string text){// 检查调用线程是否是创建控件的线程 if (textBox1.InvokeRequired){// 如果不是&#…

2.12冯诺依曼体系,各功能部件作用,简要工作流程

1)计算机由哪几部分组成?以哪部分为中心?2)主频高的CPU一定比主频低的CPU快吗?为什么?3)翻译程序、汇编程序、编译程序、解释程序有什么差别?各自的特性是什么?4)不同级别的语言编写的程序有什么区别&#…

华为OD技术面试案例3-2024年

技术一面: 1.手撕代码,算法题: 【最小路径和】 手撕代码通过,面试官拍了照片 2.深挖项目,做过的自认为最好的一个项目,描述做过的项目的工作过程,使用到哪些技术? 技术二面&…

单细胞Seurat - 细胞聚类(3)

本系列持续更新Seurat单细胞分析教程,欢迎关注! 维度确定 为了克服 scRNA-seq 数据的任何单个特征中广泛的技术噪音,Seurat 根据 PCA 分数对细胞进行聚类,每个 PC 本质上代表一个“元特征”,它结合了相关特征集的信息。…

枚举(蓝桥练习)

目录 一、枚举算法介绍 二、解空间的类型 三、循环枚举解空间 四、例题 (一、反倍数) (二、特别数的和) (三、找到最多的数) (四、小蓝的漆房) (五、小蓝和小桥的…

【JGit 】一个完整的使用案例

需求 生成一系列结构相同的项目代码,将这些项目的代码推送至一个指定的 Git 仓库,每个项目独占一个分支。 推送时若仓库不存在,则自动创建仓库。 分析 生成代码使用 Java 程序模拟,每个项目中模拟三个文件。Project.cpp 、Pro…

CUMT---图像处理与视觉感知---期末复习重点

文章目录 一、概述 本篇文章会随课程的进行持续更新中! 一、概述 1. 图像的概念及分类。  图像是用各种观测系统以不同形式和手段观测客观世界而获得的、可以直接或间接作用于人的视觉系统而产生的视知觉实体。  图像分为模拟图像和数字图像:(1) 模拟图…

Leetcode 第 385 场周赛题解

Leetcode 第 385 场周赛题解 Leetcode 第 385 场周赛题解题目1:3042. 统计前后缀下标对 I思路代码复杂度分析 题目2:3043. 最长公共前缀的长度思路代码复杂度分析 题目3:3044. 出现频率最高的质数思路代码复杂度分析 题目4:3045. …

【新书推荐】8.4 逻辑运算指令

本节内容:逻辑运算指令。8086 CPU逻辑运算指令包括NOT、AND、OR、XOR,除NOT指令外,均有两个操作数。逻辑运算指令影响状态标志位。 ■否操作指令NOT指令格式:NOT OPRD。将OPRD取反,然后送回OPRD。操作数可以是8位/16位…

Jetson系统烧录环境搭建

一 序言 Jetson 系列产品烧录系统的方法一般有两种,一种为使用 NVIDIA 官方提供 的 SDK manager 软件给 Jetson 设备烧录系统(请查看说明文档《Jetson 产品使用 SDKmanager 烧录系统》)。另一种即为当前文档所描述的,在安装 Ubun…

GZ036 区块链技术应用赛项赛题第10套

2023年全国职业院校技能大赛 高职组 “区块链技术应用” 赛项赛卷(10卷) 任 务 书 参赛队编号: 背景描述 养老保险是对于老年人的最基本的生活保障。各种数据显示,当前的养老金市场规模庞大。2016年美国的养老金资…

403页面绕过

403页面绕过 文章目录 403页面绕过姿势一: 端口利用姿势二:修改HOST姿势三:覆盖请求URL姿势四:Referer标头绕过姿势五:代理IP姿势六:扩展名绕过 姿势一: 端口利用 拿到客户给的地址后,首先进行信息收集。端…

MySQL存储引擎及索引机制

MySQL技术——存储引擎和索引机制 一、存储引擎概述二、常见存储引擎的区别三、索引机制四、索引的底层实现原理五、InnoDB主键和二级索引六、聚集索引和非聚集索引七、哈希索引八、InnoDB的自适应哈希索引九、索引常见问题十、慢查询日志总结 一、存储引擎概述 插件式存储引擎…