user weixinLogin #1
This commit is contained in:
parent
a9e8e818be
commit
45d72de8e5
@ -6,10 +6,13 @@ import (
|
||||
"catface/app/model"
|
||||
"catface/app/service/users/curd"
|
||||
userstoken "catface/app/service/users/token"
|
||||
"catface/app/service/weixin"
|
||||
"catface/app/utils/response"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
)
|
||||
|
||||
type Users struct {
|
||||
@ -17,12 +20,12 @@ type Users struct {
|
||||
|
||||
// 1.用户注册
|
||||
func (u *Users) Register(context *gin.Context) {
|
||||
// 由于本项目骨架已经将表单验证器的字段(成员)绑定在上下文,因此可以按照 GetString()、context.GetBool()、GetFloat64()等快捷获取需要的数据类型,注意:相关键名规则: 前缀+验证器结构体中的 json 标签
|
||||
// 注意:在 ginskeleton 中获取表单参数验证器中的数字键(字段),请统一使用 GetFloat64(),其它获取数字键(字段)的函数无效,例如:GetInt()、GetInt64()等
|
||||
// 由于本项目骨架已经将表单验证器的字段(成员)绑定在上下文,因此可以按照 GetString()、context.GetBool()、GetFloat64()等快捷获取需要的数据类型,注意:相关键名规则: 前缀+验证器结构体中的 json 标签
|
||||
// ATT 注意:在 ginskeleton 中获取表单参数验证器中的数字键(字段),请统一使用 GetFloat64(),其它获取数字键(字段)的函数无效,例如:GetInt()、GetInt64()等
|
||||
// 当然也可以通过gin框架的上下文原始方法获取,例如: context.PostForm("user_name") 获取,这样获取的数据格式为文本,需要自己继续转换
|
||||
userName := context.GetString(consts.ValidatorPrefix + "user_name")
|
||||
pass := context.GetString(consts.ValidatorPrefix + "pass")
|
||||
userIp := context.ClientIP()
|
||||
userIp := context.ClientIP() // INFO 通过上下文获取 IP 信息。
|
||||
if curd.CreateUserCurdFactory().Register(userName, pass, userIp) {
|
||||
response.Success(context, consts.CurdStatusOkMsg, "")
|
||||
} else {
|
||||
@ -35,6 +38,8 @@ func (u *Users) Login(context *gin.Context) {
|
||||
userName := context.GetString(consts.ValidatorPrefix + "user_name")
|
||||
pass := context.GetString(consts.ValidatorPrefix + "pass")
|
||||
phone := context.GetString(consts.ValidatorPrefix + "phone")
|
||||
|
||||
// 1. 先检查 账号密码是否正确,然后再检查 Token 状态。
|
||||
userModelFact := model.CreateUserFactory("")
|
||||
userModel := userModelFact.Login(userName, pass)
|
||||
|
||||
@ -143,3 +148,39 @@ func (u *Users) Destroy(context *gin.Context) {
|
||||
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{})
|
||||
key = consts.ValidatorPrefix + "UsersLogin"
|
||||
containers.Set(key, users.Login{})
|
||||
|
||||
key = consts.ValidatorPrefix + "UsersWeixinLogin"
|
||||
containers.Set(key, users.WeixinLogin{})
|
||||
|
||||
key = consts.ValidatorPrefix + "RefreshToken"
|
||||
containers.Set(key, users.RefreshToken{})
|
||||
|
||||
|
@ -32,5 +32,4 @@ func (l Login) CheckParams(context *gin.Context) {
|
||||
// 验证完成,调用控制器,并将验证器成员(字段)递给控制器,保持上下文数据一致性
|
||||
(&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"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// 操作数据库喜欢使用gorm自带语法的开发者可以参考 GinSkeleton-Admin 系统相关代码
|
||||
@ -22,24 +23,25 @@ func CreateUserFactory(sqlType string) *UsersModel {
|
||||
|
||||
type UsersModel struct {
|
||||
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 暂时用不到,但先保留。
|
||||
Phone string `json:"phone"`
|
||||
RealName string `gorm:"column:real_name" json:"real_name"`
|
||||
// TAG 状态管理
|
||||
Status int `json:"status"` // QUESTION
|
||||
Status uint8 `json:"status"` // QUESTION
|
||||
Token string `json:"token"`
|
||||
LastLoginIp string `gorm:"column:last_login_ip" json:"last_login_ip"`
|
||||
// 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 微信登录相关
|
||||
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"`
|
||||
}
|
||||
|
||||
// 表名
|
||||
func (u *UsersModel) TableName() string {
|
||||
return "tb_users"
|
||||
func (u *UsersModel) TableName() string { // TIP GORM 也会自动调用这个函数。
|
||||
return "users"
|
||||
}
|
||||
|
||||
// 用户注册(写一个最简单的使用账号、密码注册即可)
|
||||
@ -306,3 +308,26 @@ func (u *UsersModel) DelTokenCacheFromRedis(userId int64) {
|
||||
tokenCacheRedisFact.ClearUserToken()
|
||||
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:
|
||||
captchaId: "captcha_id" # 验证码id提交时的键名
|
||||
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