|
|
package users
|
|
|
|
|
|
import (
|
|
|
"crypto/aes"
|
|
|
"crypto/cipher"
|
|
|
"encoding/json"
|
|
|
"errors"
|
|
|
"fmt"
|
|
|
"io"
|
|
|
"io/ioutil"
|
|
|
"log"
|
|
|
"net/http"
|
|
|
"net/url"
|
|
|
"os"
|
|
|
"path/filepath"
|
|
|
"recook/internal/back"
|
|
|
"recook/internal/cache"
|
|
|
"recook/internal/dbc"
|
|
|
. "recook/internal/dbc"
|
|
|
"recook/internal/define"
|
|
|
"recook/internal/model/user"
|
|
|
service "recook/internal/service/app"
|
|
|
"recook/internal/static_path"
|
|
|
"recook/internal/v2/model/company"
|
|
|
"recook/tools"
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
"github.com/go-redis/redis"
|
|
|
"github.com/golangkit/formatime"
|
|
|
"github.com/jinzhu/gorm"
|
|
|
)
|
|
|
|
|
|
type weChatLogin struct {
|
|
|
WxType string `json:"wxType"`
|
|
|
Code string `json:"code" validate:"required"`
|
|
|
}
|
|
|
|
|
|
type mobileLogin struct {
|
|
|
Mobile string `json:"mobile" validate:"required,len=11"`
|
|
|
SMS string `json:"sms" validate:"required,len=4"`
|
|
|
UnionID string `json:"unionid"`
|
|
|
}
|
|
|
|
|
|
type autoLoginParam struct {
|
|
|
UserId uint `json:"userId"`
|
|
|
}
|
|
|
type unionIDLoginParam struct {
|
|
|
UnionID string `json:"unionid"`
|
|
|
}
|
|
|
|
|
|
type BasicAuth struct {
|
|
|
ID uint `json:"id" form:"id" validate:"required"`
|
|
|
Token string `json:"token" form:"token" validate:"len=32"`
|
|
|
}
|
|
|
|
|
|
type rtnPack struct {
|
|
|
Auth BasicAuth `json:"auth"`
|
|
|
Info *DetailInfo `json:"info"`
|
|
|
Status int `json:"status"`
|
|
|
}
|
|
|
|
|
|
type DetailInfo struct {
|
|
|
user.Information
|
|
|
UserLevel int8 `json:"userLevel"`
|
|
|
RoleLevel int `json:"roleLevel"`
|
|
|
IsVerified bool `json:"isVerified"`
|
|
|
RealInfoStatus bool `json:"realInfoStatus"`
|
|
|
IsSetPayPwd bool `json:"isSetPayPwd"`
|
|
|
TeacherWechatNo string `gorm:"column:teacher_wechat_no;size:30" json:"teacherWechatNo"`
|
|
|
}
|
|
|
|
|
|
func (r *DetailInfo) ReflectedBy(u *user.Information, v bool) *DetailInfo {
|
|
|
// todo 修改user加字段 或者放缓存
|
|
|
var userWallet user.Wallet
|
|
|
DB.Where("user_id = ?", u.ID).First(&userWallet)
|
|
|
if len(userWallet.Password) > 0 {
|
|
|
r.IsSetPayPwd = true
|
|
|
}
|
|
|
|
|
|
if u.RealInfoStatus == user.RealInfoPass {
|
|
|
r.RealInfoStatus = true
|
|
|
}
|
|
|
|
|
|
r.ID = u.ID
|
|
|
r.Nickname = u.Nickname
|
|
|
r.HeadImgUrl = u.HeadImgUrl
|
|
|
r.WxUnionId = u.WxUnionId
|
|
|
r.Mobile = u.Mobile
|
|
|
r.Gender = u.Gender
|
|
|
r.Birthday = u.Birthday
|
|
|
r.InvitationNo = u.InvitationNo
|
|
|
r.CreatedAt = u.CreatedAt
|
|
|
//r.Role = u.Role
|
|
|
r.IsVerified = v
|
|
|
r.Phone = u.Phone
|
|
|
r.WechatNo = u.WechatNo
|
|
|
r.RealName = u.RealName
|
|
|
r.IDCard = u.IDCard
|
|
|
return r
|
|
|
}
|
|
|
|
|
|
type weChatAccess struct {
|
|
|
AccessToken string `json:"access_token" validate:"required"`
|
|
|
Openid string `json:"openid" validate:"required"`
|
|
|
ErrMsg string `json:"errmsg"`
|
|
|
}
|
|
|
|
|
|
type weChatUserInfo struct {
|
|
|
OpenID string `json:"openid" validate:"required"`
|
|
|
Nickname string `json:"nickname" validate:"required,min=1"`
|
|
|
UnionId string `json:"unionId" validate:"required,min=28"`
|
|
|
Sex uint `json:"sex" validate:"required"`
|
|
|
HeadImgUrl string `json:"headImgUrl" validate:"required"`
|
|
|
}
|
|
|
|
|
|
type miniLoginParam struct {
|
|
|
AuthCode string `json:"auth_code" validator:"required"`
|
|
|
AvatarUrl string `json:"avatar_url" validator:"required"`
|
|
|
Gender uint `json:"gender" validator:"required"`
|
|
|
Nickname string `json:"nickname" validator:"required"`
|
|
|
}
|
|
|
|
|
|
type openidResp struct {
|
|
|
OpenID string `json:"openid" validate:"required"`
|
|
|
UnionId string `json:"unionId" validate:"required"`
|
|
|
SessionKey string `json:"session_key"`
|
|
|
ErrMsg string `json:"errmsg"`
|
|
|
}
|
|
|
|
|
|
const WxMiniUserOpenIDUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=%v&secret=%v&js_code=%v&grant_type=authorization_code"
|
|
|
const WxUnionIDURL = "https://api.weixin.qq.com/sns/userinfo?access_token=%v&openid=%v"
|
|
|
const WxOauth2URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%v&secret=%v&code=%v&grant_type=authorization_code"
|
|
|
|
|
|
// LoginByWeChat 微信登陆 step1
|
|
|
func LoginByWeChat(c *gin.Context) {
|
|
|
var p weChatLogin
|
|
|
|
|
|
err := tools.ParseParams(&p, c)
|
|
|
if err != nil {
|
|
|
back.Fail(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 1.获取access_token
|
|
|
var access weChatAccess
|
|
|
{
|
|
|
url := ""
|
|
|
if p.WxType == "" {
|
|
|
url = fmt.Sprintf(WxOauth2URL, define.WxAppID, define.WxAppSecret, p.Code)
|
|
|
} else {
|
|
|
wxConfig := define.WxConfig[p.WxType]
|
|
|
if wxConfig.Type == "wxapp" {
|
|
|
url = fmt.Sprintf(WxMiniUserOpenIDUrl, wxConfig.AppId, wxConfig.AppSecret, p.Code)
|
|
|
} else {
|
|
|
url = fmt.Sprintf(WxOauth2URL, wxConfig.AppId, wxConfig.AppSecret, p.Code)
|
|
|
}
|
|
|
}
|
|
|
response1, err := http.Get(url)
|
|
|
if err != nil {
|
|
|
back.Err(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
defer func() { _ = response1.Body.Close() }()
|
|
|
|
|
|
body1, err := ioutil.ReadAll(response1.Body)
|
|
|
if err != nil {
|
|
|
log.Println(string(body1))
|
|
|
back.Err(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
|
|
|
err = json.Unmarshal(body1, &access)
|
|
|
if err != nil {
|
|
|
back.Err(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if len(access.ErrMsg) > 0 {
|
|
|
back.Err(c, access.ErrMsg)
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
2.拿到了微信的openid后 再去请求uinonid 依据unionid判断用户是否存在
|
|
|
*/
|
|
|
var userInfo weChatUserInfo
|
|
|
{
|
|
|
response2, err := http.Get(fmt.Sprintf(WxUnionIDURL, access.AccessToken, access.Openid))
|
|
|
if err != nil {
|
|
|
back.Err(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
defer func() { _ = response2.Body.Close() }()
|
|
|
|
|
|
body2, err := ioutil.ReadAll(response2.Body)
|
|
|
if err != nil {
|
|
|
back.Err(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
|
|
|
err = json.Unmarshal(body2, &userInfo)
|
|
|
if err != nil {
|
|
|
back.Err(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
|
|
|
log.Println(string(body2))
|
|
|
|
|
|
marshal, _ := json.Marshal(access)
|
|
|
log.Println(string(body2))
|
|
|
log.Println(string(marshal))
|
|
|
if userInfo.UnionId == "" {
|
|
|
back.Err(c, "获取UnionId失败")
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 之后开始做用户是否绑定的验证,绑定了手机了, 就直接登陆
|
|
|
// 未绑定,需要绑定手机
|
|
|
var info user.Information
|
|
|
|
|
|
err = DB.Where(user.Information{
|
|
|
WxUnionId: userInfo.UnionId,
|
|
|
}).Last(&info).Error
|
|
|
if err != nil && !gorm.IsRecordNotFoundError(err) {
|
|
|
back.Err(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 在数据库中查找是否存在用户, 且已经有手机号和邀请码, 直接登陆
|
|
|
if info.ID > 0 && len(info.InvitationNo) > 0 && len(info.Mobile) > 0 {
|
|
|
// todo 感觉可以不确定wxAppOpenId
|
|
|
if len(info.WxAppOpenId) == 0 {
|
|
|
err = DB.Model(&info).Update(user.Information{WxMiniOpenId: access.Openid}).Error
|
|
|
if err != nil {
|
|
|
back.Err(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
login(c, &info)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
{
|
|
|
// 在缓存中查找是否已经之前导入过
|
|
|
var ur = service.NewUserWithRedis()
|
|
|
_, err := ur.GetUserInRedis(info.WxUnionId)
|
|
|
|
|
|
// 不为nil的err,直接返回。
|
|
|
if err != nil && err != redis.Nil {
|
|
|
back.Err(c, "内部错误602"+err.Error())
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 未在redis中找到数据----》用户不存在 则获取授权信息
|
|
|
var headImgPath string
|
|
|
// 下载头像
|
|
|
{
|
|
|
if userInfo.HeadImgUrl != "" {
|
|
|
headResp, err := http.Get(userInfo.HeadImgUrl)
|
|
|
if err != nil {
|
|
|
back.Err(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
defer func() { _ = headResp.Body.Close() }()
|
|
|
hash := tools.MD5(userInfo.HeadImgUrl)
|
|
|
imgName := fmt.Sprintf("%v.jpg", hash)
|
|
|
headImgPath = filepath.Join(static_path.Dir.Photo, imgName)
|
|
|
dst := filepath.Join(static_path.Dir.Root, headImgPath)
|
|
|
out, err := os.Create(dst)
|
|
|
if err != nil {
|
|
|
back.Err(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
|
|
|
defer func() { _ = out.Close() }()
|
|
|
_, err = io.Copy(out, headResp.Body)
|
|
|
if err != nil {
|
|
|
back.Err(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
} else {
|
|
|
headImgPath = "/default/officaillogo-1.png"
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 不存在用户设置信息
|
|
|
info = user.Information{
|
|
|
Nickname: userInfo.Nickname,
|
|
|
HeadImgUrl: headImgPath,
|
|
|
WxUnionId: userInfo.UnionId,
|
|
|
WxAppOpenId: userInfo.OpenID,
|
|
|
Gender: userInfo.Sex,
|
|
|
InvitationNo: "",
|
|
|
Birthday: formatime.NewSecondFrom(define.DefaultBirthday),
|
|
|
}
|
|
|
|
|
|
// redis放入wx信息
|
|
|
ok, err := ur.SetUserInRedis(info.WxUnionId, info, 0)
|
|
|
if ok != "OK" || err != nil {
|
|
|
back.Err(c, "内部错误601"+err.Error())
|
|
|
return
|
|
|
}
|
|
|
// 将wx信息放入缓存中后,返回需要填写手机号码
|
|
|
back.Suc(c, "请填写手机号码", gin.H{
|
|
|
"status": 0, //0 -> 填写 手机号 1 -> 完整用户信息
|
|
|
"bindingMobile": 0,
|
|
|
"info": gin.H{
|
|
|
"nickname": info.Nickname,
|
|
|
"wxUnionId": userInfo.UnionId,
|
|
|
},
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// LoginByMiniProgram 通过小程序登录
|
|
|
func LoginByMiniProgram(c *gin.Context) {
|
|
|
var p miniLoginParam
|
|
|
if err := tools.ParseParams(&p, c); err != nil {
|
|
|
back.Fail(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
|
|
|
response, err := http.Get(fmt.Sprintf(WxMiniUserOpenIDUrl, define.WxMiniProgramAppID, define.WxMiniProgramAppSecret, p.AuthCode))
|
|
|
if err != nil {
|
|
|
back.Err(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
defer func() { _ = response.Body.Close() }()
|
|
|
body, err := ioutil.ReadAll(response.Body)
|
|
|
if err != nil {
|
|
|
back.Fail(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
|
|
|
var resp openidResp
|
|
|
if err = json.Unmarshal(body, &resp); err != nil {
|
|
|
back.Fail(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if len(resp.ErrMsg) > 0 {
|
|
|
back.Fail(c, "微信授权失败"+resp.ErrMsg)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if len(resp.UnionId) == 0 {
|
|
|
back.Fail(c, "不可用:请等待小程序客户端升级")
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 获取到openid 判断数据库是否有
|
|
|
var info user.Information
|
|
|
err = DB.Where(user.Information{
|
|
|
WxUnionId: resp.UnionId,
|
|
|
}).First(&info).Error
|
|
|
if err != nil && !gorm.IsRecordNotFoundError(err) {
|
|
|
back.Fail(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if info.ID == 0 { // 用户不存在 则获取授权信息
|
|
|
var headImgPath string
|
|
|
// 下载头像
|
|
|
{
|
|
|
headResp, err := http.Get(p.AvatarUrl)
|
|
|
if err != nil {
|
|
|
back.Fail(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
|
|
|
defer func() { _ = headResp.Body.Close() }()
|
|
|
|
|
|
hash := tools.MD5(p.AvatarUrl)
|
|
|
imgName := fmt.Sprintf("%v.jpg", hash)
|
|
|
headImgPath = filepath.Join(static_path.Dir.Photo, imgName)
|
|
|
dst := filepath.Join(static_path.Dir.Root, headImgPath)
|
|
|
out, err := os.Create(dst)
|
|
|
if err != nil {
|
|
|
back.Err(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
|
|
|
defer func() { _ = out.Close() }()
|
|
|
_, err = io.Copy(out, headResp.Body)
|
|
|
if err != nil {
|
|
|
back.Err(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
info = user.Information{
|
|
|
Nickname: p.Nickname,
|
|
|
HeadImgUrl: headImgPath,
|
|
|
WxUnionId: resp.UnionId,
|
|
|
WxMiniOpenId: resp.OpenID,
|
|
|
Gender: p.Gender,
|
|
|
InvitationNo: "",
|
|
|
Birthday: formatime.NewSecondFrom(define.DefaultBirthday),
|
|
|
}
|
|
|
|
|
|
err = DB.Create(&info).Error
|
|
|
if err != nil {
|
|
|
back.Err(c, err.Error())
|
|
|
} else {
|
|
|
back.Suc(c, "请填写邀请码", gin.H{
|
|
|
"status": 0,
|
|
|
"info": gin.H{
|
|
|
"id": info.ID,
|
|
|
"nickname": info.Nickname,
|
|
|
},
|
|
|
})
|
|
|
}
|
|
|
} else {
|
|
|
if len(info.InvitationNo) > 0 {
|
|
|
if len(info.Mobile) > 0 {
|
|
|
if len(info.WxMiniOpenId) == 0 {
|
|
|
err = DB.Model(&info).Update(user.Information{WxMiniOpenId: resp.OpenID}).Error
|
|
|
if err != nil {
|
|
|
back.Err(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 小程序登录时 直接返回鉴权令牌
|
|
|
var realInfo user.RealInfo
|
|
|
DB.First(&realInfo, "user_id = ?", info.ID)
|
|
|
isVerified := false
|
|
|
if realInfo.ID > 0 {
|
|
|
isVerified = true
|
|
|
}
|
|
|
|
|
|
deviceType := cache.GetDeviceType(c)
|
|
|
var login user.Login
|
|
|
DB.First(&login, "user_id=? and device_type = ?", info.ID, deviceType)
|
|
|
if info.ID == 0 {
|
|
|
login = user.Login{
|
|
|
Token: tools.Token(),
|
|
|
IP: c.ClientIP(),
|
|
|
LoginTime: formatime.NewSecondNow(),
|
|
|
DeviceType: cache.GetDeviceType(c),
|
|
|
UserID: info.ID,
|
|
|
}
|
|
|
err := DB.Create(&login).Error
|
|
|
|
|
|
if err != nil {
|
|
|
back.Err(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
cache.SetUserLoginCache(&login)
|
|
|
|
|
|
back.Suc(c, "登录成功", &rtnPack{
|
|
|
BasicAuth{
|
|
|
ID: login.ID,
|
|
|
Token: login.Token,
|
|
|
},
|
|
|
(&DetailInfo{}).ReflectedBy(&info, isVerified),
|
|
|
1,
|
|
|
})
|
|
|
} else {
|
|
|
back.Suc(c, "请填写手机号码", gin.H{
|
|
|
"status": 1,
|
|
|
"bindingMobile": 0,
|
|
|
"info": gin.H{
|
|
|
"id": info.ID,
|
|
|
"nickname": info.Nickname,
|
|
|
},
|
|
|
})
|
|
|
}
|
|
|
} else {
|
|
|
back.Suc(c, "请填写邀请码", gin.H{
|
|
|
"status": 0,
|
|
|
"info": gin.H{
|
|
|
"id": info.ID,
|
|
|
"nickname": info.Nickname,
|
|
|
},
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// LoginByMobile 通过手机号登录,如果没有推荐码,就跳转到注册方法
|
|
|
func LoginByMobile(c *gin.Context) {
|
|
|
var p mobileLogin
|
|
|
|
|
|
err := tools.ParseParams(&p, c)
|
|
|
if err != nil {
|
|
|
back.Fail(c, "参数错误:"+err.Error())
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 留的登陆后门, 在密码在redis中
|
|
|
// redis中设置5分钟更新一次验证码
|
|
|
pwd, _ := Rds.Get(cache.SuperKey).Result()
|
|
|
if pwd != p.SMS {
|
|
|
// 这里是正常用户的业务逻辑
|
|
|
v := cache.GetUserSMSCode(p.Mobile)
|
|
|
if v != p.SMS {
|
|
|
back.Fail(c, "验证码错误")
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
var info user.Information
|
|
|
|
|
|
err = DB.First(&info, "mobile=?", p.Mobile).Error
|
|
|
if err != nil {
|
|
|
|
|
|
if gorm.IsRecordNotFoundError(err) {
|
|
|
back.Suc(c, "请填写邀请码", gin.H{
|
|
|
"status": 0,
|
|
|
}) // 新用户 没有填写邀请码
|
|
|
|
|
|
} else {
|
|
|
back.Err(c, "用户不存在:"+err.Error())
|
|
|
}
|
|
|
|
|
|
//只要没有数据,就去插入用户,写一个插入用户的方法,指定手机号的,并调用login方法,用来返回数据
|
|
|
|
|
|
} else {
|
|
|
if len(p.UnionID) > 0 {
|
|
|
DB.Model(&info).Where("id=?", info.ID).Update("wx_union_id", p.UnionID)
|
|
|
DB.First(&info, "mobile=?", p.Mobile)
|
|
|
}
|
|
|
login(c, &info)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
type ArgsLoginInfo struct {
|
|
|
Name string `json:"name"`
|
|
|
Password string `json:"password"`
|
|
|
}
|
|
|
|
|
|
func LoginByName(c *gin.Context) {
|
|
|
var p ArgsLoginInfo
|
|
|
err := tools.ParseParams(&p, c)
|
|
|
if err != nil {
|
|
|
back.Fail(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
var obj company.Info
|
|
|
if err := dbc.DB.First(&obj, "shop_name= ?", p.Name).Error; err != nil {
|
|
|
back.Fail(c, err.Error())
|
|
|
return
|
|
|
|
|
|
}
|
|
|
if obj.State != 2 {
|
|
|
err := errors.New("未通过审核")
|
|
|
back.Fail(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
if obj.Status != 1 {
|
|
|
err := errors.New("被禁用")
|
|
|
back.Fail(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
if obj.Password != p.Password {
|
|
|
err := errors.New("密码不正确")
|
|
|
back.Fail(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
|
|
|
var info user.Information
|
|
|
|
|
|
err = DB.First(&info, "id = ?", obj.ID).Error
|
|
|
if err != nil {
|
|
|
|
|
|
back.Err(c, "用户不存在:"+err.Error())
|
|
|
} else {
|
|
|
login(c, &info)
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// AutoLogin 自动登录
|
|
|
func AutoLogin(c *gin.Context) {
|
|
|
var p autoLoginParam
|
|
|
err := tools.ParseParams(&p, c)
|
|
|
if err != nil {
|
|
|
back.Fail(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if p.UserId > 0 {
|
|
|
var l = user.Login{ID: p.UserId}
|
|
|
err = DB.Model(&l).Updates(user.Login{LoginTime: formatime.NewSecondNow()}).Error
|
|
|
if err != nil {
|
|
|
back.Fail(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
back.Suc(c, "", nil)
|
|
|
}
|
|
|
|
|
|
// UnionID 通过unionID登录
|
|
|
func UnionID(c *gin.Context) {
|
|
|
var p unionIDLoginParam
|
|
|
err := tools.ParseParams(&p, c)
|
|
|
if err != nil {
|
|
|
back.Fail(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
var info user.Information
|
|
|
err = DB.First(&info, "wx_union_id=?", p.UnionID).Error
|
|
|
if err != nil {
|
|
|
back.Err(c, "用户不存在:"+err.Error())
|
|
|
} else {
|
|
|
login(c, &info)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//上面的几种方式调用的
|
|
|
func login(c *gin.Context, info *user.Information) {
|
|
|
deviceType := cache.GetDeviceType(c)
|
|
|
// 老用户 当主动退出登录或更换手机号码后 再次登录需要重置
|
|
|
var login user.Login
|
|
|
DB.First(&login, "user_id=? and device_type = ?", info.ID, deviceType)
|
|
|
token := tools.Token()
|
|
|
if login.ID > 0 {
|
|
|
err := DB.Model(&login).Updates(user.Login{
|
|
|
Token: token,
|
|
|
IP: c.ClientIP(),
|
|
|
LoginTime: formatime.NewSecondNow(),
|
|
|
}).Error
|
|
|
|
|
|
if err != nil {
|
|
|
back.Err(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
} else {
|
|
|
login = user.Login{
|
|
|
Token: token,
|
|
|
IP: c.ClientIP(),
|
|
|
LoginTime: formatime.NewSecondNow(),
|
|
|
DeviceType: cache.GetDeviceType(c),
|
|
|
UserID: info.ID,
|
|
|
}
|
|
|
err := DB.Create(&login).Error
|
|
|
|
|
|
if err != nil {
|
|
|
back.Err(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
cache.SetUserLoginCache(&login)
|
|
|
|
|
|
var realInfo user.RealInfo
|
|
|
DB.First(&realInfo, "user_id = ?", info.ID)
|
|
|
|
|
|
isVerified := false
|
|
|
if realInfo.ID > 0 {
|
|
|
isVerified = true
|
|
|
}
|
|
|
if info.Level == 0 && info.ParentID != 0 {
|
|
|
if err := DB.Table(info.TableName()).Where("id=?", info.ID).Update("level", 1).Error; err != nil {
|
|
|
back.Fail(c, err.Error())
|
|
|
}
|
|
|
}
|
|
|
//追加app登录状态
|
|
|
if err := DB.Table(info.TableName()).Where("id=?", info.ID).Update("login_app", 1).Error; err != nil {
|
|
|
back.Fail(c, err.Error())
|
|
|
}
|
|
|
|
|
|
back.Suc(c, "登录成功", &rtnPack{
|
|
|
BasicAuth{
|
|
|
ID: login.ID,
|
|
|
Token: login.Token,
|
|
|
},
|
|
|
(&DetailInfo{}).ReflectedBy(info, isVerified),
|
|
|
1,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
func Aes128Decrypt(crypted, key []byte, IV []byte) ([]byte, error) {
|
|
|
if key == nil || len(key) != 16 {
|
|
|
return nil, nil
|
|
|
}
|
|
|
if IV != nil && len(IV) != 16 {
|
|
|
return nil, nil
|
|
|
}
|
|
|
|
|
|
block, err := aes.NewCipher(key)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
blockSize := block.BlockSize()
|
|
|
blockMode := cipher.NewCBCDecrypter(block, IV[:blockSize])
|
|
|
origData := make([]byte, len(crypted))
|
|
|
blockMode.CryptBlocks(origData, crypted)
|
|
|
origData = PKCS7UnPadding(origData)
|
|
|
return origData, nil
|
|
|
}
|
|
|
|
|
|
func PKCS7UnPadding(origData []byte) []byte {
|
|
|
length := len(origData)
|
|
|
unpadding := int(origData[length-1])
|
|
|
return origData[:(length - unpadding)]
|
|
|
}
|
|
|
|
|
|
const (
|
|
|
AppIDH5 = "wx0a67d8af4a8252b0"
|
|
|
AppSecretH5 = "de4494be68c27fb306448f46718cbd13"
|
|
|
APIKeyH5 = "83f8932eb742257316e3168ba9e920dk"
|
|
|
MchIDH5 = "1545449631"
|
|
|
)
|
|
|
|
|
|
// H5GetCode h5获取code
|
|
|
func H5GetCode(c *gin.Context) {
|
|
|
type req struct {
|
|
|
RedirectUrl string `json:"redirectUrl"`
|
|
|
}
|
|
|
var p req
|
|
|
err := tools.ParseParams(&p, c)
|
|
|
if err != nil {
|
|
|
back.Fail(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
url := fmt.Sprintf("https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect",
|
|
|
AppIDH5,
|
|
|
url.QueryEscape(p.RedirectUrl))
|
|
|
back.Suc(c, "操作成功", gin.H{
|
|
|
"url": url,
|
|
|
})
|
|
|
return
|
|
|
}
|
|
|
|
|
|
type Response struct {
|
|
|
AccessToken string `json:"access_token"`
|
|
|
ExpiresIn int `json:"expires_in"`
|
|
|
RefreshToken string `json:"refresh_token"`
|
|
|
OpenId string `json:"openid"`
|
|
|
Scope string `json:"scope"`
|
|
|
Errcode int `json:"errcode"`
|
|
|
Errmsg string `json:"errmsg"`
|
|
|
}
|
|
|
|
|
|
// H5GetOpenId h5获取openid
|
|
|
func H5GetOpenId(c *gin.Context) {
|
|
|
type req struct {
|
|
|
Code string `json:"code" validate:"required"`
|
|
|
}
|
|
|
var p req
|
|
|
err := tools.ParseParams(&p, c)
|
|
|
if err != nil {
|
|
|
back.Fail(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
url1 := fmt.Sprintf("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code",
|
|
|
AppIDH5, AppSecretH5, p.Code)
|
|
|
|
|
|
resp, err := http.Get(url1)
|
|
|
if err != nil {
|
|
|
panic(err)
|
|
|
|
|
|
}
|
|
|
defer resp.Body.Close()
|
|
|
respBody, err := ioutil.ReadAll(resp.Body)
|
|
|
if err != nil {
|
|
|
back.Fail(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
|
|
|
var respStruct Response //iponid的结构体
|
|
|
err = json.Unmarshal(respBody, &respStruct)
|
|
|
unionid := GetUser(respStruct)
|
|
|
back.Suc(c, "", gin.H{
|
|
|
"unionid": unionid,
|
|
|
})
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
//获取unionID
|
|
|
type wxUserInfo struct {
|
|
|
UnionID string `json:"unionid"`
|
|
|
}
|
|
|
|
|
|
// GetUser 获取用户信息
|
|
|
func GetUser(respStruct Response) string {
|
|
|
url := fmt.Sprintf("https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN", respStruct.AccessToken, respStruct.OpenId)
|
|
|
resp, err := http.Get(url)
|
|
|
if err != nil {
|
|
|
//panic(err)
|
|
|
//log.Println(err)
|
|
|
|
|
|
}
|
|
|
defer resp.Body.Close()
|
|
|
respBody, err := ioutil.ReadAll(resp.Body)
|
|
|
if err != nil {
|
|
|
}
|
|
|
|
|
|
var user_struct wxUserInfo //iponid的结构体
|
|
|
err = json.Unmarshal(respBody, &user_struct)
|
|
|
return user_struct.UnionID
|
|
|
}
|
|
|
|
|
|
type getTokenByToken struct {
|
|
|
Uid uint `json:"uid"`
|
|
|
}
|
|
|
|
|
|
// GetTokenByUid 通过uid获取token
|
|
|
func GetTokenByUid(c *gin.Context) {
|
|
|
var p getTokenByToken
|
|
|
err := tools.ParseParams(&p, c)
|
|
|
if err != nil {
|
|
|
back.Fail(c, err.Error())
|
|
|
return
|
|
|
}
|
|
|
var userLogin user.Login
|
|
|
DB.First(&userLogin, "user_id=?", p.Uid)
|
|
|
back.Suc(c, "", &gin.H{
|
|
|
"token": userLogin.Token,
|
|
|
})
|
|
|
}
|