✨ scan the QR code to log in on the WeChat public account
This commit is contained in:
@@ -2,6 +2,7 @@ package api
|
||||
|
||||
import (
|
||||
"schisandra-cloud-album/api/captcha_api"
|
||||
"schisandra-cloud-album/api/oauth_api"
|
||||
"schisandra-cloud-album/api/sms_api"
|
||||
"schisandra-cloud-album/api/user_api"
|
||||
)
|
||||
@@ -11,6 +12,7 @@ type Apis struct {
|
||||
UserApi user_api.UserAPI
|
||||
CaptchaApi captcha_api.CaptchaAPI
|
||||
SmsApi sms_api.SmsAPI
|
||||
OAuthApi oauth_api.OAuthAPI
|
||||
}
|
||||
|
||||
// Api new函数实例化,实例化完成后会返回结构体地指针类型
|
||||
|
3
api/oauth_api/oauth.go
Normal file
3
api/oauth_api/oauth.go
Normal file
@@ -0,0 +1,3 @@
|
||||
package oauth_api
|
||||
|
||||
type OAuthAPI struct{}
|
281
api/oauth_api/oauth_api.go
Normal file
281
api/oauth_api/oauth_api.go
Normal file
@@ -0,0 +1,281 @@
|
||||
package oauth_api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/ArtisanCloud/PowerLibs/v3/fmt"
|
||||
"github.com/ArtisanCloud/PowerLibs/v3/http/helper"
|
||||
"github.com/ArtisanCloud/PowerWeChat/v3/src/basicService/qrCode/response"
|
||||
"github.com/ArtisanCloud/PowerWeChat/v3/src/kernel/contract"
|
||||
"github.com/ArtisanCloud/PowerWeChat/v3/src/kernel/messages"
|
||||
models2 "github.com/ArtisanCloud/PowerWeChat/v3/src/kernel/models"
|
||||
"github.com/ArtisanCloud/PowerWeChat/v3/src/officialAccount/server/handlers/models"
|
||||
ginI18n "github.com/gin-contrib/i18n"
|
||||
"github.com/gin-gonic/gin"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"github.com/yitter/idgenerator-go/idgen"
|
||||
"gorm.io/gorm"
|
||||
"schisandra-cloud-album/api/user_api/dto"
|
||||
"schisandra-cloud-album/common/constant"
|
||||
"schisandra-cloud-album/common/enum"
|
||||
"schisandra-cloud-album/common/redis"
|
||||
"schisandra-cloud-album/common/result"
|
||||
"schisandra-cloud-album/global"
|
||||
"schisandra-cloud-album/model"
|
||||
"schisandra-cloud-album/service"
|
||||
"schisandra-cloud-album/utils"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var userService = service.Service.UserService
|
||||
var userRoleService = service.Service.UserRoleService
|
||||
var userSocialService = service.Service.UserSocialService
|
||||
var rolePermissionService = service.Service.RolePermissionService
|
||||
var permissionServiceService = service.Service.PermissionService
|
||||
var roleService = service.Service.RoleService
|
||||
|
||||
// GenerateClientId 生成客户端ID
|
||||
// @Summary 生成客户端ID
|
||||
// @Description 生成客户端ID
|
||||
// @Produce json
|
||||
// @Success 200 {object} result.Result{data=string} "客户端ID"
|
||||
// @Router /api/oauth/generate_client_id [get]
|
||||
func (OAuthAPI) GenerateClientId(c *gin.Context) {
|
||||
ip := c.ClientIP()
|
||||
v1 := uuid.NewV1()
|
||||
redis.Set(constant.UserLoginClientRedisKey+ip, v1.String(), 0)
|
||||
result.OkWithData(v1.String(), c)
|
||||
return
|
||||
}
|
||||
|
||||
// CallbackNotify 微信回调验证
|
||||
// @Summary 微信回调验证
|
||||
// @Description 微信回调验证
|
||||
// @Produce json
|
||||
// @Success 200 {object} result.Result{data=string} "验证结果"
|
||||
// @Router /api/oauth/callback_notify [POST]
|
||||
func (OAuthAPI) CallbackNotify(c *gin.Context) {
|
||||
rs, err := global.Wechat.Server.Notify(c.Request, func(event contract.EventInterface) interface{} {
|
||||
fmt.Dump("event", event)
|
||||
|
||||
switch event.GetMsgType() {
|
||||
|
||||
case models2.CALLBACK_MSG_TYPE_EVENT:
|
||||
switch event.GetEvent() {
|
||||
case models.CALLBACK_EVENT_SUBSCRIBE:
|
||||
msg := models.EventSubscribe{}
|
||||
err := event.ReadMessage(&msg)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return "error"
|
||||
}
|
||||
key := strings.TrimPrefix(msg.EventKey, "qrscene_")
|
||||
res := wechatLoginHandler(msg.FromUserName, key)
|
||||
if !res {
|
||||
return messages.NewText("登录失败")
|
||||
}
|
||||
return messages.NewText("登录成功")
|
||||
|
||||
case models.CALLBACK_EVENT_UNSUBSCRIBE:
|
||||
msg := models.EventUnSubscribe{}
|
||||
err := event.ReadMessage(&msg)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return "error"
|
||||
}
|
||||
fmt.Dump(msg)
|
||||
return messages.NewText("再见,我的宝!")
|
||||
|
||||
case models.CALLBACK_EVENT_SCAN:
|
||||
msg := models.EventScan{}
|
||||
err := event.ReadMessage(&msg)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return "error"
|
||||
}
|
||||
res := wechatLoginHandler(msg.FromUserName, msg.EventKey)
|
||||
if !res {
|
||||
return messages.NewText("登录失败")
|
||||
}
|
||||
return messages.NewText("登录成功")
|
||||
|
||||
}
|
||||
|
||||
case models2.CALLBACK_MSG_TYPE_TEXT:
|
||||
msg := models.MessageText{}
|
||||
err := event.ReadMessage(&msg)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
return "error"
|
||||
}
|
||||
fmt.Dump(msg)
|
||||
}
|
||||
return messages.NewText("ok")
|
||||
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = helper.HttpResponseSend(rs, c.Writer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// CallbackVerify 微信回调验证
|
||||
// @Summary 微信回调验证
|
||||
// @Description 微信回调验证
|
||||
// @Produce json
|
||||
// @Success 200 {object} result.Result{data=string} "验证结果"
|
||||
// @Router /api/oauth/callback_verify [get]
|
||||
func (OAuthAPI) CallbackVerify(c *gin.Context) {
|
||||
rs, err := global.Wechat.Server.VerifyURL(c.Request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = helper.HttpResponseSend(rs, c.Writer)
|
||||
}
|
||||
|
||||
// GetTempQrCode 获取临时二维码
|
||||
// @Summary 获取临时二维码
|
||||
// @Description 获取临时二维码
|
||||
// @Produce json
|
||||
// @Param client_id query string true "客户端ID"
|
||||
// @Success 200 {object} result.Result{data=string} "临时二维码"
|
||||
// @Router /api/oauth/get_temp_qrcode [get]
|
||||
func (OAuthAPI) GetTempQrCode(c *gin.Context) {
|
||||
clientId := c.Query("client_id")
|
||||
if clientId == "" {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||
return
|
||||
}
|
||||
qrcode := redis.Get(constant.UserLoginQrcodeRedisKey + clientId).Val()
|
||||
|
||||
if qrcode != "" {
|
||||
data := response.ResponseQRCodeCreate{}
|
||||
err := json.Unmarshal([]byte(qrcode), &data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
result.OK(ginI18n.MustGetMessage(c, "QRCodeGetSuccess"), data.Url, c)
|
||||
return
|
||||
}
|
||||
data, err := global.Wechat.QRCode.Temporary(c.Request.Context(), clientId, 30*24*3600)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "QRCodeGetFailed"), c)
|
||||
return
|
||||
}
|
||||
serializedData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "QRCodeGetFailed"), c)
|
||||
return
|
||||
}
|
||||
wrong := redis.Set(constant.UserLoginQrcodeRedisKey+clientId, serializedData, time.Hour*24*30).Err()
|
||||
|
||||
if wrong != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "QRCodeGetFailed"), c)
|
||||
return
|
||||
}
|
||||
result.OK(ginI18n.MustGetMessage(c, "QRCodeGetSuccess"), data.Url, c)
|
||||
}
|
||||
|
||||
func wechatLoginHandler(openId string, clientId string) bool {
|
||||
if openId == "" {
|
||||
return false
|
||||
}
|
||||
authUserSocial, err := userSocialService.QueryUserSocialByOpenID(openId)
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
uid := idgen.NextId()
|
||||
uidStr := strconv.FormatInt(uid, 10)
|
||||
createUser := model.ScaAuthUser{
|
||||
UID: &uidStr,
|
||||
Username: &openId,
|
||||
}
|
||||
addUser, err := userService.AddUser(createUser)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
wechat := enum.OAuthSourceWechat
|
||||
userSocial := model.ScaAuthUserSocial{
|
||||
UserID: &addUser.ID,
|
||||
OpenID: &openId,
|
||||
Source: &wechat,
|
||||
}
|
||||
wrong := userSocialService.AddUserSocial(userSocial)
|
||||
if wrong != nil {
|
||||
return false
|
||||
}
|
||||
userRole := model.ScaAuthUserRole{
|
||||
UserID: addUser.ID,
|
||||
RoleID: enum.User,
|
||||
}
|
||||
e := userRoleService.AddUserRole(userRole)
|
||||
if e != nil {
|
||||
return false
|
||||
}
|
||||
res := handelUserLogin(addUser, clientId)
|
||||
if !res {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
user, err := userService.QueryUserById(authUserSocial.UserID)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
res := handelUserLogin(user, clientId)
|
||||
if !res {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// handelUserLogin 处理用户登录
|
||||
func handelUserLogin(user model.ScaAuthUser, clientId string) bool {
|
||||
ids, err := userRoleService.GetUserRoleIdsByUserId(user.ID)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
permissionIds := rolePermissionService.QueryPermissionIdsByRoleId(ids)
|
||||
permissions, err := permissionServiceService.GetPermissionsByIds(permissionIds)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
serializedPermissions, err := json.Marshal(permissions)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
wrong := redis.Set(constant.UserAuthPermissionRedisKey+*user.UID, serializedPermissions, 0).Err()
|
||||
if wrong != nil {
|
||||
return false
|
||||
}
|
||||
roleList, err := roleService.GetRoleListByIds(ids)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
serializedRoleList, err := json.Marshal(roleList)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
er := redis.Set(constant.UserAuthRoleRedisKey+*user.UID, serializedRoleList, 0).Err()
|
||||
if er != nil {
|
||||
return false
|
||||
}
|
||||
accessToken, refreshToken, expiresAt := utils.GenerateAccessTokenAndRefreshToken(utils.JWTPayload{UserID: user.UID, RoleID: ids})
|
||||
|
||||
data := dto.ResponseData{
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
ExpiresAt: expiresAt,
|
||||
UID: user.UID,
|
||||
}
|
||||
fail := redis.Set(constant.UserLoginTokenRedisKey+*user.UID, data, time.Hour*24*7).Err()
|
||||
w := redis.Set(constant.UserLoginWechatRedisKey+clientId, data, time.Minute*5).Err()
|
||||
if fail != nil || w != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
@@ -13,6 +13,27 @@ type PhoneLoginRequest struct {
|
||||
Captcha string `json:"captcha"`
|
||||
}
|
||||
|
||||
// AccountLoginRequest 账号登录请求
|
||||
type AccountLoginRequest struct {
|
||||
Account string `json:"account"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
// AddUserRequest 新增用户请求
|
||||
type AddUserRequest struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Phone string `json:"phone"`
|
||||
}
|
||||
|
||||
// ResetPasswordRequest 重置密码请求
|
||||
type ResetPasswordRequest struct {
|
||||
Phone string `json:"phone"`
|
||||
Captcha string `json:"captcha"`
|
||||
Password string `json:"password"`
|
||||
Repassword string `json:"repassword"`
|
||||
}
|
||||
|
||||
// ResponseData 返回数据
|
||||
type ResponseData struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
|
@@ -60,7 +60,11 @@ func (UserAPI) QueryUserByUsername(c *gin.Context) {
|
||||
// @Router /api/auth/user/query_by_uuid [get]
|
||||
func (UserAPI) QueryUserByUuid(c *gin.Context) {
|
||||
uuid := c.Query("uuid")
|
||||
user := userService.QueryUserByUuid(uuid)
|
||||
user, err := userService.QueryUserByUuid(&uuid)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "NotFoundUser"), c)
|
||||
return
|
||||
}
|
||||
if reflect.DeepEqual(user, model.ScaAuthUser{}) {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "NotFoundUser"), c)
|
||||
return
|
||||
@@ -100,16 +104,81 @@ func (UserAPI) QueryUserByPhone(c *gin.Context) {
|
||||
result.OkWithData(user, c)
|
||||
}
|
||||
|
||||
// AddUser 添加用户
|
||||
// @Summary 添加用户
|
||||
// @Tags 鉴权模块
|
||||
// @Param user body dto.AddUserRequest true "用户信息"
|
||||
// @Success 200 {string} json
|
||||
// @Router /api/user/add [post]
|
||||
func (UserAPI) AddUser(c *gin.Context) {
|
||||
addUserRequest := dto.AddUserRequest{}
|
||||
err := c.ShouldBindJSON(&addUserRequest)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||
return
|
||||
}
|
||||
|
||||
username := userService.QueryUserByUsername(addUserRequest.Username)
|
||||
if !reflect.DeepEqual(username, model.ScaAuthUser{}) {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "UsernameExists"), c)
|
||||
return
|
||||
}
|
||||
|
||||
phone := userService.QueryUserByPhone(addUserRequest.Phone)
|
||||
if !reflect.DeepEqual(phone, model.ScaAuthUser{}) {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "PhoneExists"), c)
|
||||
return
|
||||
}
|
||||
encrypt, err := utils.Encrypt(addUserRequest.Password)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "AddUserError"), c)
|
||||
return
|
||||
}
|
||||
uid := idgen.NextId()
|
||||
uidStr := strconv.FormatInt(uid, 10)
|
||||
user := model.ScaAuthUser{
|
||||
UID: &uidStr,
|
||||
Username: &addUserRequest.Username,
|
||||
Password: &encrypt,
|
||||
Phone: &addUserRequest.Phone,
|
||||
}
|
||||
addUser, err := userService.AddUser(user)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "AddUserError"), c)
|
||||
return
|
||||
}
|
||||
userRole := model.ScaAuthUserRole{
|
||||
UserID: addUser.ID,
|
||||
RoleID: enum.User,
|
||||
}
|
||||
e := userRoleService.AddUserRole(userRole)
|
||||
if e != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "AddUserRoleError"), c)
|
||||
return
|
||||
}
|
||||
result.OkWithMessage(ginI18n.MustGetMessage(c, "AddUserSuccess"), c)
|
||||
return
|
||||
}
|
||||
|
||||
// AccountLogin 账号登录
|
||||
// @Summary 账号登录
|
||||
// @Tags 鉴权模块
|
||||
// @Param account query string true "账号"
|
||||
// @Param password query string true "密码"
|
||||
// @Param user body dto.AccountLoginRequest true "用户信息"
|
||||
// @Success 200 {string} json
|
||||
// @Router /api/user/login [post]
|
||||
func (UserAPI) AccountLogin(c *gin.Context) {
|
||||
account := c.PostForm("account")
|
||||
password := c.PostForm("password")
|
||||
accountLoginRequest := dto.AccountLoginRequest{}
|
||||
err := c.ShouldBindJSON(&accountLoginRequest)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||
return
|
||||
}
|
||||
account := accountLoginRequest.Account
|
||||
password := accountLoginRequest.Password
|
||||
if account == "" || password == "" {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "AccountAndPasswordNotEmpty"), c)
|
||||
return
|
||||
}
|
||||
isPhone := utils.IsPhone(account)
|
||||
if isPhone {
|
||||
user := userService.QueryUserByPhone(account)
|
||||
@@ -117,9 +186,9 @@ func (UserAPI) AccountLogin(c *gin.Context) {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "PhoneNotRegister"), c)
|
||||
return
|
||||
} else {
|
||||
verify := utils.Verify(password, *user.Password)
|
||||
verify := utils.Verify(*user.Password, password)
|
||||
if verify {
|
||||
result.OkWithData(user, c)
|
||||
handelUserLogin(user, c)
|
||||
return
|
||||
} else {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "PasswordError"), c)
|
||||
@@ -134,9 +203,9 @@ func (UserAPI) AccountLogin(c *gin.Context) {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "EmailNotRegister"), c)
|
||||
return
|
||||
} else {
|
||||
verify := utils.Verify(password, *user.Password)
|
||||
verify := utils.Verify(*user.Password, password)
|
||||
if verify {
|
||||
result.OkWithData(user, c)
|
||||
handelUserLogin(user, c)
|
||||
return
|
||||
} else {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "PasswordError"), c)
|
||||
@@ -151,17 +220,18 @@ func (UserAPI) AccountLogin(c *gin.Context) {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "UsernameNotRegister"), c)
|
||||
return
|
||||
} else {
|
||||
verify := utils.Verify(password, *user.Password)
|
||||
verify := utils.Verify(*user.Password, password)
|
||||
if verify {
|
||||
result.OkWithData(user, c)
|
||||
handelUserLogin(user, c)
|
||||
return
|
||||
} else {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "PasswordError"), c)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "AccountErrorFormat"), c)
|
||||
return
|
||||
}
|
||||
|
||||
// PhoneLogin 手机号登录/注册
|
||||
@@ -218,55 +288,7 @@ func (UserAPI) PhoneLogin(c *gin.Context) {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
|
||||
return
|
||||
}
|
||||
ids, err := userRoleService.GetUserRoleIdsByUserId(addUser.ID)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
|
||||
return
|
||||
}
|
||||
permissionIds := rolePermissionService.QueryPermissionIdsByRoleId(ids)
|
||||
permissions, err := permissionServiceService.GetPermissionsByIds(permissionIds)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
|
||||
return
|
||||
}
|
||||
serializedPermissions, err := json.Marshal(permissions)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
|
||||
return
|
||||
}
|
||||
wrong := redis.Set(constant.UserAuthPermissionRedisKey+*addUser.UID, serializedPermissions, 0).Err()
|
||||
if wrong != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
|
||||
return
|
||||
}
|
||||
roleList, err := roleService.GetRoleListByIds(ids)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
serializedRoleList, err := json.Marshal(roleList)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
|
||||
return
|
||||
}
|
||||
er := redis.Set(constant.UserAuthRoleRedisKey+*addUser.UID, serializedRoleList, 0).Err()
|
||||
if er != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
|
||||
return
|
||||
}
|
||||
accessToken, refreshToken, expiresAt := utils.GenerateAccessTokenAndRefreshToken(utils.JWTPayload{UserID: addUser.UID, RoleID: ids})
|
||||
|
||||
data := dto.ResponseData{
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
ExpiresAt: expiresAt,
|
||||
UID: addUser.UID,
|
||||
}
|
||||
fail := redis.Set(constant.UserLoginTokenRedisKey+*addUser.UID, data, time.Hour*24*7).Err()
|
||||
if fail != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
|
||||
return
|
||||
}
|
||||
result.OkWithData(data, c)
|
||||
handelUserLogin(addUser, c)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
@@ -279,6 +301,73 @@ func (UserAPI) PhoneLogin(c *gin.Context) {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CaptchaError"), c)
|
||||
return
|
||||
} else {
|
||||
handelUserLogin(user, c)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// RefreshHandler 刷新token
|
||||
// @Summary 刷新token
|
||||
// @Tags 鉴权模块
|
||||
// @Param refresh_token query string true "刷新token"
|
||||
// @Success 200 {string} json
|
||||
// @Router /api/token/refresh [post]
|
||||
func (UserAPI) RefreshHandler(c *gin.Context) {
|
||||
request := dto.RefreshTokenRequest{}
|
||||
err := c.ShouldBindJSON(&request)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||
return
|
||||
}
|
||||
refreshToken := request.RefreshToken
|
||||
if refreshToken == "" {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||
return
|
||||
}
|
||||
plaintext, err := aes.AesCtrDecryptByHex(refreshToken, []byte(global.CONFIG.Encrypt.Key), []byte(global.CONFIG.Encrypt.IV))
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginExpired"), c)
|
||||
return
|
||||
}
|
||||
parseRefreshToken, isUpd, err := utils.ParseToken(string(plaintext))
|
||||
if err != nil {
|
||||
global.LOG.Errorln(err)
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginExpired"), c)
|
||||
return
|
||||
}
|
||||
if isUpd {
|
||||
accessTokenString, err := utils.GenerateAccessToken(utils.JWTPayload{UserID: parseRefreshToken.UserID, RoleID: parseRefreshToken.RoleID})
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginExpired"), c)
|
||||
return
|
||||
}
|
||||
wrong := redis.Get(constant.UserLoginTokenRedisKey + *parseRefreshToken.UserID).Err()
|
||||
if wrong != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginExpired"), c)
|
||||
return
|
||||
}
|
||||
data := dto.ResponseData{
|
||||
AccessToken: accessTokenString,
|
||||
RefreshToken: refreshToken,
|
||||
UID: parseRefreshToken.UserID,
|
||||
}
|
||||
fail := redis.Set("user:login:token:"+*parseRefreshToken.UserID, data, time.Hour*24*7).Err()
|
||||
if fail != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginExpired"), c)
|
||||
return
|
||||
}
|
||||
result.OkWithData(data, c)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// handelUserLogin 处理用户登录
|
||||
func handelUserLogin(user model.ScaAuthUser, c *gin.Context) {
|
||||
ids, err := userRoleService.GetUserRoleIdsByUserId(user.ID)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
|
||||
@@ -329,65 +418,59 @@ func (UserAPI) PhoneLogin(c *gin.Context) {
|
||||
}
|
||||
result.OkWithData(data, c)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// RefreshHandler 刷新token
|
||||
// @Summary 刷新token
|
||||
// ResetPassword 重置密码
|
||||
// @Summary 重置密码
|
||||
// @Tags 鉴权模块
|
||||
// @Param refresh_token query string true "刷新token"
|
||||
// @Param user body dto.ResetPasswordRequest true "用户信息"
|
||||
// @Success 200 {string} json
|
||||
// @Router /api/auth/token/refresh [post]
|
||||
func (UserAPI) RefreshHandler(c *gin.Context) {
|
||||
request := dto.RefreshTokenRequest{}
|
||||
err := c.ShouldBindJSON(&request)
|
||||
// @Router /api/user/reset_password [post]
|
||||
func (UserAPI) ResetPassword(c *gin.Context) {
|
||||
resetPasswordRequest := dto.ResetPasswordRequest{}
|
||||
err := c.ShouldBindJSON(&resetPasswordRequest)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||
return
|
||||
}
|
||||
refreshToken := request.RefreshToken
|
||||
if refreshToken == "" {
|
||||
phone := resetPasswordRequest.Phone
|
||||
captcha := resetPasswordRequest.Captcha
|
||||
password := resetPasswordRequest.Password
|
||||
repassword := resetPasswordRequest.Repassword
|
||||
if phone == "" || captcha == "" || password == "" || repassword == "" {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||
return
|
||||
}
|
||||
plaintext, err := aes.AesCtrDecryptByHex(refreshToken, []byte(global.CONFIG.Encrypt.Key), []byte(global.CONFIG.Encrypt.IV))
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginExpired"), c)
|
||||
isPhone := utils.IsPhone(phone)
|
||||
if !isPhone {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "PhoneErrorFormat"), c)
|
||||
return
|
||||
}
|
||||
parseRefreshToken, isUpd, err := utils.ParseToken(string(plaintext))
|
||||
if err != nil {
|
||||
global.LOG.Errorln(err)
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginExpired"), c)
|
||||
code := redis.Get(constant.UserLoginSmsRedisKey + phone)
|
||||
if code == nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CaptchaExpired"), c)
|
||||
return
|
||||
} else {
|
||||
if captcha != code.Val() {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CaptchaError"), c)
|
||||
return
|
||||
}
|
||||
if isUpd {
|
||||
accessTokenString, err := utils.GenerateAccessToken(utils.JWTPayload{UserID: parseRefreshToken.UserID, RoleID: parseRefreshToken.RoleID})
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginExpired"), c)
|
||||
}
|
||||
user := userService.QueryUserByPhone(phone)
|
||||
if reflect.DeepEqual(user, model.ScaAuthUser{}) {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "PhoneNotRegister"), c)
|
||||
return
|
||||
}
|
||||
wrong := redis.Get(constant.UserLoginTokenRedisKey + *parseRefreshToken.UserID).Err()
|
||||
encrypt, err := utils.Encrypt(password)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ResetPasswordError"), c)
|
||||
return
|
||||
}
|
||||
wrong := userService.UpdateUser(phone, encrypt)
|
||||
if wrong != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginExpired"), c)
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ResetPasswordError"), c)
|
||||
return
|
||||
}
|
||||
data := dto.ResponseData{
|
||||
AccessToken: accessTokenString,
|
||||
RefreshToken: refreshToken,
|
||||
UID: parseRefreshToken.UserID,
|
||||
}
|
||||
fail := redis.Set("user:login:token:"+*parseRefreshToken.UserID, data, time.Hour*24*7).Err()
|
||||
if fail != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginExpired"), c)
|
||||
result.OkWithMessage(ginI18n.MustGetMessage(c, "ResetPasswordSuccess"), c)
|
||||
return
|
||||
}
|
||||
result.OkWithData(data, c)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@@ -6,4 +6,7 @@ const (
|
||||
UserLoginCaptchaRedisKey = "user:login:captcha:"
|
||||
UserAuthRoleRedisKey = "user:auth:role:"
|
||||
UserAuthPermissionRedisKey = "user:auth:permission:"
|
||||
UserLoginClientRedisKey = "user:login:client:"
|
||||
UserLoginQrcodeRedisKey = "user:login:qrcode:"
|
||||
UserLoginWechatRedisKey = "user:wechat:token:"
|
||||
)
|
||||
|
7
common/enum/oauth_source.go
Normal file
7
common/enum/oauth_source.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package enum
|
||||
|
||||
const (
|
||||
OAuthSourceWechat = "wechat"
|
||||
OAuthSourceQQ = "qq"
|
||||
OAuthSourceWeibo = "weibo"
|
||||
)
|
8
config/conf_wechat.go
Normal file
8
config/conf_wechat.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package config
|
||||
|
||||
type Wechat struct {
|
||||
AppID string `json:"app-id"`
|
||||
AppSecret string `json:"app-secret"`
|
||||
Token string `json:"token"`
|
||||
AESKey string `json:"aes-key"`
|
||||
}
|
@@ -8,4 +8,5 @@ type Config struct {
|
||||
SMS SMS `yaml:"sms"`
|
||||
JWT JWT `yaml:"jwt"`
|
||||
Encrypt Encrypt `yaml:"encrypt"`
|
||||
Wechat Wechat `yaml:"wechat"`
|
||||
}
|
||||
|
33
core/wechat.go
Normal file
33
core/wechat.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"github.com/ArtisanCloud/PowerWeChat/v3/src/kernel"
|
||||
"github.com/ArtisanCloud/PowerWeChat/v3/src/officialAccount"
|
||||
"os"
|
||||
"schisandra-cloud-album/global"
|
||||
)
|
||||
|
||||
func InitWechat() {
|
||||
OfficialAccountApp, err := officialAccount.NewOfficialAccount(&officialAccount.UserConfig{
|
||||
AppID: "wx55251c2f83b9fc25",
|
||||
Secret: "d511800cd53d248afe1260bb8aeed230",
|
||||
Token: "LDQ20020618xxx",
|
||||
AESKey: global.CONFIG.Wechat.AESKey,
|
||||
//Log: officialAccount.Log{
|
||||
// Level: "debug",
|
||||
// File: "./wechat.log",
|
||||
//},
|
||||
ResponseType: os.Getenv("response_type"),
|
||||
HttpDebug: true,
|
||||
Debug: true,
|
||||
Cache: kernel.NewRedisClient(&kernel.UniversalOptions{
|
||||
Addrs: []string{global.CONFIG.Redis.Addr()},
|
||||
Password: global.CONFIG.Redis.Password,
|
||||
DB: 0,
|
||||
}),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
global.Wechat = OfficialAccountApp
|
||||
}
|
256
docs/docs.go
256
docs/docs.go
@@ -56,38 +56,6 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/auth/user/login": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"鉴权模块"
|
||||
],
|
||||
"summary": "账号登录",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "账号",
|
||||
"name": "account",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "密码",
|
||||
"name": "password",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/auth/user/query_by_phone": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -163,33 +131,6 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/auth/user/register": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"鉴权模块"
|
||||
],
|
||||
"summary": "用户注册",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "用户信息",
|
||||
"name": "user",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.ScaAuthUser"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/captcha/rotate/check": {
|
||||
"post": {
|
||||
"description": "验证旋转验证码",
|
||||
@@ -414,7 +355,7 @@ const docTemplate = `{
|
||||
"tags": [
|
||||
"短信验证码"
|
||||
],
|
||||
"summary": "发送短信验证码",
|
||||
"summary": "短信宝发送短信验证码",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
@@ -426,74 +367,163 @@ const docTemplate = `{
|
||||
],
|
||||
"responses": {}
|
||||
}
|
||||
},
|
||||
"/api/sms/test/send": {
|
||||
"get": {
|
||||
"description": "发送测试短信验证码",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"短信验证码"
|
||||
],
|
||||
"summary": "发送测试短信验证码",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "手机号",
|
||||
"name": "phone",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {}
|
||||
}
|
||||
},
|
||||
"/api/token/refresh": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"鉴权模块"
|
||||
],
|
||||
"summary": "刷新token",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "刷新token",
|
||||
"name": "refresh_token",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/user/add": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"鉴权模块"
|
||||
],
|
||||
"summary": "添加用户",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "用户信息",
|
||||
"name": "user",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.AddUserRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/user/login": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"鉴权模块"
|
||||
],
|
||||
"summary": "账号登录",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "用户信息",
|
||||
"name": "user",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.AccountLoginRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/user/phone_login": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"鉴权模块"
|
||||
],
|
||||
"summary": "手机号登录/注册",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "手机号",
|
||||
"name": "phone",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "验证码",
|
||||
"name": "captcha",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"dto.ScaAuthUser": {
|
||||
"dto.AccountLoginRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"avatar": {
|
||||
"description": "头像",
|
||||
"account": {
|
||||
"type": "string"
|
||||
},
|
||||
"blog": {
|
||||
"description": "博客",
|
||||
"password": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"company": {
|
||||
"description": "公司",
|
||||
"type": "string"
|
||||
},
|
||||
"created_by": {
|
||||
"description": "创建人",
|
||||
"type": "string"
|
||||
},
|
||||
"created_time": {
|
||||
"description": "创建时间",
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"description": "邮箱",
|
||||
"type": "string"
|
||||
},
|
||||
"gender": {
|
||||
"description": "性别",
|
||||
"type": "string"
|
||||
},
|
||||
"introduce": {
|
||||
"description": "介绍",
|
||||
"type": "string"
|
||||
},
|
||||
"location": {
|
||||
"description": "地址",
|
||||
"type": "string"
|
||||
},
|
||||
"nickname": {
|
||||
"description": "昵称",
|
||||
"dto.AddUserRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"phone": {
|
||||
"description": "电话",
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"description": "状态 0 正常 1 封禁",
|
||||
"type": "integer"
|
||||
},
|
||||
"update_by": {
|
||||
"description": "更新人",
|
||||
"type": "string"
|
||||
},
|
||||
"update_time": {
|
||||
"description": "更新时间",
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"description": "用户名",
|
||||
"type": "string"
|
||||
},
|
||||
"uuid": {
|
||||
"description": "唯一ID",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
|
@@ -45,38 +45,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/auth/user/login": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"鉴权模块"
|
||||
],
|
||||
"summary": "账号登录",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "账号",
|
||||
"name": "account",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "密码",
|
||||
"name": "password",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/auth/user/query_by_phone": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -152,33 +120,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/auth/user/register": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"鉴权模块"
|
||||
],
|
||||
"summary": "用户注册",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "用户信息",
|
||||
"name": "user",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/model.ScaAuthUser"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/captcha/rotate/check": {
|
||||
"post": {
|
||||
"description": "验证旋转验证码",
|
||||
@@ -403,7 +344,7 @@
|
||||
"tags": [
|
||||
"短信验证码"
|
||||
],
|
||||
"summary": "发送短信验证码",
|
||||
"summary": "短信宝发送短信验证码",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
@@ -415,74 +356,163 @@
|
||||
],
|
||||
"responses": {}
|
||||
}
|
||||
},
|
||||
"/api/sms/test/send": {
|
||||
"get": {
|
||||
"description": "发送测试短信验证码",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"短信验证码"
|
||||
],
|
||||
"summary": "发送测试短信验证码",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "手机号",
|
||||
"name": "phone",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {}
|
||||
}
|
||||
},
|
||||
"/api/token/refresh": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"鉴权模块"
|
||||
],
|
||||
"summary": "刷新token",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "刷新token",
|
||||
"name": "refresh_token",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/user/add": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"鉴权模块"
|
||||
],
|
||||
"summary": "添加用户",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "用户信息",
|
||||
"name": "user",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.AddUserRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/user/login": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"鉴权模块"
|
||||
],
|
||||
"summary": "账号登录",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "用户信息",
|
||||
"name": "user",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.AccountLoginRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/user/phone_login": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"鉴权模块"
|
||||
],
|
||||
"summary": "手机号登录/注册",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "手机号",
|
||||
"name": "phone",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "验证码",
|
||||
"name": "captcha",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"model.ScaAuthUser": {
|
||||
"dto.AccountLoginRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"avatar": {
|
||||
"description": "头像",
|
||||
"account": {
|
||||
"type": "string"
|
||||
},
|
||||
"blog": {
|
||||
"description": "博客",
|
||||
"password": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"company": {
|
||||
"description": "公司",
|
||||
"type": "string"
|
||||
},
|
||||
"created_by": {
|
||||
"description": "创建人",
|
||||
"type": "string"
|
||||
},
|
||||
"created_time": {
|
||||
"description": "创建时间",
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"description": "邮箱",
|
||||
"type": "string"
|
||||
},
|
||||
"gender": {
|
||||
"description": "性别",
|
||||
"type": "string"
|
||||
},
|
||||
"introduce": {
|
||||
"description": "介绍",
|
||||
"type": "string"
|
||||
},
|
||||
"location": {
|
||||
"description": "地址",
|
||||
"type": "string"
|
||||
},
|
||||
"nickname": {
|
||||
"description": "昵称",
|
||||
"dto.AddUserRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"phone": {
|
||||
"description": "电话",
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"description": "状态 0 正常 1 封禁",
|
||||
"type": "integer"
|
||||
},
|
||||
"update_by": {
|
||||
"description": "更新人",
|
||||
"type": "string"
|
||||
},
|
||||
"update_time": {
|
||||
"description": "更新时间",
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"description": "用户名",
|
||||
"type": "string"
|
||||
},
|
||||
"uuid": {
|
||||
"description": "唯一ID",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
|
@@ -1,53 +1,18 @@
|
||||
definitions:
|
||||
model.ScaAuthUser:
|
||||
dto.AccountLoginRequest:
|
||||
properties:
|
||||
avatar:
|
||||
description: 头像
|
||||
account:
|
||||
type: string
|
||||
blog:
|
||||
description: 博客
|
||||
password:
|
||||
type: string
|
||||
company:
|
||||
description: 公司
|
||||
type: string
|
||||
created_by:
|
||||
description: 创建人
|
||||
type: string
|
||||
created_time:
|
||||
description: 创建时间
|
||||
type: string
|
||||
email:
|
||||
description: 邮箱
|
||||
type: string
|
||||
gender:
|
||||
description: 性别
|
||||
type: string
|
||||
introduce:
|
||||
description: 介绍
|
||||
type: string
|
||||
location:
|
||||
description: 地址
|
||||
type: string
|
||||
nickname:
|
||||
description: 昵称
|
||||
type: object
|
||||
dto.AddUserRequest:
|
||||
properties:
|
||||
password:
|
||||
type: string
|
||||
phone:
|
||||
description: 电话
|
||||
type: string
|
||||
status:
|
||||
description: 状态 0 正常 1 封禁
|
||||
type: integer
|
||||
update_by:
|
||||
description: 更新人
|
||||
type: string
|
||||
update_time:
|
||||
description: 更新时间
|
||||
type: string
|
||||
username:
|
||||
description: 用户名
|
||||
type: string
|
||||
uuid:
|
||||
description: 唯一ID
|
||||
type: string
|
||||
type: object
|
||||
info:
|
||||
@@ -79,27 +44,6 @@ paths:
|
||||
summary: 删除用户
|
||||
tags:
|
||||
- 鉴权模块
|
||||
/api/auth/user/login:
|
||||
post:
|
||||
parameters:
|
||||
- description: 账号
|
||||
in: query
|
||||
name: account
|
||||
required: true
|
||||
type: string
|
||||
- description: 密码
|
||||
in: query
|
||||
name: password
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
summary: 账号登录
|
||||
tags:
|
||||
- 鉴权模块
|
||||
/api/auth/user/query_by_phone:
|
||||
get:
|
||||
parameters:
|
||||
@@ -148,23 +92,6 @@ paths:
|
||||
summary: 根据uuid查询用户
|
||||
tags:
|
||||
- 鉴权模块
|
||||
/api/auth/user/register:
|
||||
post:
|
||||
parameters:
|
||||
- description: 用户信息
|
||||
in: body
|
||||
name: user
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/model.ScaAuthUser'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
summary: 用户注册
|
||||
tags:
|
||||
- 鉴权模块
|
||||
/api/captcha/rotate/check:
|
||||
post:
|
||||
description: 验证旋转验证码
|
||||
@@ -319,7 +246,93 @@ paths:
|
||||
produces:
|
||||
- application/json
|
||||
responses: {}
|
||||
summary: 发送短信验证码
|
||||
summary: 短信宝发送短信验证码
|
||||
tags:
|
||||
- 短信验证码
|
||||
/api/sms/test/send:
|
||||
get:
|
||||
description: 发送测试短信验证码
|
||||
parameters:
|
||||
- description: 手机号
|
||||
in: query
|
||||
name: phone
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses: {}
|
||||
summary: 发送测试短信验证码
|
||||
tags:
|
||||
- 短信验证码
|
||||
/api/token/refresh:
|
||||
post:
|
||||
parameters:
|
||||
- description: 刷新token
|
||||
in: query
|
||||
name: refresh_token
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
summary: 刷新token
|
||||
tags:
|
||||
- 鉴权模块
|
||||
/api/user/add:
|
||||
post:
|
||||
parameters:
|
||||
- description: 用户信息
|
||||
in: body
|
||||
name: user
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.AddUserRequest'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
summary: 添加用户
|
||||
tags:
|
||||
- 鉴权模块
|
||||
/api/user/login:
|
||||
post:
|
||||
parameters:
|
||||
- description: 用户信息
|
||||
in: body
|
||||
name: user
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.AccountLoginRequest'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
summary: 账号登录
|
||||
tags:
|
||||
- 鉴权模块
|
||||
/api/user/phone_login:
|
||||
post:
|
||||
parameters:
|
||||
- description: 手机号
|
||||
in: query
|
||||
name: phone
|
||||
required: true
|
||||
type: string
|
||||
- description: 验证码
|
||||
in: query
|
||||
name: captcha
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
summary: 手机号登录/注册
|
||||
tags:
|
||||
- 鉴权模块
|
||||
swagger: "2.0"
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"github.com/ArtisanCloud/PowerWeChat/v3/src/officialAccount"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/wenlng/go-captcha/v2/click"
|
||||
@@ -22,4 +23,5 @@ var (
|
||||
RotateCaptcha rotate.Captcha
|
||||
SlideRegionCaptcha slide.Captcha
|
||||
REDIS *redis.Client
|
||||
Wechat *officialAccount.OfficialAccount
|
||||
)
|
||||
|
10
go.mod
10
go.mod
@@ -25,10 +25,14 @@ require (
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/ArtisanCloud/PowerLibs/v3 v3.2.5 // indirect
|
||||
github.com/ArtisanCloud/PowerSocialite/v3 v3.0.7 // indirect
|
||||
github.com/ArtisanCloud/PowerWeChat/v3 v3.2.38 // indirect
|
||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||
github.com/bytedance/sonic v1.12.0 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
@@ -56,13 +60,19 @@ require (
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/nicksnyder/go-i18n/v2 v2.4.0 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkg6/go-requests v0.2.2 // indirect
|
||||
github.com/pkg6/go-sms v0.1.2 // indirect
|
||||
github.com/satori/go.uuid v1.2.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
github.com/wumansgy/goEncrypt v1.1.0 // indirect
|
||||
github.com/yitter/idgenerator-go v1.3.3 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/arch v0.8.0 // indirect
|
||||
golang.org/x/image v0.18.0 // indirect
|
||||
golang.org/x/mod v0.19.0 // indirect
|
||||
|
20
go.sum
20
go.sum
@@ -1,5 +1,11 @@
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/ArtisanCloud/PowerLibs/v3 v3.2.5 h1:W3NKBTnh4d5RBzondNo++QdZ99HPYs5TQKMH2gngKvk=
|
||||
github.com/ArtisanCloud/PowerLibs/v3 v3.2.5/go.mod h1:XFRnJA+D0b0IoeSk2ceZzBp9qxatMHOGtWdZCa/r/3U=
|
||||
github.com/ArtisanCloud/PowerSocialite/v3 v3.0.7 h1:P+erNlErr+X2v7Et+yTWaTfIRhw+HfpAPdvNIEwk9Gw=
|
||||
github.com/ArtisanCloud/PowerSocialite/v3 v3.0.7/go.mod h1:VZQNCvcK/rldF3QaExiSl1gJEAkyc5/I8RLOd3WFZq4=
|
||||
github.com/ArtisanCloud/PowerWeChat/v3 v3.2.38 h1:f2gDqq4s3FR3wEdaMJM/Cr3gRhSG3usjQhhbM3Tj+eU=
|
||||
github.com/ArtisanCloud/PowerWeChat/v3 v3.2.38/go.mod h1:9CbKc6nODhoM8TVjoXqujrAr7zrTBUlr0Z7daFJVAJI=
|
||||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
@@ -17,6 +23,8 @@ github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
|
||||
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||
@@ -115,8 +123,12 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg6/go-requests v0.2.2 h1:wL0aFmyybM/Wuqj8xQa3sNL5ioAL97hQZ78TJovltbM=
|
||||
github.com/pkg6/go-requests v0.2.2/go.mod h1:/rcVm8Itd2djtxDVxjRnHURChV86TB4ooZnP+IBZBmg=
|
||||
github.com/pkg6/go-sms v0.1.2 h1:HZQlBkRVF9xQHhyCMB3kXY/kltfvuNgMTKuN/DoSg7w=
|
||||
@@ -127,6 +139,8 @@ github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0
|
||||
github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
@@ -162,6 +176,12 @@ github.com/wumansgy/goEncrypt v1.1.0/go.mod h1:dWgF7mi5Ujmt8V5EoyRqjH6XtZ8wmNQyT
|
||||
github.com/yitter/idgenerator-go v1.3.3 h1:i6rzmpbCL0vlmr/tuW5+lSQzNuDG9vYBjIYRvnRcHE8=
|
||||
github.com/yitter/idgenerator-go v1.3.3/go.mod h1:VVjbqFjGUsIkaXVkXEdmx1LiXUL3K1NvyxWPJBPbBpE=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
||||
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
|
@@ -41,3 +41,14 @@ PhoneAndCaptchaNotEmpty = "phone number and captcha can not be empty!"
|
||||
PhoneErrorFormat = "phone number error format!"
|
||||
RegisterUserError = "register user error!"
|
||||
LoginExpired = "login expired!, please try again!"
|
||||
AccountAndPasswordNotEmpty = "account and password can not be empty!"
|
||||
UserNotRegister = "user not register!"
|
||||
AccountErrorFormat = "account error format!"
|
||||
AddUserError = "add user error!"
|
||||
AddUserRoleError = "add user role error!"
|
||||
AddUserSuccess = "add user success!"
|
||||
ResetPasswordError = "reset password error!"
|
||||
ResetPasswordSuccess = "reset password success!"
|
||||
QRCodeGetFailed = "qr code get failed!"
|
||||
QRCodeGetSuccess = "qr code get successfully!"
|
||||
QRCodeExpired = "qr code expired!"
|
||||
|
@@ -41,3 +41,15 @@ PhoneAndCaptchaNotEmpty = "手机号和验证码不能为空!"
|
||||
PhoneErrorFormat = "手机号格式错误!"
|
||||
RegisterUserError = "注册用户错误!"
|
||||
LoginExpired = "登录已过期!,请重新登录!"
|
||||
AccountAndPasswordNotEmpty = "账号和密码不能为空!"
|
||||
UserNotRegister = "用户未注册!"
|
||||
AccountErrorFormat = "账号格式错误!"
|
||||
AddUserError = "添加用户错误!"
|
||||
AddUserRoleError = "添加用户角色错误!"
|
||||
AddUserSuccess = "添加用户成功!"
|
||||
ResetPasswordError = "重置密码错误!"
|
||||
ResetPasswordSuccess = "重置密码成功!"
|
||||
QRCodeGetFailed = "获取二维码失败!"
|
||||
QRCodeGetSuccess = "获取二维码成功!"
|
||||
QRCodeExpired = "二维码已过期!"
|
||||
|
||||
|
1
main.go
1
main.go
@@ -15,6 +15,7 @@ func main() {
|
||||
core.InitRedis() // 初始化redis
|
||||
core.InitCaptcha() // 初始化验证码
|
||||
core.InitIDGenerator() // 初始化ID生成器
|
||||
core.InitWechat() // 初始化微信
|
||||
// 命令行参数绑定
|
||||
option := cmd.Parse()
|
||||
if cmd.IsStopWeb(&option) {
|
||||
|
@@ -9,14 +9,13 @@ const TableNameScaAuthUserSocial = "sca_auth_user_social"
|
||||
// ScaAuthUserSocial 社会用户信息表
|
||||
type ScaAuthUserSocial struct {
|
||||
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;comment:主键ID" json:"id"` // 主键ID
|
||||
UserID int64 `gorm:"column:user_id;type:bigint(20);not null;comment:用户ID" json:"user_id"` // 用户ID
|
||||
UserID *int64 `gorm:"column:user_id;type:bigint(20);not null;comment:用户ID" json:"user_id"` // 用户ID
|
||||
UUID *string `gorm:"column:uuid;type:varchar(255);comment:第三方系统的唯一ID" json:"uuid"` // 第三方系统的唯一ID
|
||||
Source *string `gorm:"column:source;type:varchar(255);comment:第三方用户来源" json:"source"` // 第三方用户来源
|
||||
AccessToken *string `gorm:"column:access_token;type:varchar(255);comment:用户的授权令牌" json:"access_token"` // 用户的授权令牌
|
||||
ExpireIn *int64 `gorm:"column:expire_in;type:int(11);comment:第三方用户的授权令牌的有效期" json:"expire_in"` // 第三方用户的授权令牌的有效期
|
||||
RefreshToken *string `gorm:"column:refresh_token;type:varchar(255);comment:刷新令牌" json:"refresh_token"` // 刷新令牌
|
||||
OpenID *string `gorm:"column:open_id;type:varchar(255);comment:第三方用户的 open id" json:"open_id"` // 第三方用户的 open id
|
||||
UID *string `gorm:"column:uid;type:varchar(255);comment:第三方用户的 ID" json:"uid"` // 第三方用户的 ID
|
||||
AccessCode *string `gorm:"column:access_code;type:varchar(255);comment:个别平台的授权信息" json:"access_code"` // 个别平台的授权信息
|
||||
UnionID *string `gorm:"column:union_id;type:varchar(255);comment:第三方用户的 union id" json:"union_id"` // 第三方用户的 union id
|
||||
Scope *string `gorm:"column:scope;type:varchar(255);comment:第三方用户授予的权限" json:"scope"` // 第三方用户授予的权限
|
||||
@@ -27,13 +26,13 @@ type ScaAuthUserSocial struct {
|
||||
Code *string `gorm:"column:code;type:varchar(255);comment:用户的授权code" json:"code"` // 用户的授权code
|
||||
OauthToken *string `gorm:"column:oauth_token;type:varchar(255);comment:Twitter平台用户的附带属性" json:"oauth_token"` // Twitter平台用户的附带属性
|
||||
OauthTokenSecret *string `gorm:"column:oauth_token_secret;type:varchar(255);comment:Twitter平台用户的附带属性" json:"oauth_token_secret"` // Twitter平台用户的附带属性
|
||||
Status *string `gorm:"column:status;type:varchar(255);comment:状态 0正常 1 封禁" json:"status"` // 状态 0正常 1 封禁
|
||||
Status *string `gorm:"column:status;type:varchar(255);default:0;comment:状态 0正常 1 封禁" json:"status"` // 状态 0正常 1 封禁
|
||||
ExtJSON *string `gorm:"column:ext_json;type:varchar(255);comment:额外字段" json:"ext_json"` // 额外字段
|
||||
CreatedBy *string `gorm:"column:created_by;type:varchar(32);comment:创建人" json:"created_by"` // 创建人
|
||||
CreatedTime *time.Time `gorm:"column:created_time;type:datetime;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_time"` // 创建时间
|
||||
UpdateBy *string `gorm:"column:update_by;type:varchar(32);comment:更新人" json:"update_by"` // 更新人
|
||||
UpdateTime *time.Time `gorm:"column:update_time;type:datetime;default:CURRENT_TIMESTAMP;comment:更新时间" json:"update_time"` // 更新时间
|
||||
Deleted *int64 `gorm:"column:deleted;type:int(11);comment:是否删除" json:"deleted"` // 是否删除
|
||||
Deleted *int64 `gorm:"column:deleted;type:int(11);default:0;comment:是否删除" json:"deleted"` // 是否删除
|
||||
}
|
||||
|
||||
// TableName ScaAuthUserSocial's table name
|
||||
|
16
router/modules/oauth_router.go
Normal file
16
router/modules/oauth_router.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package modules
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"schisandra-cloud-album/api"
|
||||
)
|
||||
|
||||
var oauth = api.Api.OAuthApi
|
||||
|
||||
func OauthRouter(router *gin.RouterGroup) {
|
||||
group := router.Group("/oauth")
|
||||
group.GET("/generate_client_id", oauth.GenerateClientId)
|
||||
group.GET("/get_temp_qrcode", oauth.GetTempQrCode)
|
||||
//group.GET("/callback", oauth.CallbackVerify)
|
||||
group.POST("/callback", oauth.CallbackNotify)
|
||||
}
|
@@ -14,6 +14,8 @@ func UserRouter(router *gin.RouterGroup) {
|
||||
{
|
||||
userGroup.POST("/login", userApi.AccountLogin)
|
||||
userGroup.POST("/phone_login", userApi.PhoneLogin)
|
||||
userGroup.POST("/add", userApi.AddUser)
|
||||
userGroup.POST("/reset_password", userApi.ResetPassword)
|
||||
}
|
||||
authGroup := router.Group("auth").Use(middleware.JWTAuthMiddleware())
|
||||
{
|
||||
|
@@ -26,5 +26,6 @@ func InitRouter() *gin.Engine {
|
||||
modules.UserRouter(publicGroup) // 注册鉴权路由
|
||||
modules.CaptchaRouter(publicGroup) // 注册验证码路由
|
||||
modules.SmsRouter(publicGroup) // 注册短信验证码路由
|
||||
modules.OauthRouter(publicGroup) // 注册oauth路由
|
||||
return router
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
"schisandra-cloud-album/service/role_service"
|
||||
"schisandra-cloud-album/service/user_role_service"
|
||||
"schisandra-cloud-album/service/user_service"
|
||||
"schisandra-cloud-album/service/user_social_service"
|
||||
)
|
||||
|
||||
// Services 统一导出的service
|
||||
@@ -15,6 +16,7 @@ type Services struct {
|
||||
UserRoleService user_role_service.UserRoleService
|
||||
RolePermissionService role_permission_service.RolePermissionService
|
||||
PermissionService permission_service.PermissionService
|
||||
UserSocialService user_social_service.UserSocialService
|
||||
}
|
||||
|
||||
// Service new函数实例化,实例化完成后会返回结构体地指针类型
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package user_service
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"schisandra-cloud-album/common/enum"
|
||||
"schisandra-cloud-album/global"
|
||||
"schisandra-cloud-album/model"
|
||||
@@ -22,10 +21,21 @@ func (UserService) QueryUserByUsername(username string) model.ScaAuthUser {
|
||||
}
|
||||
|
||||
// QueryUserByUuid 根据用户uuid查询用户
|
||||
func (UserService) QueryUserByUuid(uuid string) model.ScaAuthUser {
|
||||
func (UserService) QueryUserByUuid(uuid *string) (model.ScaAuthUser, error) {
|
||||
authUser := model.ScaAuthUser{}
|
||||
global.DB.Where("uuid = ? and deleted = 0", uuid).First(&authUser)
|
||||
return authUser
|
||||
if err := global.DB.Where("uid = ? and deleted = 0", uuid).First(&authUser).Error; err != nil {
|
||||
return model.ScaAuthUser{}, err
|
||||
}
|
||||
return authUser, nil
|
||||
}
|
||||
|
||||
// QueryUserById 根据用户id查询用户
|
||||
func (UserService) QueryUserById(id *int64) (model.ScaAuthUser, error) {
|
||||
authUser := model.ScaAuthUser{}
|
||||
if err := global.DB.Where("id = ? and deleted = 0", id).First(&authUser).Error; err != nil {
|
||||
return model.ScaAuthUser{}, err
|
||||
}
|
||||
return authUser, nil
|
||||
}
|
||||
|
||||
// AddUser 添加用户
|
||||
@@ -42,15 +52,14 @@ func (UserService) AddUser(user model.ScaAuthUser) (model.ScaAuthUser, error) {
|
||||
}
|
||||
|
||||
// UpdateUser 更新用户
|
||||
func (UserService) UpdateUser(user model.ScaAuthUser) *gorm.DB {
|
||||
authUser := model.ScaAuthUser{}
|
||||
return global.DB.Model(&authUser).Where("uuid = ?", user.UID).Updates(user)
|
||||
func (UserService) UpdateUser(phone string, password string) error {
|
||||
return global.DB.Model(&model.ScaAuthUser{}).Where("phone = ? and deleted = 0", phone).Updates(&model.ScaAuthUser{Password: &password}).Error
|
||||
}
|
||||
|
||||
// DeleteUser 删除用户
|
||||
func (UserService) DeleteUser(uuid string) error {
|
||||
authUser := model.ScaAuthUser{}
|
||||
return global.DB.Model(&authUser).Where("uuid = ?", uuid).Updates(&model.ScaAuthUser{Deleted: &enum.DELETED}).Error
|
||||
return global.DB.Model(&authUser).Where("uid = ?", uuid).Updates(&model.ScaAuthUser{Deleted: &enum.DELETED}).Error
|
||||
}
|
||||
|
||||
// QueryUserByPhone 根据手机号查询用户
|
||||
|
3
service/user_social_service/user_social.go
Normal file
3
service/user_social_service/user_social.go
Normal file
@@ -0,0 +1,3 @@
|
||||
package user_social_service
|
||||
|
||||
type UserSocialService struct{}
|
31
service/user_social_service/user_social_service.go
Normal file
31
service/user_social_service/user_social_service.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package user_social_service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"gorm.io/gorm"
|
||||
"schisandra-cloud-album/global"
|
||||
"schisandra-cloud-album/model"
|
||||
)
|
||||
|
||||
// AddUserSocial 添加社会化登录用户信息
|
||||
|
||||
func (UserSocialService) AddUserSocial(user model.ScaAuthUserSocial) error {
|
||||
result := global.DB.Create(&user)
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// QueryUserSocialByOpenID 根据openID查询用户信息
|
||||
func (UserSocialService) QueryUserSocialByOpenID(openID string) (model.ScaAuthUserSocial, error) {
|
||||
var user model.ScaAuthUserSocial
|
||||
result := global.DB.Where("open_id = ? and deleted = 0", openID).First(&user)
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return model.ScaAuthUserSocial{}, result.Error
|
||||
}
|
||||
return model.ScaAuthUserSocial{}, result.Error
|
||||
}
|
||||
return user, nil
|
||||
}
|
29
wechat/info.log
Normal file
29
wechat/info.log
Normal file
@@ -0,0 +1,29 @@
|
||||
{"L":"INFO","timestamp":"2024-08-15T16:56:15+08:00","M":"Server response created:","content":"269685512388607999"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T16:58:26+08:00","M":"GET https://api.weixin.qq.com/cgi-bin/token?appid=&grant_type=client_credential&neededText=&secret= request header: { Accept:*/*} "}
|
||||
{"L":"INFO","timestamp":"2024-08-15T16:58:27+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 74\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Thu, 15 Aug 2024 08:58:27 GMT\r\nLogicret: 41002\r\nRetkey: 11\r\n\r\n{\"errcode\":41002,\"errmsg\":\"appid missing rid: 66bdc333-1a4b473f-4fe5f5c6\"}"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T17:00:28+08:00","M":"GET https://api.weixin.qq.com/cgi-bin/token?appid=&grant_type=client_credential&neededText=&secret= request header: { Accept:*/*} "}
|
||||
{"L":"INFO","timestamp":"2024-08-15T17:00:28+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 74\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Thu, 15 Aug 2024 09:00:28 GMT\r\nLogicret: 41002\r\nRetkey: 11\r\n\r\n{\"errcode\":41002,\"errmsg\":\"appid missing rid: 66bdc3ac-59196e03-5ed1ff84\"}"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T17:08:50+08:00","M":"GET https://api.weixin.qq.com/cgi-bin/token?appid=&grant_type=client_credential&neededText=&secret= request header: { Accept:*/*} "}
|
||||
{"L":"INFO","timestamp":"2024-08-15T17:08:50+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 74\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Thu, 15 Aug 2024 09:08:50 GMT\r\nLogicret: 41002\r\nRetkey: 11\r\n\r\n{\"errcode\":41002,\"errmsg\":\"appid missing rid: 66bdc5a2-10088a26-2e3835d6\"}"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T17:19:18+08:00","M":"GET https://api.weixin.qq.com/cgi-bin/token?appid=wx55251c2f83b9fc25&grant_type=client_credential&neededText=&secret=d511800cd53d248afe1260bb8aeed230 request header: { Accept:*/*} "}
|
||||
{"L":"INFO","timestamp":"2024-08-15T17:19:18+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 173\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Thu, 15 Aug 2024 09:19:18 GMT\r\n\r\n{\"access_token\":\"83_HgqCjNIkKPGe_jIVDhx5LSmwI8Q7Am7-Acr2FeDNla7HeXGu-A-rFCgHSrA9d2sH9eUCvo7g_0KkE6tlcpfoX75Dn8wkmmwgA-EfVwiPUOA1uMY0vy0Hf9u-6acCHMaAAAJOT\",\"expires_in\":7200}"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T17:19:18+08:00","M":"POST https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=83_HgqCjNIkKPGe_jIVDhx5LSmwI8Q7Am7-Acr2FeDNla7HeXGu-A-rFCgHSrA9d2sH9eUCvo7g_0KkE6tlcpfoX75Dn8wkmmwgA-EfVwiPUOA1uMY0vy0Hf9u-6acCHMaAAAJOT&debug=1 request header: { Content-Type:application/jsonAccept:*/*} request body:{\"action_info\":{\"scene\":{\"scene_str\":\"7cd96062-5ade-11ef-9e17-902e16172287\"}},\"action_name\":\"QR_STR_SCENE\",\"expire_seconds\":2592000}\n"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T17:19:18+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 192\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Thu, 15 Aug 2024 09:19:18 GMT\r\n\r\n{\"ticket\":\"gQFJ8DwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyb1Fobk5TbmxjbkYxUW1sQk5DY3IAAgQWyL1mAwQAjScA\",\"expire_seconds\":2592000,\"url\":\"http:\\/\\/weixin.qq.com\\/q\\/02oQhnNSnlcnF1QmlBNCcr\"}"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T17:20:32+08:00","M":"POST https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=83_HgqCjNIkKPGe_jIVDhx5LSmwI8Q7Am7-Acr2FeDNla7HeXGu-A-rFCgHSrA9d2sH9eUCvo7g_0KkE6tlcpfoX75Dn8wkmmwgA-EfVwiPUOA1uMY0vy0Hf9u-6acCHMaAAAJOT&debug=1 request header: { Accept:*/*Content-Type:application/json} request body:{\"action_info\":{\"scene\":{\"scene_str\":\"7cd96062-5ade-11ef-9e17-902e16172287\"}},\"action_name\":\"QR_STR_SCENE\",\"expire_seconds\":2592000}\n"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T17:20:32+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 192\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Thu, 15 Aug 2024 09:20:32 GMT\r\n\r\n{\"ticket\":\"gQFX8DwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAycXpEVk1IbmxjbkYxUndsQjFDY0kAAgRgyL1mAwQAjScA\",\"expire_seconds\":2592000,\"url\":\"http:\\/\\/weixin.qq.com\\/q\\/02qzDVMHnlcnF1RwlB1CcI\"}"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T17:20:38+08:00","M":"POST https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=83_HgqCjNIkKPGe_jIVDhx5LSmwI8Q7Am7-Acr2FeDNla7HeXGu-A-rFCgHSrA9d2sH9eUCvo7g_0KkE6tlcpfoX75Dn8wkmmwgA-EfVwiPUOA1uMY0vy0Hf9u-6acCHMaAAAJOT&debug=1 request header: { Content-Type:application/jsonAccept:*/*} request body:{\"action_info\":{\"scene\":{\"scene_str\":\"7cd96062-5ade-11ef-9e17-902e16172287\"}},\"action_name\":\"QR_STR_SCENE\",\"expire_seconds\":2592000}\n"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T17:20:38+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 192\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Thu, 15 Aug 2024 09:20:38 GMT\r\n\r\n{\"ticket\":\"gQFs8DwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyYlpseE1YbmxjbkYxUkNsQjFDYzcAAgRmyL1mAwQAjScA\",\"expire_seconds\":2592000,\"url\":\"http:\\/\\/weixin.qq.com\\/q\\/02bZlxMXnlcnF1RClB1Cc7\"}"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T17:21:32+08:00","M":"POST https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=83_HgqCjNIkKPGe_jIVDhx5LSmwI8Q7Am7-Acr2FeDNla7HeXGu-A-rFCgHSrA9d2sH9eUCvo7g_0KkE6tlcpfoX75Dn8wkmmwgA-EfVwiPUOA1uMY0vy0Hf9u-6acCHMaAAAJOT&debug=1 request header: { Accept:*/*Content-Type:application/json} request body:{\"action_info\":{\"scene\":{\"scene_str\":\"7cd96062-5ade-11ef-9e17-902e16172287\"}},\"action_name\":\"QR_STR_SCENE\",\"expire_seconds\":2592000}\n"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T17:21:32+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 192\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Thu, 15 Aug 2024 09:21:32 GMT\r\n\r\n{\"ticket\":\"gQGv8DwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAydnlNSk5tbmxjbkYxU3NsQnhDY0oAAgScyL1mAwQAjScA\",\"expire_seconds\":2592000,\"url\":\"http:\\/\\/weixin.qq.com\\/q\\/02vyMJNmnlcnF1SslBxCcJ\"}"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T17:22:21+08:00","M":"POST https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=83_HgqCjNIkKPGe_jIVDhx5LSmwI8Q7Am7-Acr2FeDNla7HeXGu-A-rFCgHSrA9d2sH9eUCvo7g_0KkE6tlcpfoX75Dn8wkmmwgA-EfVwiPUOA1uMY0vy0Hf9u-6acCHMaAAAJOT&debug=1 request header: { Content-Type:application/jsonAccept:*/*} request body:{\"action_info\":{\"scene\":{\"scene_str\":\"7cd96062-5ade-11ef-9e17-902e16172287\"}},\"action_name\":\"QR_STR_SCENE\",\"expire_seconds\":2592000}\n"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T17:22:21+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 192\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Thu, 15 Aug 2024 09:22:21 GMT\r\n\r\n{\"ticket\":\"gQHJ8DwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyaE8xaU5obmxjbkYxVGRsQmhDY1cAAgTNyL1mAwQAjScA\",\"expire_seconds\":2592000,\"url\":\"http:\\/\\/weixin.qq.com\\/q\\/02hO1iNhnlcnF1TdlBhCcW\"}"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T17:22:39+08:00","M":"POST https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=83_HgqCjNIkKPGe_jIVDhx5LSmwI8Q7Am7-Acr2FeDNla7HeXGu-A-rFCgHSrA9d2sH9eUCvo7g_0KkE6tlcpfoX75Dn8wkmmwgA-EfVwiPUOA1uMY0vy0Hf9u-6acCHMaAAAJOT&debug=1 request header: { Content-Type:application/jsonAccept:*/*} request body:{\"action_info\":{\"scene\":{\"scene_str\":\"7cd96062-5ade-11ef-9e17-902e16172287\"}},\"action_name\":\"QR_STR_SCENE\",\"expire_seconds\":2592000}\n"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T17:22:39+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 192\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Thu, 15 Aug 2024 09:22:39 GMT\r\n\r\n{\"ticket\":\"gQHz8DwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyX3k1Yk5XbmxjbkYxVHZsQjFDYzMAAgTfyL1mAwQAjScA\",\"expire_seconds\":2592000,\"url\":\"http:\\/\\/weixin.qq.com\\/q\\/02_y5bNWnlcnF1TvlB1Cc3\"}"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T17:24:17+08:00","M":"POST https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=83_HgqCjNIkKPGe_jIVDhx5LSmwI8Q7Am7-Acr2FeDNla7HeXGu-A-rFCgHSrA9d2sH9eUCvo7g_0KkE6tlcpfoX75Dn8wkmmwgA-EfVwiPUOA1uMY0vy0Hf9u-6acCHMaAAAJOT&debug=1 request header: { Content-Type:application/jsonAccept:*/*} request body:{\"action_info\":{\"scene\":{\"scene_str\":\"7cd96062-5ade-11ef-9e17-902e16172287\"}},\"action_name\":\"QR_STR_SCENE\",\"expire_seconds\":2592000}\n"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T17:24:17+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 192\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Thu, 15 Aug 2024 09:24:17 GMT\r\n\r\n{\"ticket\":\"gQGL8DwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyWndrRE5GbmxjbkYxUjFtQnhDYzcAAgRByb1mAwQAjScA\",\"expire_seconds\":2592000,\"url\":\"http:\\/\\/weixin.qq.com\\/q\\/02ZwkDNFnlcnF1R1mBxCc7\"}"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T21:46:59+08:00","M":"Server response created:","content":"2932968073927229439"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T21:47:37+08:00","M":"Server response created:","content":"6631222197266362111"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T21:47:48+08:00","M":"Server response created:","content":"3904152095992776479"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T21:48:35+08:00","M":"Server response created:","content":"7016009957992470331"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T21:51:45+08:00","M":"Server response created:","content":"4905816075205062651"}
|
||||
{"L":"INFO","timestamp":"2024-08-15T23:24:38+08:00","M":"Server response created:","content":"3390456157377093054"}
|
Reference in New Issue
Block a user