🎨 优化微信登录流程&新增手机和微信绑定接口
This commit is contained in:
@@ -3,6 +3,9 @@ package app
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"git.echol.cn/loser/lckt/global"
|
||||
"git.echol.cn/loser/lckt/model/app"
|
||||
r "git.echol.cn/loser/lckt/model/common/response"
|
||||
@@ -13,7 +16,6 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"go.uber.org/zap"
|
||||
"time"
|
||||
)
|
||||
|
||||
type AppUserApi struct{}
|
||||
@@ -63,14 +65,14 @@ func (*AppUserApi) Login(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = global.GVA_REDIS.Get(ctx, user.Phone).Result(); errors.Is(err, redis.Nil) {
|
||||
if _, err = global.GVA_REDIS.Get(ctx, strconv.Itoa(int(user.ID))).Result(); errors.Is(err, redis.Nil) {
|
||||
// 此处过期时间等于jwt过期时间
|
||||
dr, err := utils.ParseDuration(global.GVA_CONFIG.JWT.ExpiresTime)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
timer := dr
|
||||
if err := global.GVA_REDIS.Set(ctx, user.Phone, token, timer).Err(); err != nil {
|
||||
if err := global.GVA_REDIS.Set(ctx, strconv.Itoa(int(user.ID)), token, timer).Err(); err != nil {
|
||||
global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err))
|
||||
r.FailWithMessage("设置登录状态失败", ctx)
|
||||
return
|
||||
@@ -115,19 +117,26 @@ func (*AppUserApi) WechatLogin(ctx *gin.Context) {
|
||||
r.FailWithMessage("获取token失败", ctx)
|
||||
return
|
||||
}
|
||||
if _, err = global.GVA_REDIS.Get(ctx, user.Phone).Result(); errors.Is(err, redis.Nil) {
|
||||
if _, err = global.GVA_REDIS.Get(ctx, strconv.Itoa(int(user.ID))).Result(); errors.Is(err, redis.Nil) {
|
||||
// 此处过期时间等于jwt过期时间
|
||||
dr, err := utils.ParseDuration(global.GVA_CONFIG.JWT.ExpiresTime)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
timer := dr
|
||||
if err := global.GVA_REDIS.Set(ctx, user.Phone, token, timer).Err(); err != nil {
|
||||
if err := global.GVA_REDIS.Set(ctx, strconv.Itoa(int(user.ID)), token, timer).Err(); err != nil {
|
||||
global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err))
|
||||
r.FailWithMessage("设置登录状态失败", ctx)
|
||||
return
|
||||
}
|
||||
user_jwt.SetToken(ctx, token, int(claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix()))
|
||||
|
||||
result := map[string]interface{}{}
|
||||
result["User"] = user
|
||||
result["Token"] = token
|
||||
result["ExpiresAt"] = claims.RegisteredClaims.ExpiresAt.Unix() * 1000
|
||||
fmt.Println(result)
|
||||
|
||||
r.OkWithDetailed(gin.H{
|
||||
"User": user,
|
||||
"Token": token,
|
||||
@@ -182,7 +191,7 @@ func (*AppUserApi) PwdLogin(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
timer := dr
|
||||
if err := global.GVA_REDIS.Set(ctx, user.Phone, token, timer).Err(); err != nil {
|
||||
if err := global.GVA_REDIS.Set(ctx, strconv.Itoa(int(user.ID)), token, timer).Err(); err != nil {
|
||||
global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err))
|
||||
r.FailWithMessage("设置登录状态失败", ctx)
|
||||
return
|
||||
@@ -289,3 +298,74 @@ func (a *AppUserApi) GetTeacherApply(context *gin.Context) {
|
||||
|
||||
r.OkWithDetailed(status, "获取教师申请状态成功", context)
|
||||
}
|
||||
|
||||
// BindWechat 手机登录用户绑定微信
|
||||
func (a *AppUserApi) BindWechat(context *gin.Context) {
|
||||
var p request.BindWechatReq
|
||||
if err := context.ShouldBind(&p); err != nil {
|
||||
global.GVA_LOG.Error("绑定微信请求参数有误")
|
||||
r.FailWithMessage("绑定微信请求参数有误", context)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := appUserService.BindWechat(p)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("绑定微信失败", zap.Error(err))
|
||||
}
|
||||
|
||||
// 生成新token
|
||||
token, claims, err := user_jwt.LoginToken(*user)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取token失败!", zap.Error(err))
|
||||
r.FailWithMessage("获取token失败", context)
|
||||
return
|
||||
}
|
||||
|
||||
// 此处过期时间等于jwt过期时间
|
||||
dr, err := utils.ParseDuration(global.GVA_CONFIG.JWT.ExpiresTime)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("解析JWT过期时间失败", zap.Error(err))
|
||||
r.FailWithMessage("解析JWT过期时间失败", context)
|
||||
return
|
||||
}
|
||||
|
||||
timer := dr
|
||||
if err := global.GVA_REDIS.Set(context, user.Phone, token, timer).Err(); err != nil {
|
||||
global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err))
|
||||
r.FailWithMessage("设置登录状态失败", context)
|
||||
return
|
||||
}
|
||||
|
||||
user_jwt.SetToken(context, token, int(claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix()))
|
||||
r.OkWithDetailed(gin.H{
|
||||
"User": user,
|
||||
"Token": token,
|
||||
"ExpiresAt": claims.RegisteredClaims.ExpiresAt.Unix() * 1000,
|
||||
}, "绑定微信成功", context)
|
||||
}
|
||||
|
||||
// BindPhone 微信登录用户绑定手机号s
|
||||
func (a *AppUserApi) BindPhone(context *gin.Context) {
|
||||
var p request.BindPhoneReq
|
||||
if err := context.ShouldBind(&p); err != nil {
|
||||
global.GVA_LOG.Error("绑定手机号请求参数有误")
|
||||
r.FailWithMessage("绑定手机号请求参数有误", context)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证码检查
|
||||
if result, _ := global.GVA_REDIS.Get(context, fmt.Sprintf("VerifyCode:%s", p.Phone)).Result(); result != p.Code {
|
||||
global.GVA_LOG.Error("验证码错误", zap.String("phone", p.Phone))
|
||||
r.FailWithMessage("验证码错误", context)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := appUserService.BindPhone(p)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("绑定手机号失败", zap.Error(err))
|
||||
r.FailWithMessage("绑定手机号失败", context)
|
||||
return
|
||||
}
|
||||
|
||||
r.OkWithDetailed(user, "绑定手机号成功", context)
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package user
|
||||
|
||||
import (
|
||||
"git.echol.cn/loser/lckt/global"
|
||||
"git.echol.cn/loser/lckt/model/app"
|
||||
common "git.echol.cn/loser/lckt/model/common/request"
|
||||
r "git.echol.cn/loser/lckt/model/common/response"
|
||||
"git.echol.cn/loser/lckt/model/user/request"
|
||||
@@ -138,3 +139,19 @@ func (a *UserApi) GetTeacherApplyList(context *gin.Context) {
|
||||
PageSize: p.PageSize,
|
||||
}, "获取教师申请列表成功", context)
|
||||
}
|
||||
|
||||
// UpdateTeacherApplyStatus 更新教师申请状态
|
||||
func (a *UserApi) UpdateTeacherApplyStatus(context *gin.Context) {
|
||||
var p app.TeacherApply
|
||||
if err := context.ShouldBind(&p); err != nil {
|
||||
r.FailWithMessage(err.Error(), context)
|
||||
global.GVA_LOG.Error("参数错误,更新教师申请状态失败", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err := userService.UpdateTeacherApplyStatus(p); err != nil {
|
||||
r.FailWithMessage("更新教师申请状态失败", context)
|
||||
return
|
||||
}
|
||||
r.OkWithMessage("更新教师申请状态成功", context)
|
||||
}
|
||||
|
@@ -1,18 +1,19 @@
|
||||
package initialize
|
||||
|
||||
import (
|
||||
"git.echol.cn/loser/lckt/plugin/customerservice"
|
||||
"git.echol.cn/loser/lckt/plugin/picturelibrary"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"git.echol.cn/loser/lckt/docs"
|
||||
"git.echol.cn/loser/lckt/global"
|
||||
"git.echol.cn/loser/lckt/middleware"
|
||||
"git.echol.cn/loser/lckt/plugin/customerservice"
|
||||
"git.echol.cn/loser/lckt/plugin/picturelibrary"
|
||||
"git.echol.cn/loser/lckt/router"
|
||||
gc "github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
swaggerFiles "github.com/swaggo/files"
|
||||
ginSwagger "github.com/swaggo/gin-swagger"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
type justFilesFilesystem struct {
|
||||
@@ -38,6 +39,17 @@ func (fs justFilesFilesystem) Open(name string) (http.File, error) {
|
||||
func Routers() *gin.Engine {
|
||||
Router := gin.New()
|
||||
Router.Use(gin.Recovery())
|
||||
Router.Use(middleware.AllCors())
|
||||
|
||||
Router.Use(gc.New(gc.Config{
|
||||
AllowAllOrigins: true, // 允许所有来源
|
||||
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
|
||||
AllowHeaders: []string{"*"}, // 允许所有自定义header
|
||||
ExposeHeaders: []string{"Content-Length", "Content-Type"},
|
||||
AllowCredentials: true,
|
||||
MaxAge: 12 * time.Hour,
|
||||
}))
|
||||
|
||||
if gin.Mode() == gin.DebugMode {
|
||||
Router.Use(gin.Logger())
|
||||
}
|
||||
@@ -55,7 +67,7 @@ func Routers() *gin.Engine {
|
||||
|
||||
Router.StaticFS(global.GVA_CONFIG.Local.StorePath, justFilesFilesystem{http.Dir(global.GVA_CONFIG.Local.StorePath)}) // Router.Use(middleware.LoadTls()) // 如果需要使用https 请打开此中间件 然后前往 core/server.go 将启动模式 更变为 Router.RunTLS("端口","你的cre/pem文件","你的key文件")
|
||||
// 跨域,如需跨域可以打开下面的注释
|
||||
// Router.Use(middleware.Cors()) // 直接放行全部跨域请求
|
||||
// Router.Use(middleware.AllCors()) // 直接放行全部跨域请求
|
||||
// Router.Use(middleware.CorsByRules()) // 按照配置的规则放行跨域请求
|
||||
// global.GVA_LOG.Info("use middleware cors")
|
||||
docs.SwaggerInfo.BasePath = global.GVA_CONFIG.System.RouterPrefix
|
||||
@@ -64,13 +76,13 @@ func Routers() *gin.Engine {
|
||||
// 方便统一添加路由组前缀 多服务器上线使用
|
||||
|
||||
PublicGroup := Router.Group(global.GVA_CONFIG.System.RouterPrefix)
|
||||
PublicGroup.Use(middleware.Cors()) // 直接放行全部跨域请求
|
||||
PublicGroup.Use(middleware.AllCors()) // 直接放行全部跨域请求
|
||||
PrivateGroup := Router.Group(global.GVA_CONFIG.System.RouterPrefix)
|
||||
|
||||
PrivateGroup.Use(middleware.JWTAuth()).Use(middleware.CasbinHandler()).Use(middleware.Cors())
|
||||
PrivateGroup.Use(middleware.JWTAuth()).Use(middleware.CasbinHandler()).Use(middleware.AllCors())
|
||||
AppAuthGroup := Router.Group(global.GVA_CONFIG.System.RouterPrefix)
|
||||
AppAuthGroup.Use(middleware.Cors())
|
||||
//AppAuthGroup.Use(middleware.UserJWTAuth()).Use(middleware.Cors())
|
||||
AppAuthGroup.Use(middleware.AllCors())
|
||||
//AppAuthGroup.Use(middleware.UserJWTAuth()).Use(middleware.AllCors())
|
||||
{
|
||||
// 健康监测
|
||||
PublicGroup.GET("/health", func(c *gin.Context) {
|
||||
|
@@ -7,7 +7,7 @@ type SendCodeReq struct {
|
||||
}
|
||||
|
||||
type CodeLoginReq struct {
|
||||
Phone string `json:"phone" form:"phone" vd:"@:len($)>0; msg:'请输入手机号码'"`
|
||||
Phone string `json:"phone" form:"phone"`
|
||||
Code string `json:"code" form:"code" vd:"@:len($)>0; msg:'请输入短信验证码'"`
|
||||
}
|
||||
|
||||
@@ -35,8 +35,10 @@ type BindWechatReq struct {
|
||||
}
|
||||
|
||||
type BindPhoneReq struct {
|
||||
Id int `json:"id" form:"id" vd:"@:len($)>0; msg:'用户ID不能为空'"`
|
||||
Phone string `json:"phone" form:"phone" vd:"@:len($)>0; msg:'手机号码不能为空'"`
|
||||
Id int `json:"id" form:"id" vd:"@:len($)>0; msg:'用户ID不能为空'"`
|
||||
Phone string `json:"phone" form:"phone" vd:"@:len($)>0; msg:'手机号码不能为空'"`
|
||||
Code string `json:"code" form:"code" vd:"@:len($)>0; msg:'验证码不能为空'"`
|
||||
PassWord string `json:"password" form:"password" vd:"@:len($)>0; msg:'密码不能为空'"`
|
||||
}
|
||||
|
||||
type GetUserListReq struct {
|
||||
|
@@ -17,6 +17,8 @@ func (s *UserRouter) InitAppUserRouter(AppAuthGroup, PublicRouter *gin.RouterGro
|
||||
}
|
||||
{
|
||||
publicRouter.POST("wxLogin", userApi.WechatLogin) // 微信登录
|
||||
publicRouter.POST("bindWX", userApi.BindWechat) // 绑定微信
|
||||
publicRouter.POST("bindPhone", userApi.BindPhone) // 获取用户信息
|
||||
publicRouter.POST("pwdlogin", userApi.PwdLogin) // 密码登录
|
||||
publicRouter.POST("sms/send", userApi.SendCode) // 发送短信验证码
|
||||
publicRouter.POST("login", userApi.Login) // 短信验证码登录
|
||||
|
@@ -11,12 +11,13 @@ type UserRouter struct{}
|
||||
func (s *UserRouter) InitUserRouter(Router *gin.RouterGroup, PublicRouter *gin.RouterGroup) {
|
||||
userRouter := Router.Group("app_user").Use(middleware.OperationRecord())
|
||||
{
|
||||
userRouter.GET("list", userApi.GetUserList) // 获取用户列表
|
||||
userRouter.PUT("setBalance", userApi.SetBalance) // 更新用户余额
|
||||
userRouter.POST("register", userApi.Register) // 注册
|
||||
userRouter.PUT("status/:id", userApi.SetUserStatus) // 更新用户状态
|
||||
userRouter.GET(":id", userApi.GetUserById) // 获取用户信息
|
||||
userRouter.GET("/teachers", userApi.GetTeachers) // 获取教师列表
|
||||
userRouter.GET("/teacherApplyList", userApi.GetTeacherApplyList) // 获取教师信息
|
||||
userRouter.GET("list", userApi.GetUserList) // 获取用户列表
|
||||
userRouter.PUT("setBalance", userApi.SetBalance) // 更新用户余额
|
||||
userRouter.POST("register", userApi.Register) // 注册
|
||||
userRouter.PUT("status/:id", userApi.SetUserStatus) // 更新用户状态
|
||||
userRouter.GET(":id", userApi.GetUserById) // 获取用户信息
|
||||
userRouter.GET("/teachers", userApi.GetTeachers) // 获取教师列表
|
||||
userRouter.GET("/teacherApplyList", userApi.GetTeacherApplyList) // 获取教师信息
|
||||
userRouter.PUT("/teacherApply/status", userApi.UpdateTeacherApplyStatus) // 更新教师申请状态
|
||||
}
|
||||
}
|
||||
|
@@ -175,3 +175,49 @@ func (u *AppUserService) GetTeacherApplyStatus(id uint) (teacherApply app.Teache
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// BindWechat 手机登录用户绑定微信
|
||||
func (u *AppUserService) BindWechat(p request.BindWechatReq) (*user.User, error) {
|
||||
var userInfo user.User
|
||||
err := global.GVA_DB.Model(&user.User{}).Where("id = ?", p.Id).First(&userInfo).Error
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("查询用户失败", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if userInfo.OpenId != "" {
|
||||
global.GVA_LOG.Error("用户已绑定微信")
|
||||
return nil, fmt.Errorf("用户已绑定微信")
|
||||
}
|
||||
|
||||
userInfo.OpenId = p.Openid
|
||||
|
||||
err = global.GVA_DB.Save(&userInfo).Error
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("绑定微信失败", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &userInfo, nil
|
||||
}
|
||||
|
||||
// BindPhone 微信登录用户绑定手机号
|
||||
func (u *AppUserService) BindPhone(p request.BindPhoneReq) (*user.User, error) {
|
||||
var userInfo user.User
|
||||
err := global.GVA_DB.Model(&user.User{}).Where("id = ?", p.Id).First(&userInfo).Error
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("查询用户失败", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userInfo.Phone = p.Phone
|
||||
pwd, _ := bcrypt.GenerateFromPassword([]byte(p.PassWord), bcrypt.DefaultCost)
|
||||
userInfo.Password = string(pwd)
|
||||
err = global.GVA_DB.Save(&userInfo).Error
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("绑定微信失败", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &userInfo, nil
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
common "git.echol.cn/loser/lckt/model/common/request"
|
||||
"git.echol.cn/loser/lckt/model/user"
|
||||
"git.echol.cn/loser/lckt/model/user/request"
|
||||
"git.echol.cn/loser/lckt/utils/sms"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"math/rand"
|
||||
@@ -43,11 +44,11 @@ func (u *UserService) SendCode(req request.SendCodeReq) (err error) {
|
||||
rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
verifyCode := fmt.Sprintf("%06v", rand.Int31n(1000000))
|
||||
|
||||
//if ok := sms.SendSMS(req.Phone, verifyCode); !ok {
|
||||
// global.GVA_LOG.Error("发送验证码失败")
|
||||
// return
|
||||
//}
|
||||
//
|
||||
if ok := sms.DxbSendSMS(req.Phone, verifyCode); !ok {
|
||||
global.GVA_LOG.Error("发送验证码失败")
|
||||
return
|
||||
}
|
||||
|
||||
if err = rdb.Set(context.Background(), key, verifyCode, 5*time.Minute).Err(); err != nil {
|
||||
global.GVA_LOG.Error("设置验证码缓存失败", zap.Error(err))
|
||||
return
|
||||
@@ -202,3 +203,28 @@ func (u *UserService) GetTeacherApplyList(p request.GetTeacherApplyListReq) (lis
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (u *UserService) UpdateTeacherApplyStatus(p app.TeacherApply) (err error) {
|
||||
err = global.GVA_DB.Save(&p).Error
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("更新教师申请状态失败", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
// 如果申请通过,更新用户类型为教师
|
||||
if p.Status == 1 {
|
||||
var user user.User
|
||||
err = global.GVA_DB.Model(&user).Where("id = ?", p.UserId).First(&user).Error
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("查询用户信息失败", zap.Error(err))
|
||||
return
|
||||
}
|
||||
user.UserType = 2 // 设置为教师
|
||||
err = global.GVA_DB.Save(&user).Error
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("更新用户类型失败", zap.Error(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@ var WechatPay *payment.Payment
|
||||
func InitWeOfficial() {
|
||||
OfficialAccountApp, err := officialAccount.NewOfficialAccount(&officialAccount.UserConfig{
|
||||
AppID: "wx3d21df18d7f8f9fc", // 公众号、小程序的appid
|
||||
Secret: "ffce59a9a9272c1aaee53950e96617d8", //
|
||||
Secret: "3ab19e9b6a5e155c25ac6457be650047", //
|
||||
|
||||
Log: officialAccount.Log{
|
||||
Level: "debug",
|
||||
|
Reference in New Issue
Block a user