【微信公众平台】扫码登陆

文章目录

    • 前置准备
      • 测试号接口配置
    • 带参数二维码登陆
      • 获取access token
      • 获取Ticket
      • 拼装二维码Url
      • 编写接口返回二维码
      • 接收扫描带参数二维码事件
      • 编写登陆轮训接口
      • 测试页面
    • 网页授权二维码登陆
      • 生成ticket
      • 生成授权地址
      • 获取QR码
        • 静态文件支持
        • 编写获取QR码的接口
      • 接收重定向参数
      • 轮训登陆接口
      • 测试页面

前置准备

80/443端口能被联网访问:内网穿透、云服务器(测试号无需域名,ip即可)

申请测试号:微信公众平台 (qq.com)

测试号接口配置

开始开发 / 接入指南 (qq.com)

在这里插入图片描述

Token随便写入,用于判断请求是否来自微信服务器。

URl绑定需要编写一个接口用来接收微信的信息:

  • 接收微信GET请求传来四个参数 (后续事件推送也会POST到这个接口)

  • 返回参数中的Echostr参数

(gin框架)

wxgroup := r.Group("/wechat")
{wxgroup.Any("/message",controller.WxMessage)
}
r.Run(":80") // 80 端口启动服务
func WxMessage(ctx *gin.Context) {vp := &wxgo.VerifyParams{Signature: ctx.Query("signature"),Echostr:   ctx.Query("echostr"),Timestamp: ctx.Query("timestamp"),Nonce:     ctx.Query("nonce"),}// 判断请求是否来自微信服务器。if flag, _ := wechat.Wx.VerifySignature(*vp); flag {log.Println(vp)// 返回echostr字符串ctx.String(http.StatusOK, vp.Echostr)}
}

开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带参数如下表所示:

参数描述
signature微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
timestamp时间戳
nonce随机数
echostr随机字符串

开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。加密/校验流程如下:

1)将token、timestamp、nonce三个参数进行字典序排序

2)将三个参数字符串拼接成一个字符串进行sha1加密

3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信

检验signature的Golang示例代码:

// 签名验证
func (w *Wechat) VerifySignature(vp VerifyParams) (res bool, err error) {// 获取 token 字段, 为接口配置设置的token参数token, err := w.Cfg.GetToken()if err != nil {return false, err}// 构造匹配字段strs := []string{vp.Timestamp, vp.Nonce, token}// 按字典序排列后拼接成一个字符串sort.Strings(strs)str := strings.Join(strs, "")// 对拼接后的字符串进行 SHA1 加密hash := sha1.New()hash.Write([]byte(str))hashed := fmt.Sprintf("%x", hash.Sum(nil))// 加密结果与 signature 比较if hashed != vp.Signature {return false, errors.New("error: Signature mismatch")}return true, nil
}

将接口地址http://your_ip:80/wechat/message写入配置信息中的URL即可配置成功

带参数二维码登陆

账号管理 / 生成带参数的二维码 (qq.com)

流程:

  • 获取access token
  • 通过access token与一些请求参数获取二维码ticket
  • 通过ticket换取二维码url,返回给前端
  • 用户扫描二维码后事件信息推送到消息接口、将ticket放入redis
  • 前端用ticket轮训是否已经登陆

获取access token

开始开发 / 获取 Access token (qq.com)

  • 在测试号信息下获取:appID、appsecret

  • 用http client发送请求获取access token

接口调用请求说明

https请求方式: GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

参数说明

参数是否必须说明
grant_type获取access_token填写client_credential
appid第三方用户唯一凭证
secret第三方用户唯一凭证密钥,即appsecret

返回说明

正常情况下,微信会返回下述JSON数据包给公众号:

{"access_token":"ACCESS_TOKEN","expires_in":7200}

参数说明

参数说明
access_token获取到的凭证
expires_in凭证有效时间,单位:秒

错误时微信会返回错误码等信息,JSON数据包示例如下(该示例为AppID无效错误):

{"errcode":40013,"errmsg":"invalid appid"}
// 获取普通access token
func (w *Wechat) GetATReq() error {// 获取appID与appsecretappid, err := w.Cfg.GetAppid()if err != nil {return err}appsecret, err := w.Cfg.GetAppsecret()if err != nil {return err}// 构造请求地址// ReqUrl.ATUrl: "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",url := fmt.Sprintf(ReqUrl.ATUrl, appid, appsecret)// 发送 GET 请求获取响应client := &http.Client{}req, err := http.NewRequest("GET", url, nil)if err != nil {return err}resp, err := client.Do(req)if err != nil {return err}defer resp.Body.Close()// 读取响应body, err := io.ReadAll(resp.Body)if err != nil {return err}// 如果响应结果包含错误错误码,返回错误信息if strings.Contains(string(body), "errcode") {return fmt.Errorf("wechat response error: %s", string(body))}// 解析字符串err = json.Unmarshal(body, &w.LatestAT)if err != nil {return errors.New("json Unmarshal fail")}// 设置成功获取时间w.LatestAT.Time = time.Now()return nil
}
// wechat 用于保存at与配置信息
type Wechat struct {Cfg      *WechatCfgLatestAT *AT
}
// access token
type AT struct {AccessToken string `json:"access_token"`ExpiresTime int    `json:"expires_in"`Time        time.Time // access token获取时间
}
// 配置
type WechatCfg struct {Token       stringAppid       stringAppsecret   stringExpiresTime int
}
// 获取 accesstoken
func (w *Wechat) GetAccessToken() (at string, err error) {w.RefreshAT()return w.LatestAT.AccessToken, nil
}
// 刷新 LatestAT
func (w *Wechat) RefreshAT() error {// 先判断上次获取的是否超时duration := time.Since(w.LatestAT.Time)durationInSeconds := int(duration.Seconds())if durationInSeconds < (w.LatestAT.ExpiresTime - 600) {return nil}// 发送请求获取access tokenerr := w.GetATReq()return err
}

获取Ticket

创建二维码ticket

每次创建二维码ticket需要提供一个开发者自行设定的参数(scene_id),分别介绍临时二维码和永久二维码的创建二维码ticket过程。

临时二维码请求说明

http请求方式: POST URL: https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=TOKEN POST数据格式:json POST数据例子:{“expire_seconds”: 604800, “action_name”: “QR_SCENE”, “action_info”: {“scene”: {“scene_id”: 123}}} 或者也可以使用以下POST数据创建字符串形式的二维码参数:{“expire_seconds”: 604800, “action_name”: “QR_STR_SCENE”, “action_info”: {“scene”: {“scene_str”: “test”}}}

参数说明

参数说明
expire_seconds该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为60秒。
action_name二维码类型,QR_SCENE为临时的整型参数值,QR_STR_SCENE为临时的字符串参数值,QR_LIMIT_SCENE为永久的整型参数值,QR_LIMIT_STR_SCENE为永久的字符串参数值
action_info二维码详细信息
scene_id场景值ID,临时二维码时为32位非0整型,永久二维码时最大值为100000(目前参数只支持1–100000)
scene_str场景值ID(字符串形式的ID),字符串类型,长度限制为1到64
func (w *Wechat) GetQRTicketReq(codetype string, sceneId int) (string, error) {// 获取 access tokenat, err := w.GetAccessToken()if err != nil {return "", err}// 拼接请求地址url := fmt.Sprintf(ReqUrl.TicketUrl, at)// 构造请求数据data := &QRCodeReq{ExpireSeconds: w.Cfg.GetExpiresTime(),ActionName:    codetype, // QR码 类型ActionInfo: ActionInfo{Scene: Scene{SceneId: sceneId,},},}// 发送 post 请求获取响应client := &http.Client{}Jsondata, err := json.Marshal(&data)if err != nil {return "", err}reader := bytes.NewReader(Jsondata)req, err := http.NewRequest("POST", url, reader)if err != nil {return "", err}// 设置请求头 json格式req.Header.Set("Content-Type", "application/json")resp, err := client.Do(req)if err != nil {return "", err}defer resp.Body.Close()// 读取响应body, err := io.ReadAll(resp.Body)if err != nil {return "", err}var respData = QRCodeRes{}// 解析字符串err = json.Unmarshal(body, &respData)if err != nil {return "", errors.New("json unmarsha fail")}return respData.Ticket, nil
}

拼装二维码Url

通过ticket换取二维码

获取二维码ticket后,开发者可用ticket换取二维码图片。请注意,本接口无须登录态即可调用。

请求说明

HTTP GET请求(请使用https协议)https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=TICKET 提醒:TICKET记得进行UrlEncode

返回说明

ticket正确情况下,http 返回码是200,是一张图片,可以直接展示或者下载。

HTTP头(示例)如下: Accept-Ranges:bytes Cache-control:max-age=604800 Connection:keep-alive Content-Length:28026 Content-Type:image/jpg Date:Wed, 16 Oct 2013 06:37:10 GMT Expires:Wed, 23 Oct 2013 14:37:10 +0800 Server:nginx/1.4.1

错误情况下(如ticket非法)返回HTTP错误码404。

func (w *Wechat) GetQrImageUrl(ticket string) string {ticket = url.QueryEscape(ticket) // 进行UrlEncode// ReqUrl.QRImgUrl: "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s"url := fmt.Sprintf(ReqUrl.QRImgUrl,ticket)return url
}

编写接口返回二维码

wxgroup.GET("/getloginqr",controller.GetGZQrUrl)
// 获取公众号登陆二维码
func GetGZQrUrl(ctx *gin.Context) {// 获取ticketticket, _ := wechat.Wx.GetQRTicketReq("QR_STR_SCENE", 123)// 拼装二维码urlqrUrl := wechat.Wx.GetQrImageUrl(ticket)ctx.JSON(http.StatusOK, gin.H{"ticket": ticket,"qrUrl":  qrUrl,})
}

接收扫描带参数二维码事件

基础消息能力 / 接收事件推送 (qq.com)基础消息能力 / 接收事件推送 (qq.com)

用户扫描带场景值二维码时,可能推送以下两种事件:

  1. 如果用户还未关注公众号,则用户可以关注公众号,关注后微信会将带场景值关注事件推送给开发者。
  2. 如果用户已经关注公众号,则微信会将带场景值扫描事件推送给开发者。

推送XML数据包示例:

<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[FromUser]]></FromUserName><CreateTime>123456789</CreateTime><MsgType><![CDATA[event]]></MsgType><Event><![CDATA[subscribe]]></Event><EventKey><![CDATA[qrscene_123123]]></EventKey><Ticket><![CDATA[TICKET]]></Ticket>
</xml>

参数说明:

参数描述
ToUserName开发者微信号
FromUserName发送方账号(一个OpenID)
CreateTime消息创建时间 (整型)
MsgType消息类型,event
Event事件类型,subscribe(关注) / SCAN(之前已关注)
EventKey事件KEY值,qrscene_为前缀,后面为二维码的参数值
Ticket二维码的ticket,可用来换取二维码图片

在最开始时的消息接口添加消息处理逻辑,接收到扫描带参数二维码事件推送后将ticket和openid放入redis

func WxMessage(ctx *gin.Context) {vp := &wxgo.VerifyParams{Signature: ctx.Query("signature"),Echostr:   ctx.Query("echostr"),Timestamp: ctx.Query("timestamp"),Nonce:     ctx.Query("nonce"),}if flag, _ := wechat.Wx.VerifySignature(*vp); flag {log.Println(vp)ctx.String(http.StatusOK, vp.Echostr)}// 添加消息处理逻辑uEvent := &wxgo.UserEvent{}ctx.ShouldBindXML(&uEvent)fmt.Println(uEvent)if uEvent.Ticket != "" && (uEvent.Event == "SCAN" || uEvent.Event == "subscribe") {openid := uEvent.FromUserNamelog.Printf("ticket:%s, openid:%s", uEvent.Ticket, openid)// 将ticket和openid存入rediserr := redis.RedisClient.Set(uEvent.Ticket, openid, 60*time.Second).Err()if err != nil {log.Println(err.Error())}}
}
// 用户事件
type UserEvent struct {ToUserName   string `xml:"ToUserName"`   // 开发者微信号FromUserName string `xml:"FromUserName"` // 发送方账号(一个OpenID)CreateTime   int    `xml:"CreateTime"`   // 消息创建时间(整型)MsgType      string `xml:"MsgType"`      // 消息类型,event,Event        string `xml:"Event"`        // 事件类型,subscribe(关注), SCAN(已关注)EventKey     string `xml:"EventKey"`     // 事件KEY值,qrscene_为前缀,后面为二维码的参数值Ticket       string `xml:"Ticket"`       // 二维码的ticket,可用来换取二维码图片
}

编写登陆轮训接口

前端需要传递参数ticket询问是否登陆

// 登陆轮训接口
func CheckLogin(ctx *gin.Context) {ticket := ctx.Query("ticket")// 从redis中读取ticketopenid, err := redis.RedisClient.Get(ticket).Result()if err != nil {ctx.JSON(http.StatusOK, gin.H{"login": false,})} else {ctx.JSON(http.StatusOK, gin.H{"login":  true,"openid": openid,})}
}
wxgroup.GET("/checklogin",controller.CheckLogin)

测试页面

修改两处请求地址

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>登录页面</title><style>#qr-code {width: 200px;height: 200px;}</style>
</head>
<body><div id="qr-code-container"><img id="qr-code" src="#" alt="QR Code"></div><h1 id="login-status"></h1><h3 id="login-user"></h3><script>// 请求后端获取二维码图片地址function getQRCode() {// 修改请求地址fetch('http://your_ip/wechat/getloginqr') // 假设'/get_qr_code'是后端提供的接口地址.then(response => response.json()).then(data => {console.log(data.qrUrl)document.getElementById('qr-code').src = data.qrUrl;// 开始轮询检查登录状态// 根据问号分割URL,获取问号后面的部分var queryString = data.qrUrl.split('?')[1];// 根据等号分割查询字符串,获取ticket参数的值var ticket = queryString.split('=')[1];console.log(ticket);checkLoginStatus(ticket);}).catch(error => console.error('Error:', error));}// 轮询检查登录状态function checkLoginStatus(ticket) {// 修改请求地址url = 'http://your_ip/wechat/checklogin?ticket='+ ticketconsole.log(url)var checkLoginInterval = setInterval(() => {fetch(url) // 假设'/check_login_status'是后端提供的接口地址.then(response => response.json()).then(data => {console.log(data)if (data.login) {document.getElementById('login-status').innerText = '登录成功';document.getElementById('login-user').innerText = 'Openid: ' + data.openid; clearInterval(checkLoginInterval); // 登录成功后停止轮询} }).catch(error => console.error('Error:', error));}, 2000); // 每隔2秒轮询一次}// 页面加载完成后立即获取二维码window.onload = function() {getQRCode();};</script>
</body>
</html>

网页授权二维码登陆

微信网页开发 / 网页授权 (qq.com)

微信公众测试号不支持PC端网页登陆,但是可以模拟带参数二维码的登陆流程来实现类似的功能

流程:

  • 生成ticket作为授权地址的state参数
  • 编写接口作为授权地址都redirect_uri参数
  • 用授权地址生成QR码,并将QR码与ticket返回给前端
  • 用户扫描QR码将携带code和state参数重定向到接口
  • 接口接收code和state中的ticket参数,用code向微信服务器获取用户的access token和open id
  • 将ticket和openid存入redis
  • 前端用ticket轮训是否登陆

生成ticket

生成随机字符串

func GenerateRandomTicket(length int) string {rand.Seed(time.Now().UnixNano())var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")b := make([]rune, length)for i := range b {b[i] = letters[rand.Intn(len(letters))]}return string(b)
}

生成授权地址

在确保微信公众账号拥有授权作用域(scope参数)的权限的前提下(已认证服务号,默认拥有scope参数中的snsapi_base和snsapi_userinfo 权限),引导关注者打开如下页面:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

参数说明

参数是否必须说明
appid公众号的唯一标识
redirect_uri授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理
response_type返回类型,请填写code
scope应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 )
state重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节
#wechat_redirect无论直接打开还是做页面302重定向时候,必须带此参数
forcePopup强制此次授权需要用户弹窗确认;默认为false;需要注意的是,若用户命中了特殊场景下的静默授权逻辑,则此参数不生效
// 生成ticket
ticket := wxgo.GenerateRandomTicket(20)
// 生成授权地址
redirect_url := "http://39.101.78.10/wechat/accessusercode" // 微信授权后重定向地址,用于接收用户code
scope := "snsapi_base" //授权权限
oauthUrl := wechat.Wx.GetOauth2CodeUrl(redirect_url, scope, ticket) // 授权地址
// Oauth2CodeUrl: "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect"
func (w *Wechat) GetOauth2CodeUrl(redirectUrl string, scope string, state string) string {encodeUrl := url.QueryEscape(redirectUrl)url := fmt.Sprintf(ReqUrl.Oauth2CodeUrl, w.Cfg.Appid, encodeUrl, scope, state)return url
}

获取QR码

静态文件支持

qr码保存到服务器中,需要联网访问到

r.Static("/static","resource")
编写获取QR码的接口
wxgroup.GET("/getauthqr",controller.GetAuthQrUrl)
// 获取网页授权登陆二维码
func GetAuthQrUrl(ctx *gin.Context) {// 生成ticketticket := wxgo.GenerateRandomTicket(20)// 生成授权地址redirect_url := "http://your_ip/wechat/accessusercode" // 微信授权后重定向地址,用于接收用户codescope := "snsapi_base"                                  //授权权限oauthUrl := wechat.Wx.GetOauth2CodeUrl(redirect_url, scope, ticket)// 将授权地址生成QR码savePath := "./resource/image"err := wxgo.GenerateQrCode(oauthUrl, savePath, ticket)if err != nil {log.Fatal(err.Error())return}qrUrl := fmt.Sprintf("http://your_ip/static/image/%s.png", ticket)ctx.JSON(http.StatusOK, gin.H{"ticket": ticket,"qrUrl":  qrUrl,})
}

GenerateQrCode:

func GenerateQrCode(url string, savedir string, fname string) error {// "github.com/skip2/go-qrcode" 包qrcode, err := qrcode.New(url, qrcode.Highest)if err != nil {return err}qrcode.DisableBorder = true//保存成文件savepath := fmt.Sprintf("%s/%s.png", savedir, fname)err = qrcode.WriteFile(256, savepath)return err
}

接收重定向参数

如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE。

code说明:code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。

// 网页授权接收code
func AccessUserCode(ctx *gin.Context) {code := ctx.Query("code")ticke := ctx.Query("state")// 用code获取用户access tokenuat, _ := wechat.Wx.GetUserATReq(code)// 用access token获取用户信息uInfo, _ := wechat.Wx.GetUserInfoReq(uat)log.Printf(uInfo.NickName, uInfo.Headimgurl, uInfo.City)// 将ticket和openid放入redisredis.RedisClient.Set(ticke, uInfo.OpenId, 60*time.Second)// 重定向到成功/失败页面ctx.Redirect(http.StatusTemporaryRedirect, "http://your_ip/static/html/loginsucceed.html")
}

轮训登陆接口

复用带参数二维码的登陆轮训接口

测试页面

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>登录页面</title><style>#qr-code {width: 200px;height: 200px;}</style>
</head>
<body><div id="qr-code-container"><img id="qr-code" src="#" alt="QR Code"></div><h1 id="login-status"></h1><h3 id="login-user"></h3><script>// 请求后端获取二维码图片地址function getQRCode() {// 修改ipfetch('http://your_ip/wechat/getauthqr') .then(response => response.json()).then(data => {console.log(data.qrUrl)document.getElementById('qr-code').src = data.qrUrl;// 开始轮询检查登录状态var ticket = data.ticket;console.log(ticket);checkLoginStatus(ticket);}).catch(error => console.error('Error:', error));}// 轮询检查登录状态function checkLoginStatus(ticket) {// 修改ipurl = 'http://your_ip/wechat/checklogin?ticket='+ ticketconsole.log(url)var checkLoginInterval = setInterval(() => {fetch(url) // 假设'/check_login_status'是后端提供的接口地址.then(response => response.json()).then(data => {console.log(data)if (data.login) {document.getElementById('login-status').innerText = '登录成功';document.getElementById('login-user').innerText = 'Openid: ' + data.openid; clearInterval(checkLoginInterval); // 登录成功后停止轮询} }).catch(error => console.error('Error:', error));}, 2000); // 每隔2秒轮询一次}// 页面加载完成后立即获取二维码window.onload = function() {getQRCode();};</script>
</body>
</html>

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

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

相关文章

游泳耳机哪个牌子好?体验与口碑兼顾的4大游泳耳机汇总!

最近的天气越来越炎热了&#xff0c;许多人选择游泳作为一种既能锻炼身体又能享受清凉的活动。而随着科技的发展&#xff0c;越来越多的运动爱好者希望在游泳时也能享受到音乐的乐趣。因此&#xff0c;游泳耳机应运而生&#xff0c;成为市场上的热门产品。然而&#xff0c;面对…

使用PixVerse使用指定的角色生成视频

PixVerse 是一款可以将文字描述转换为高清视频的AI视频生成工具&#xff0c;它还支持直接生成原神角色的专属动画视频。以下是如何使用PixVerse使用指定的角色生成视频的步骤&#xff1a; 1. 点击PixVerse 网址 访问以下网址&#xff1a;https://app.pixverse.ai/create/vide…

jvm中的垃圾回收器

Jvm中的垃圾回收器 在jvm中&#xff0c;实现了多种垃圾收集器&#xff0c; 包括&#xff1a; 1.串行垃圾收集器 2.并行垃圾收集器 3.CMS&#xff08;并发&#xff09;垃圾收集器 4.G1垃圾收集器 1.串行垃圾回收器 效率低&#xff0c;使用较少 2.并行垃圾回收器 3.并发垃圾回…

软件估算的方法、过程、内容解读(估算指南)

4 估算方法 4.1 基于经验的方法 4.1.1 头脑风暴法 4.1.2 Delphi方法 4.1.2.1 过程图 4.1.2.2 组建评估组 4.1.2.3 系统介绍 4.1.2.4 系统分解与假设 4.1.2.5 设定偏差值 4.1.2.6 个人估计 4.1.2.7 估计结果汇总 4.1.2.8 估计差异讨论 4.1.2.9 结束 4.2 分解的方法…

Brainpan(VulnHub)

Brainpan 1、nmap 2、web渗透 随便看看 目录爆破 使用不同工具&#xff0c;不同字典进行爆破 9999端口分析 10000端口分析 字符串信息中&#xff0c;提示这个程序不能运行在DOS模式下&#xff0c;然后有32个A&#xff0c;还有一行关于复制字节到缓冲区的信息&#xff0c;还有一…

谈谈前端CSS盒模型

前言&#xff1a; 什么是CSS盒模型&#xff1f;盒模型的构造&#xff1f; 在前端开发中&#xff0c;CSS 盒模型是一种非常基础且核心的概念&#xff0c;它描述了文档中的每个元素被框架处理的方式。 ---- 打开浏览器开发者工具&#xff0c;查看Elements右侧下的Styles底部。 …

libVLC Ubuntu编译详解

1.简介 有时候&#xff0c;windows上开发不满足项目需求&#xff0c;需要移植到linux上&#xff0c;不得不自行编译libvlc&#xff0c;编译libvlc相对而言稍微麻烦一点。 我使用的操作系统&#xff1a;Ubuntu20.04 查看系统命令lsb_release -a libvlc版本&#xff1a; 3.0.1…

elment-plus 中 table 左对齐

elment-plus 中 table 左对齐 <el-tablev-loading"loading"class"flex-1 !h-auto":data"roleList":header-cell-style"{text-align: left }":row-style"{ height: 55px }":cell-style"{ text-align: left }"&…

Argus DBM 一款开源的数据库监控工具,无需部署Agent

开箱即用 无需部署Agent&#xff0c;开箱即用。我们使用JDBC直连您的数据库&#xff0c;输入IP端口账户密码即可。 全平台支持 Argus目前支持对Mysql, PostgreSQL, Oracle等数据库类型的监控&#xff0c;我们也会尽快适配其它数据库&#xff0c;致力于监控所有数据库。我们提…

AES 加解密(包含JS、VUE、JAVA、MySQL)工具方法

介绍 AES 是 Advanced Encryption Standard 的缩写&#xff0c;是最常见的对称加密算法。AES 在密码学中又称 Rijndael 加密法&#xff0c;是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的 DES&#xff0c;已经被多方分析且广为全世界所使用。 基本原理&#…

python 使用 Stable Diffusion API 生成图片示例

python 使用 Stable Diffusion API 生成图片示例 一、前言 在无聊的时候&#xff0c;想瞅一下sd生图遂做了一下 二、具体步骤 1、启动SD的api设置 注意&#xff0c;运行后的api相关功能可以在:http://127.0.0.1:7860/docs 查看 比如这一次我们要的生图的地址就是/sdapi/v1…

华为OD机试 - 结队编程(Java 2024 C卷 100分)

华为OD机试 2024C卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测试…

户外旅行摄影手册,旅游摄影完全攻略

一、资料前言 本套旅游摄影资料&#xff0c;大小295.47M&#xff0c;共有9个文件。 二、资料目录 《川藏线旅游摄影》杨桦.彩印版.pdf 《户外摄影指南》(Essential.Guide.to.Outdoor.photography.amateur)影印版.pdf 《旅行摄影大师班》(英)科尼什.扫描版.PDF 《旅行摄影…

数据结构面试常见问题:数组和链表的区别是什么?

数组 在编程的世界里&#xff0c;数组无疑是最基础的数据结构之一&#xff0c;它像一排整齐的房子&#xff0c;每个房子都有自己的门牌号&#xff0c;我们可以通过这个门牌号直接找到这个房子&#xff0c;无需从头至尾的逐一查找。这个门牌号&#xff0c;就是我们所说的索引&am…

一键下载全自动安装Office全家桶

概述 今天分享一款超级强大的工具软件&#xff0c;该软件实现了一键自动化下载、安装Office全家桶的功能。整套安装流程堪称行云流水&#xff0c;从下载到安装全自动&#xff0c;无需上手操作。只需要安装该工具软件后&#xff0c;点击安装即可。软件会自动识别不同的操作系统架…

Oracle——领先的企业级数据库解决方案

一、WHAT IS ORACLWE&#xff1a; ORACLE 数据库系统是美国 ORACLE 公司&#xff08;甲骨文&#xff09;提供的以分布式数据库为核心的一组软件产品&#xff0c;是目前最流行的客户/服务器(CLIENT/SERVER)或B/S 体系结构的数据库之一&#xff0c;ORACLE 通常应用于大型系统的数…

【计算机毕业设计】微信小程序:MHK自学平台的设计与实现——后附源码

&#x1f389;**欢迎来到我的技术世界&#xff01;**&#x1f389; &#x1f4d8; 博主小档案&#xff1a; 一名来自世界500强的资深程序媛&#xff0c;毕业于国内知名985高校。 &#x1f527; 技术专长&#xff1a; 在深度学习任务中展现出卓越的能力&#xff0c;包括但不限于…

MajorDoMo thumb.php 未授权RCE漏洞复现(CNVD-2024-02175)

0x01 产品简介 MajorDoMo是MajorDoMo社区的一个开源DIY智能家居自动化平台。 0x02 漏洞概述 MajorDoMo /modules/thumb/thumb.php接口处存在远程命令执行漏洞&#xff0c;未经身份验证的攻击者可利用此漏洞执行任意指令&#xff0c;获取服务器权限。 0x03 影响范围 MajorD…

ARM64架构栈帧回溯

文章目录 前言一、栈帧简介二、demo演示 前言 请参考&#xff1a;ARM64架构栈帧以及帧指针FP 一、栈帧简介 假设下列函数调用&#xff1a; funb() {func() }funa() {funb() }main() {funa() }main函数&#xff0c;funa函数&#xff0c;funb函数都不是叶子函数&#xff0c;其…

MySQL 的事务概念

事务概念 MySQL事务是一个或者多个的数据库操作&#xff0c;要么全部执行成功&#xff0c;要么全部失败回滚。 事务是通过事务日志来实现的&#xff0c;事务日志包括&#xff1a;redo log和undo log。 事务状态 事务有以下五种状态&#xff1a; 活动的部分提交的失败的中止的…