feat(wechat): 重构小程序登录接口,实现自动生成用户信息和头像
- 移除微信用户信息解密相关代码,改为系统自动生成用户名和头像 - 添加用户信息存储功能,使用openID作为用户ID - 集成govatar和namegenerator库生成用户头像和随机用户名 - 添加token生成功能,返回给客户端用于后续认证 - 更新swagger文档,反映接口变更
This commit is contained in:
parent
e4d4258918
commit
a4e532c6b6
89
docs/docs.go
89
docs/docs.go
@ -1165,7 +1165,7 @@ const docTemplate = `{
|
|||||||
},
|
},
|
||||||
"/api/wechat/miniprogram/login": {
|
"/api/wechat/miniprogram/login": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "通过AppID和code获取用户的openid和session_key",
|
"description": "通过AppID和code获取用户的openid,系统自动生成用户名和头像",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@ -2378,49 +2378,6 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"wechat.DecryptedUserInfo": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"avatarUrl": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"city": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"country": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"gender": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"nickName": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"openId": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"province": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"unionId": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"watermark": {
|
|
||||||
"$ref": "#/definitions/wechat.Watermark"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"wechat.Watermark": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"appid": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"timestamp": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"wechat.generateQRCodeRequest": {
|
"wechat.generateQRCodeRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
@ -2469,39 +2426,15 @@ const docTemplate = `{
|
|||||||
"description": "小程序AppID",
|
"description": "小程序AppID",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"encrypted_data": {
|
|
||||||
"description": "加密数据(可选)",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"iv": {
|
|
||||||
"description": "初始向量(可选)",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"js_code": {
|
"js_code": {
|
||||||
"description": "登录时获取的code",
|
"description": "登录时获取的code",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
|
||||||
"raw_data": {
|
|
||||||
"description": "原始数据(可选,用于签名验证)",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"signature": {
|
|
||||||
"description": "签名(可选,用于验证数据完整性)",
|
|
||||||
"type": "string"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"wechat.miniprogramLoginResponse": {
|
"wechat.miniprogramLoginResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"decrypted_data": {
|
|
||||||
"description": "解密后的用户信息(可选)",
|
|
||||||
"allOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/wechat.DecryptedUserInfo"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"message": {
|
"message": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@ -2509,16 +2442,28 @@ const docTemplate = `{
|
|||||||
"description": "用户唯一标识",
|
"description": "用户唯一标识",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"session_key": {
|
|
||||||
"description": "会话密钥",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"success": {
|
"success": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"token": {
|
||||||
|
"description": "登录token",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"unionid": {
|
"unionid": {
|
||||||
"description": "用户在开放平台的唯一标识符",
|
"description": "用户在开放平台的唯一标识符",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"user_avatar": {
|
||||||
|
"description": "用户头像",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"description": "用户ID",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"user_name": {
|
||||||
|
"description": "用户昵称",
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1157,7 +1157,7 @@
|
|||||||
},
|
},
|
||||||
"/api/wechat/miniprogram/login": {
|
"/api/wechat/miniprogram/login": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "通过AppID和code获取用户的openid和session_key",
|
"description": "通过AppID和code获取用户的openid,系统自动生成用户名和头像",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
@ -2370,49 +2370,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"wechat.DecryptedUserInfo": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"avatarUrl": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"city": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"country": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"gender": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"nickName": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"openId": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"province": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"unionId": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"watermark": {
|
|
||||||
"$ref": "#/definitions/wechat.Watermark"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"wechat.Watermark": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"appid": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"timestamp": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"wechat.generateQRCodeRequest": {
|
"wechat.generateQRCodeRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
@ -2461,39 +2418,15 @@
|
|||||||
"description": "小程序AppID",
|
"description": "小程序AppID",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"encrypted_data": {
|
|
||||||
"description": "加密数据(可选)",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"iv": {
|
|
||||||
"description": "初始向量(可选)",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"js_code": {
|
"js_code": {
|
||||||
"description": "登录时获取的code",
|
"description": "登录时获取的code",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
|
||||||
"raw_data": {
|
|
||||||
"description": "原始数据(可选,用于签名验证)",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"signature": {
|
|
||||||
"description": "签名(可选,用于验证数据完整性)",
|
|
||||||
"type": "string"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"wechat.miniprogramLoginResponse": {
|
"wechat.miniprogramLoginResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"decrypted_data": {
|
|
||||||
"description": "解密后的用户信息(可选)",
|
|
||||||
"allOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/wechat.DecryptedUserInfo"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"message": {
|
"message": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@ -2501,16 +2434,28 @@
|
|||||||
"description": "用户唯一标识",
|
"description": "用户唯一标识",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"session_key": {
|
|
||||||
"description": "会话密钥",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"success": {
|
"success": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"token": {
|
||||||
|
"description": "登录token",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"unionid": {
|
"unionid": {
|
||||||
"description": "用户在开放平台的唯一标识符",
|
"description": "用户在开放平台的唯一标识符",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"user_avatar": {
|
||||||
|
"description": "用户头像",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"description": "用户ID",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"user_name": {
|
||||||
|
"description": "用户昵称",
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -695,34 +695,6 @@ definitions:
|
|||||||
description: 真实图片地址
|
description: 真实图片地址
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
wechat.DecryptedUserInfo:
|
|
||||||
properties:
|
|
||||||
avatarUrl:
|
|
||||||
type: string
|
|
||||||
city:
|
|
||||||
type: string
|
|
||||||
country:
|
|
||||||
type: string
|
|
||||||
gender:
|
|
||||||
type: integer
|
|
||||||
nickName:
|
|
||||||
type: string
|
|
||||||
openId:
|
|
||||||
type: string
|
|
||||||
province:
|
|
||||||
type: string
|
|
||||||
unionId:
|
|
||||||
type: string
|
|
||||||
watermark:
|
|
||||||
$ref: '#/definitions/wechat.Watermark'
|
|
||||||
type: object
|
|
||||||
wechat.Watermark:
|
|
||||||
properties:
|
|
||||||
appid:
|
|
||||||
type: string
|
|
||||||
timestamp:
|
|
||||||
type: integer
|
|
||||||
type: object
|
|
||||||
wechat.generateQRCodeRequest:
|
wechat.generateQRCodeRequest:
|
||||||
properties:
|
properties:
|
||||||
app_id:
|
app_id:
|
||||||
@ -754,44 +726,37 @@ definitions:
|
|||||||
app_id:
|
app_id:
|
||||||
description: 小程序AppID
|
description: 小程序AppID
|
||||||
type: string
|
type: string
|
||||||
encrypted_data:
|
|
||||||
description: 加密数据(可选)
|
|
||||||
type: string
|
|
||||||
iv:
|
|
||||||
description: 初始向量(可选)
|
|
||||||
type: string
|
|
||||||
js_code:
|
js_code:
|
||||||
description: 登录时获取的code
|
description: 登录时获取的code
|
||||||
type: string
|
type: string
|
||||||
raw_data:
|
|
||||||
description: 原始数据(可选,用于签名验证)
|
|
||||||
type: string
|
|
||||||
signature:
|
|
||||||
description: 签名(可选,用于验证数据完整性)
|
|
||||||
type: string
|
|
||||||
required:
|
required:
|
||||||
- app_id
|
- app_id
|
||||||
- js_code
|
- js_code
|
||||||
type: object
|
type: object
|
||||||
wechat.miniprogramLoginResponse:
|
wechat.miniprogramLoginResponse:
|
||||||
properties:
|
properties:
|
||||||
decrypted_data:
|
|
||||||
allOf:
|
|
||||||
- $ref: '#/definitions/wechat.DecryptedUserInfo'
|
|
||||||
description: 解密后的用户信息(可选)
|
|
||||||
message:
|
message:
|
||||||
type: string
|
type: string
|
||||||
openid:
|
openid:
|
||||||
description: 用户唯一标识
|
description: 用户唯一标识
|
||||||
type: string
|
type: string
|
||||||
session_key:
|
|
||||||
description: 会话密钥
|
|
||||||
type: string
|
|
||||||
success:
|
success:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
token:
|
||||||
|
description: 登录token
|
||||||
|
type: string
|
||||||
unionid:
|
unionid:
|
||||||
description: 用户在开放平台的唯一标识符
|
description: 用户在开放平台的唯一标识符
|
||||||
type: string
|
type: string
|
||||||
|
user_avatar:
|
||||||
|
description: 用户头像
|
||||||
|
type: string
|
||||||
|
user_id:
|
||||||
|
description: 用户ID
|
||||||
|
type: string
|
||||||
|
user_name:
|
||||||
|
description: 用户昵称
|
||||||
|
type: string
|
||||||
type: object
|
type: object
|
||||||
info:
|
info:
|
||||||
contact: {}
|
contact: {}
|
||||||
@ -1542,7 +1507,7 @@ paths:
|
|||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 通过AppID和code获取用户的openid和session_key
|
description: 通过AppID和code获取用户的openid,系统自动生成用户名和头像
|
||||||
parameters:
|
parameters:
|
||||||
- description: 请求参数
|
- description: 请求参数
|
||||||
in: body
|
in: body
|
||||||
|
|||||||
2
go.mod
2
go.mod
@ -63,6 +63,7 @@ require (
|
|||||||
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
|
github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
@ -79,6 +80,7 @@ require (
|
|||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/o1egl/govatar v0.4.1 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect
|
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect
|
||||||
github.com/prometheus/common v0.44.0 // indirect
|
github.com/prometheus/common v0.44.0 // indirect
|
||||||
|
|||||||
9
go.sum
9
go.sum
@ -119,6 +119,7 @@ github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnht
|
|||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ=
|
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ=
|
||||||
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w=
|
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@ -241,6 +242,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
|||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||||
|
github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e h1:XmA6L9IPRdUr28a+SK/oMchGgQy159wvzXA5tJ7l+40=
|
||||||
|
github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e/go.mod h1:AFIo+02s+12CEg8Gzz9kzhCbmbq6JcKNrhHffCGA9z4=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
@ -318,6 +321,8 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
|
|||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
|
github.com/o1egl/govatar v0.4.1 h1:RRzAxm52WpZMSEoWgAXrTcXWKhIUPpgpI54KP+UI0Ew=
|
||||||
|
github.com/o1egl/govatar v0.4.1/go.mod h1:cSBJjpgYiKmQ8E+C4zNBcsbuDwy9UH4HS8BwE4m6JmQ=
|
||||||
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
||||||
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
|
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
|
||||||
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||||
@ -344,10 +349,12 @@ github.com/rs/cors v1.8.1 h1:OrP+y5H+5Md29ACTA9imbALaKHwOSUZkcizaG0LT5ow=
|
|||||||
github.com/rs/cors v1.8.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
|
github.com/rs/cors v1.8.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
|
||||||
github.com/rs/cors/wrapper/gin v0.0.0-20231013084403-73f81b45a644 h1:BBwREPixt0iE77C9z7DOenoeh5OGFrzyL1cWOp5oQTs=
|
github.com/rs/cors/wrapper/gin v0.0.0-20231013084403-73f81b45a644 h1:BBwREPixt0iE77C9z7DOenoeh5OGFrzyL1cWOp5oQTs=
|
||||||
github.com/rs/cors/wrapper/gin v0.0.0-20231013084403-73f81b45a644/go.mod h1:gmu40DuK3SLdKUzGOUofS3UDZwyeOUy6ZjPPuaALatw=
|
github.com/rs/cors/wrapper/gin v0.0.0-20231013084403-73f81b45a644/go.mod h1:gmu40DuK3SLdKUzGOUofS3UDZwyeOUy6ZjPPuaALatw=
|
||||||
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ=
|
github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ=
|
||||||
github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U=
|
github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U=
|
||||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||||
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
||||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
@ -395,6 +402,7 @@ github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6
|
|||||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
|
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
@ -800,6 +808,7 @@ gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
|||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
|||||||
@ -94,7 +94,7 @@ func (h *handler) LatestMessageByAppId() core.HandlerFunc {
|
|||||||
|
|
||||||
// 分页查询指定小程序的最新消息
|
// 分页查询指定小程序的最新消息
|
||||||
resultData, err := query.
|
resultData, err := query.
|
||||||
Order(h.readDB.AppMessageLog.SendTime.Desc()).
|
Order(h.readDB.AppMessageLog.SendTime.Asc()).
|
||||||
Offset((req.Page - 1) * req.PageSize).
|
Offset((req.Page - 1) * req.PageSize).
|
||||||
Limit(req.PageSize).
|
Limit(req.PageSize).
|
||||||
Find()
|
Find()
|
||||||
|
|||||||
@ -87,7 +87,7 @@ func (h *handler) AppMessagePageList() core.HandlerFunc {
|
|||||||
countQueryDB := query.Session(&gorm.Session{})
|
countQueryDB := query.Session(&gorm.Session{})
|
||||||
|
|
||||||
resultData, err := listQueryDB.
|
resultData, err := listQueryDB.
|
||||||
Order(h.readDB.AppMessageLog.SendTime.Desc()).
|
Order(h.readDB.AppMessageLog.SendTime.Asc()).
|
||||||
Limit(req.PageSize).
|
Limit(req.PageSize).
|
||||||
Offset((req.Page - 1) * req.PageSize).
|
Offset((req.Page - 1) * req.PageSize).
|
||||||
Find()
|
Find()
|
||||||
|
|||||||
@ -86,7 +86,7 @@ func (h *handler) AppMessagePageList() core.HandlerFunc {
|
|||||||
countQueryDB := query.Session(&gorm.Session{})
|
countQueryDB := query.Session(&gorm.Session{})
|
||||||
|
|
||||||
resultData, err := listQueryDB.
|
resultData, err := listQueryDB.
|
||||||
Order(h.readDB.AppMessageLog.SendTime.Desc()).
|
Order(h.readDB.AppMessageLog.SendTime.Asc()).
|
||||||
Limit(req.PageSize).
|
Limit(req.PageSize).
|
||||||
Offset((req.Page - 1) * req.PageSize).
|
Offset((req.Page - 1) * req.PageSize).
|
||||||
Find()
|
Find()
|
||||||
|
|||||||
@ -1,33 +1,39 @@
|
|||||||
package wechat
|
package wechat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"image/png"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/goombaio/namegenerator"
|
||||||
|
"github.com/o1egl/govatar"
|
||||||
|
|
||||||
"mini-chat/internal/code"
|
"mini-chat/internal/code"
|
||||||
"mini-chat/internal/pkg/core"
|
"mini-chat/internal/pkg/core"
|
||||||
"mini-chat/internal/pkg/httpclient"
|
"mini-chat/internal/pkg/httpclient"
|
||||||
"mini-chat/internal/pkg/validation"
|
"mini-chat/internal/pkg/validation"
|
||||||
"mini-chat/internal/pkg/wechat"
|
"mini-chat/internal/repository/mysql/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
type miniprogramLoginRequest struct {
|
type miniprogramLoginRequest struct {
|
||||||
AppID string `json:"app_id" binding:"required"` // 小程序AppID
|
AppID string `json:"app_id" binding:"required"` // 小程序AppID
|
||||||
JSCode string `json:"js_code" binding:"required"` // 登录时获取的code
|
JSCode string `json:"js_code" binding:"required"` // 登录时获取的code
|
||||||
EncryptedData string `json:"encrypted_data,omitempty"` // 加密数据(可选)
|
|
||||||
IV string `json:"iv,omitempty"` // 初始向量(可选)
|
|
||||||
RawData string `json:"raw_data,omitempty"` // 原始数据(可选,用于签名验证)
|
|
||||||
Signature string `json:"signature,omitempty"` // 签名(可选,用于验证数据完整性)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type miniprogramLoginResponse struct {
|
type miniprogramLoginResponse struct {
|
||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
OpenID string `json:"openid,omitempty"` // 用户唯一标识
|
Token string `json:"token"` // 登录token
|
||||||
SessionKey string `json:"session_key,omitempty"` // 会话密钥
|
UserID string `json:"user_id"` // 用户ID
|
||||||
UnionID string `json:"unionid,omitempty"` // 用户在开放平台的唯一标识符
|
UserName string `json:"user_name"` // 用户昵称
|
||||||
DecryptedData *wechat.DecryptedUserInfo `json:"decrypted_data,omitempty"` // 解密后的用户信息(可选)
|
Avatar string `json:"user_avatar"` // 用户头像
|
||||||
|
OpenID string `json:"openid,omitempty"` // 用户唯一标识
|
||||||
|
UnionID string `json:"unionid,omitempty"` // 用户在开放平台的唯一标识符
|
||||||
}
|
}
|
||||||
|
|
||||||
// Code2SessionResponse 微信code2Session接口响应
|
// Code2SessionResponse 微信code2Session接口响应
|
||||||
@ -41,7 +47,7 @@ type Code2SessionResponse struct {
|
|||||||
|
|
||||||
// MiniprogramLogin 小程序登录
|
// MiniprogramLogin 小程序登录
|
||||||
// @Summary 小程序登录
|
// @Summary 小程序登录
|
||||||
// @Description 通过AppID和code获取用户的openid和session_key
|
// @Description 通过AppID和code获取用户的openid,系统自动生成用户名和头像
|
||||||
// @Tags 微信
|
// @Tags 微信
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
@ -90,46 +96,150 @@ func (h *handler) MiniprogramLogin() core.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 查询或创建用户
|
||||||
|
user, err := h.getOrCreateUser(ctx, req.AppID, openID, unionID)
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Error(fmt.Sprintf("获取或创建用户失败: %s", err.Error()))
|
||||||
|
ctx.AbortWithError(core.Error(
|
||||||
|
http.StatusInternalServerError,
|
||||||
|
code.ServerError,
|
||||||
|
"用户创建失败",
|
||||||
|
))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成登录token
|
||||||
|
token, err := h.generateToken(user.UserID, sessionKey)
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Error(fmt.Sprintf("生成token失败: %s", err.Error()))
|
||||||
|
ctx.AbortWithError(core.Error(
|
||||||
|
http.StatusInternalServerError,
|
||||||
|
code.ServerError,
|
||||||
|
"token生成失败",
|
||||||
|
))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
res.Success = true
|
res.Success = true
|
||||||
res.Message = "登录成功"
|
res.Message = "登录成功"
|
||||||
|
res.Token = token
|
||||||
|
res.UserID = user.UserID
|
||||||
|
res.UserName = user.UserName
|
||||||
|
res.Avatar = user.UserAvatar
|
||||||
res.OpenID = openID
|
res.OpenID = openID
|
||||||
res.SessionKey = sessionKey
|
|
||||||
res.UnionID = unionID
|
res.UnionID = unionID
|
||||||
|
|
||||||
// 如果提供了加密数据,则进行解密
|
|
||||||
if req.EncryptedData != "" && req.IV != "" {
|
|
||||||
// 如果提供了签名验证数据,先验证签名
|
|
||||||
if req.RawData != "" && req.Signature != "" {
|
|
||||||
if !wechat.VerifySignature(req.RawData, req.Signature, sessionKey) {
|
|
||||||
h.logger.Warn("数据签名验证失败")
|
|
||||||
ctx.AbortWithError(core.Error(
|
|
||||||
http.StatusBadRequest,
|
|
||||||
code.ParamBindError,
|
|
||||||
"数据签名验证失败",
|
|
||||||
))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解密用户数据
|
|
||||||
decryptedUserInfo, err := wechat.DecryptUserInfo(sessionKey, req.EncryptedData, req.IV)
|
|
||||||
if err != nil {
|
|
||||||
h.logger.Error(fmt.Sprintf("解密用户数据失败: %s", err.Error()))
|
|
||||||
ctx.AbortWithError(core.Error(
|
|
||||||
http.StatusBadRequest,
|
|
||||||
code.ServerError,
|
|
||||||
"解密用户数据失败",
|
|
||||||
))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
res.DecryptedData = decryptedUserInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Payload(res)
|
ctx.Payload(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getOrCreateUser 获取或创建用户
|
||||||
|
func (h *handler) getOrCreateUser(ctx core.Context, appID, openID, unionID string) (*model.AppUser, error) {
|
||||||
|
// 先查询用户是否存在(使用openID作为用户ID)
|
||||||
|
user, err := h.readDB.AppUser.WithContext(ctx.RequestContext()).
|
||||||
|
Where(h.readDB.AppUser.AppID.Eq(appID)).
|
||||||
|
Where(h.readDB.AppUser.UserID.Eq(openID)).
|
||||||
|
First()
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
// 用户已存在,直接返回
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户不存在,创建新用户
|
||||||
|
// 生成随机用户名
|
||||||
|
seed := time.Now().UTC().UnixNano()
|
||||||
|
nameGen := namegenerator.NewNameGenerator(seed)
|
||||||
|
username := nameGen.Generate()
|
||||||
|
|
||||||
|
// 生成头像URL
|
||||||
|
avatarURL, err := h.generateAvatar(openID)
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Warn(fmt.Sprintf("生成头像失败: %s,使用默认头像", err.Error()))
|
||||||
|
avatarURL = "/static/avatars/default.svg"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建新用户
|
||||||
|
newUser := &model.AppUser{
|
||||||
|
AppID: appID,
|
||||||
|
UserID: openID, // 使用openID作为用户ID
|
||||||
|
UserName: username,
|
||||||
|
UserMobile: "", // 暂时为空
|
||||||
|
UserAvatar: avatarURL,
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.writeDB.AppUser.WithContext(ctx.RequestContext()).Create(newUser)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("创建用户失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return newUser, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// generateAvatar 生成头像
|
||||||
|
func (h *handler) generateAvatar(seed string) (string, error) {
|
||||||
|
// 根据seed生成随机性别
|
||||||
|
gender := govatar.MALE
|
||||||
|
if len(seed)%2 == 0 {
|
||||||
|
gender = govatar.FEMALE
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成头像文件名(基于seed的hash)
|
||||||
|
filename := fmt.Sprintf("%x", seed)
|
||||||
|
if len(filename) > 16 {
|
||||||
|
filename = filename[:16]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成头像文件路径
|
||||||
|
avatarFilename := fmt.Sprintf("%s_%d.png", filename, gender)
|
||||||
|
avatarPath := fmt.Sprintf("static/avatars/%s", avatarFilename)
|
||||||
|
avatarURL := fmt.Sprintf("/static/avatars/%s", avatarFilename)
|
||||||
|
|
||||||
|
// 检查文件是否已存在
|
||||||
|
if _, err := os.Stat(avatarPath); err == nil {
|
||||||
|
// 文件已存在,直接返回URL
|
||||||
|
return avatarURL, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成头像图片
|
||||||
|
img, err := govatar.GenerateForUsername(gender, seed)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("生成头像失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建文件
|
||||||
|
file, err := os.Create(avatarPath)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("创建头像文件失败: %v", err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// 保存PNG图片
|
||||||
|
err = png.Encode(file, img)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("保存头像文件失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return avatarURL, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// generateToken 生成登录token
|
||||||
|
func (h *handler) generateToken(userID, sessionKey string) (string, error) {
|
||||||
|
// 生成32字节的随机token
|
||||||
|
bytes := make([]byte, 32)
|
||||||
|
if _, err := rand.Read(bytes); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
token := hex.EncodeToString(bytes)
|
||||||
|
|
||||||
|
// TODO: 这里应该将token保存到缓存或数据库中,并设置过期时间
|
||||||
|
// 可以结合sessionKey一起存储,用于后续的用户身份验证
|
||||||
|
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
||||||
// callCode2Session 调用微信code2Session接口
|
// callCode2Session 调用微信code2Session接口
|
||||||
func (h *handler) callCode2Session(ctx core.Context, appID, appSecret, jsCode string) (string, string, string, error) {
|
func (h *handler) callCode2Session(ctx core.Context, appID, appSecret, jsCode string) (string, string, string, error) {
|
||||||
// 构建请求URL
|
// 构建请求URL
|
||||||
|
|||||||
@ -233,6 +233,7 @@ func New(logger logger.CustomLogger, options ...Option) (Mux, error) {
|
|||||||
|
|
||||||
mux.engine.Use(cors.New())
|
mux.engine.Use(cors.New())
|
||||||
mux.engine.StaticFS("resources", gin.Dir(configs.GetResourcesFilePath(), true))
|
mux.engine.StaticFS("resources", gin.Dir(configs.GetResourcesFilePath(), true))
|
||||||
|
mux.engine.StaticFS("static", gin.Dir("static", true))
|
||||||
|
|
||||||
// withoutTracePaths 这些请求,默认不记录日志
|
// withoutTracePaths 这些请求,默认不记录日志
|
||||||
withoutTracePaths := map[string]bool{
|
withoutTracePaths := map[string]bool{
|
||||||
|
|||||||
5
static/avatars/default.svg
Normal file
5
static/avatars/default.svg
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="50" cy="50" r="50" fill="#e0e0e0"/>
|
||||||
|
<circle cx="50" cy="35" r="15" fill="#9e9e9e"/>
|
||||||
|
<path d="M20 80 Q20 65 35 65 L65 65 Q80 65 80 80 L80 100 L20 100 Z" fill="#9e9e9e"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 281 B |
Loading…
x
Reference in New Issue
Block a user