user weixinLogin #1
This commit is contained in:
parent
a9e8e818be
commit
45d72de8e5
@ -6,10 +6,13 @@ import (
|
|||||||
"catface/app/model"
|
"catface/app/model"
|
||||||
"catface/app/service/users/curd"
|
"catface/app/service/users/curd"
|
||||||
userstoken "catface/app/service/users/token"
|
userstoken "catface/app/service/users/token"
|
||||||
|
"catface/app/service/weixin"
|
||||||
"catface/app/utils/response"
|
"catface/app/utils/response"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Users struct {
|
type Users struct {
|
||||||
@ -17,12 +20,12 @@ type Users struct {
|
|||||||
|
|
||||||
// 1.用户注册
|
// 1.用户注册
|
||||||
func (u *Users) Register(context *gin.Context) {
|
func (u *Users) Register(context *gin.Context) {
|
||||||
// 由于本项目骨架已经将表单验证器的字段(成员)绑定在上下文,因此可以按照 GetString()、context.GetBool()、GetFloat64()等快捷获取需要的数据类型,注意:相关键名规则: 前缀+验证器结构体中的 json 标签
|
// 由于本项目骨架已经将表单验证器的字段(成员)绑定在上下文,因此可以按照 GetString()、context.GetBool()、GetFloat64()等快捷获取需要的数据类型,注意:相关键名规则: 前缀+验证器结构体中的 json 标签
|
||||||
// 注意:在 ginskeleton 中获取表单参数验证器中的数字键(字段),请统一使用 GetFloat64(),其它获取数字键(字段)的函数无效,例如:GetInt()、GetInt64()等
|
// ATT 注意:在 ginskeleton 中获取表单参数验证器中的数字键(字段),请统一使用 GetFloat64(),其它获取数字键(字段)的函数无效,例如:GetInt()、GetInt64()等
|
||||||
// 当然也可以通过gin框架的上下文原始方法获取,例如: context.PostForm("user_name") 获取,这样获取的数据格式为文本,需要自己继续转换
|
// 当然也可以通过gin框架的上下文原始方法获取,例如: context.PostForm("user_name") 获取,这样获取的数据格式为文本,需要自己继续转换
|
||||||
userName := context.GetString(consts.ValidatorPrefix + "user_name")
|
userName := context.GetString(consts.ValidatorPrefix + "user_name")
|
||||||
pass := context.GetString(consts.ValidatorPrefix + "pass")
|
pass := context.GetString(consts.ValidatorPrefix + "pass")
|
||||||
userIp := context.ClientIP()
|
userIp := context.ClientIP() // INFO 通过上下文获取 IP 信息。
|
||||||
if curd.CreateUserCurdFactory().Register(userName, pass, userIp) {
|
if curd.CreateUserCurdFactory().Register(userName, pass, userIp) {
|
||||||
response.Success(context, consts.CurdStatusOkMsg, "")
|
response.Success(context, consts.CurdStatusOkMsg, "")
|
||||||
} else {
|
} else {
|
||||||
@ -35,6 +38,8 @@ func (u *Users) Login(context *gin.Context) {
|
|||||||
userName := context.GetString(consts.ValidatorPrefix + "user_name")
|
userName := context.GetString(consts.ValidatorPrefix + "user_name")
|
||||||
pass := context.GetString(consts.ValidatorPrefix + "pass")
|
pass := context.GetString(consts.ValidatorPrefix + "pass")
|
||||||
phone := context.GetString(consts.ValidatorPrefix + "phone")
|
phone := context.GetString(consts.ValidatorPrefix + "phone")
|
||||||
|
|
||||||
|
// 1. 先检查 账号密码是否正确,然后再检查 Token 状态。
|
||||||
userModelFact := model.CreateUserFactory("")
|
userModelFact := model.CreateUserFactory("")
|
||||||
userModel := userModelFact.Login(userName, pass)
|
userModel := userModelFact.Login(userName, pass)
|
||||||
|
|
||||||
@ -143,3 +148,39 @@ func (u *Users) Destroy(context *gin.Context) {
|
|||||||
response.Fail(context, consts.CurdDeleteFailCode, consts.CurdDeleteFailMsg, "")
|
response.Fail(context, consts.CurdDeleteFailCode, consts.CurdDeleteFailMsg, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK Start by Hav;
|
||||||
|
func (u *Users) WeixinLogin(context *gin.Context) {
|
||||||
|
code := context.GetString(consts.ValidatorPrefix + "code")
|
||||||
|
userAvatar := context.GetString(consts.ValidatorPrefix + "user_avatar")
|
||||||
|
userName := context.GetString(consts.ValidatorPrefix + "user_name")
|
||||||
|
userIp := context.ClientIP() // INFO 通过上下文获取 IP 信息。
|
||||||
|
|
||||||
|
// 1. 访问 微信 API 获取 openid
|
||||||
|
openId, err := weixin.Code2Session(code)
|
||||||
|
if err != nil {
|
||||||
|
// 解析微信登录成功,返回用户信息
|
||||||
|
fmt.Println(err) // TODO 换成 LOG
|
||||||
|
response.Fail(context, consts.CurdLoginFailCode, consts.CurdLoginFailMsg, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 执行 CURD
|
||||||
|
if UsersModel, err := curd.CreateUserFactory().WeixinLogin(openId, userName, userAvatar) {
|
||||||
|
if userId > 0 {
|
||||||
|
// 3. 生成 token
|
||||||
|
token, err := userstoken.CreateUserFactory().GenerateToken(userId, userName, "", 0)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(context, consts.CurdLoginFailCode, consts.CurdLoginFailMsg, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 返回 token
|
||||||
|
res := gin.H{
|
||||||
|
"userId": UsersModel.userId,
|
||||||
|
"permission": UsersModel.Permission
|
||||||
|
"token": token,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
response.Fail(context, consts.CurdLoginFailCode, consts.CurdLoginFailMsg, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -21,6 +21,10 @@ func WebRegisterValidator() {
|
|||||||
containers.Set(key, users.Register{})
|
containers.Set(key, users.Register{})
|
||||||
key = consts.ValidatorPrefix + "UsersLogin"
|
key = consts.ValidatorPrefix + "UsersLogin"
|
||||||
containers.Set(key, users.Login{})
|
containers.Set(key, users.Login{})
|
||||||
|
|
||||||
|
key = consts.ValidatorPrefix + "UsersWeixinLogin"
|
||||||
|
containers.Set(key, users.WeixinLogin{})
|
||||||
|
|
||||||
key = consts.ValidatorPrefix + "RefreshToken"
|
key = consts.ValidatorPrefix + "RefreshToken"
|
||||||
containers.Set(key, users.RefreshToken{})
|
containers.Set(key, users.RefreshToken{})
|
||||||
|
|
||||||
|
@ -32,5 +32,4 @@ func (l Login) CheckParams(context *gin.Context) {
|
|||||||
// 验证完成,调用控制器,并将验证器成员(字段)递给控制器,保持上下文数据一致性
|
// 验证完成,调用控制器,并将验证器成员(字段)递给控制器,保持上下文数据一致性
|
||||||
(&web.Users{}).Login(extraAddBindDataContext)
|
(&web.Users{}).Login(extraAddBindDataContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
33
app/http/validator/web/users/weixin_login.go
Normal file
33
app/http/validator/web/users/weixin_login.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package users
|
||||||
|
|
||||||
|
import (
|
||||||
|
"catface/app/global/consts"
|
||||||
|
"catface/app/http/controller/web"
|
||||||
|
"catface/app/http/validator/core/data_transfer"
|
||||||
|
"catface/app/utils/response"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WeixinLogin struct {
|
||||||
|
Code string `json:"code"`
|
||||||
|
UserName string `json:"user_name"`
|
||||||
|
UserAvatar string `json:"user_avatar"` // INFO 本地缓存,不确定 url 的类型。
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w WeixinLogin) CheckParams(context *gin.Context) {
|
||||||
|
//1.先按照验证器提供的基本语法,基本可以校验90%以上的不合格参数
|
||||||
|
if err := context.ShouldBind(&w); err != nil {
|
||||||
|
response.ValidatorError(context, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// INFO 该函数主要是将本结构体的字段(成员)按照 consts.ValidatorPrefix+ json标签对应的 键 => 值 形式绑定在上下文,便于下一步(控制器)可以直接通过 context.Get(键) 获取相关值
|
||||||
|
extraAddBindDataContext := data_transfer.DataAddContext(w, consts.ValidatorPrefix, context)
|
||||||
|
if extraAddBindDataContext == nil {
|
||||||
|
response.ErrorSystem(context, "userLogin表单验证器json化失败", "")
|
||||||
|
} else {
|
||||||
|
// 验证完成,调用控制器,并将验证器成员(字段)递给控制器,保持上下文数据一致性
|
||||||
|
(&web.Users{}).WeixinLogin(extraAddBindDataContext)
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 操作数据库喜欢使用gorm自带语法的开发者可以参考 GinSkeleton-Admin 系统相关代码
|
// 操作数据库喜欢使用gorm自带语法的开发者可以参考 GinSkeleton-Admin 系统相关代码
|
||||||
@ -22,24 +23,25 @@ func CreateUserFactory(sqlType string) *UsersModel {
|
|||||||
|
|
||||||
type UsersModel struct {
|
type UsersModel struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
UserName string `gorm:"column:user_name" json:"user_name"`
|
UserName string `gorm:"column:user_name;size:20" json:"user_name"`
|
||||||
Pass string `json:"-"` // INFO 暂时用不到,但先保留。
|
Pass string `json:"-"` // INFO 暂时用不到,但先保留。
|
||||||
Phone string `json:"phone"`
|
Phone string `json:"phone"`
|
||||||
RealName string `gorm:"column:real_name" json:"real_name"`
|
RealName string `gorm:"column:real_name" json:"real_name"`
|
||||||
// TAG 状态管理
|
// TAG 状态管理
|
||||||
Status int `json:"status"` // QUESTION
|
Status uint8 `json:"status"` // QUESTION
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
LastLoginIp string `gorm:"column:last_login_ip" json:"last_login_ip"`
|
LastLoginIp string `gorm:"column:last_login_ip" json:"last_login_ip"`
|
||||||
// TAG MySELF
|
// TAG MySELF
|
||||||
Permissions int `json:"permissions"`
|
UserAvatar string `gorm:"column:user_avatar;size:255" json:"user_avatar"` // TODO 暂时存储 url,之后考虑需要把文件上传到 Nginx
|
||||||
|
Permission uint8 `json:"permission" gorm:"default:9"`
|
||||||
// TAG 微信登录相关
|
// TAG 微信登录相关
|
||||||
OpenId string `gorm:"column:open_id;size:35" json:"open_id"`
|
OpenId string `gorm:"column:open_id;size:35;index" json:"open_id"`
|
||||||
SessionKey string `gorm:"column:session_key;size:35" json:"session_key"`
|
SessionKey string `gorm:"column:session_key;size:35" json:"session_key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 表名
|
// 表名
|
||||||
func (u *UsersModel) TableName() string {
|
func (u *UsersModel) TableName() string { // TIP GORM 也会自动调用这个函数。
|
||||||
return "tb_users"
|
return "users"
|
||||||
}
|
}
|
||||||
|
|
||||||
// 用户注册(写一个最简单的使用账号、密码注册即可)
|
// 用户注册(写一个最简单的使用账号、密码注册即可)
|
||||||
@ -306,3 +308,26 @@ func (u *UsersModel) DelTokenCacheFromRedis(userId int64) {
|
|||||||
tokenCacheRedisFact.ClearUserToken()
|
tokenCacheRedisFact.ClearUserToken()
|
||||||
tokenCacheRedisFact.ReleaseRedisConn()
|
tokenCacheRedisFact.ReleaseRedisConn()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
func (u *UsersModel) WeixinLogin(openId string, name string, avatar string) (temp *UsersModel, err error) {
|
||||||
|
db := u.DB
|
||||||
|
|
||||||
|
var user UsersModel
|
||||||
|
if result := db.Where("open_id = ?", openId).First(&user); result.Error != nil {
|
||||||
|
temp = &user
|
||||||
|
} else if result.Error == gorm.ErrRecordNotFound {
|
||||||
|
newUser := UsersModel{OpenId: openId, UserName: name, UserAvatar: avatar}
|
||||||
|
if err := db.Create(&newUser).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
temp = &newUser // INFO 这里应该就是 GORM 插入后得到的对象。
|
||||||
|
} else {
|
||||||
|
return nil, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return temp, nil
|
||||||
|
}
|
||||||
|
39
app/service/weixin/code2Session.go
Normal file
39
app/service/weixin/code2Session.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package weixin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"catface/app/global/variable"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Code2Session(js_code string) (string, error) {
|
||||||
|
appid := variable.ConfigYml.GetString("Weixin.AppId")
|
||||||
|
appSecret := variable.ConfigYml.GetString("Weixin.AppSecret")
|
||||||
|
grantType := variable.ConfigYml.GetString("Weixin.Code2Session.GrantType")
|
||||||
|
|
||||||
|
url := fmt.Sprintf("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=%s", appid, appSecret, js_code, grantType)
|
||||||
|
|
||||||
|
// 创建一个新的HTTP请求
|
||||||
|
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("error creating request: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送HTTP请求
|
||||||
|
client := &http.Client{}
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("error sending request: %v", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// 读取响应体
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("error reading response body: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回响应体
|
||||||
|
return string(body), nil
|
||||||
|
}
|
@ -140,4 +140,12 @@ RabbitMq:
|
|||||||
Captcha:
|
Captcha:
|
||||||
captchaId: "captcha_id" # 验证码id提交时的键名
|
captchaId: "captcha_id" # 验证码id提交时的键名
|
||||||
captchaValue: "captcha_value" #验证码值提交时的键名
|
captchaValue: "captcha_value" #验证码值提交时的键名
|
||||||
length: 4 # 验证码生成时的长度
|
length: 4 # 验证码生成时的长度
|
||||||
|
|
||||||
|
WeixinServer:
|
||||||
|
AppId: "wxe1ff76a57cc6eed3"
|
||||||
|
AppSecret: "46a3557653462da34c6e69f17a472c7c"
|
||||||
|
|
||||||
|
Code2Session:
|
||||||
|
grant_type: "authorization_code" # 主要就是想避免硬编码。
|
||||||
|
|
17
test/usersModel_test.go
Normal file
17
test/usersModel_test.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// add_test.go
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"catface/app/model"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUsers(t *testing.T) {
|
||||||
|
Init()
|
||||||
|
|
||||||
|
user := model.UsersModel{}
|
||||||
|
err := DB.AutoMigrate(&user)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user