init project

This commit is contained in:
2023-04-24 17:19:41 +08:00
parent 84729ebb66
commit cdb5a4f9cd
51 changed files with 3328 additions and 1 deletions

109
api/app/login.go Normal file
View File

@@ -0,0 +1,109 @@
package app
import (
"Lee-WineList/client"
"Lee-WineList/common/constant"
"Lee-WineList/core"
"Lee-WineList/model/param"
"Lee-WineList/oauth2"
"Lee-WineList/repository"
"context"
"encoding/json"
"fmt"
"git.echol.cn/loser/logger/log"
"github.com/gin-gonic/gin"
"net/http"
"net/url"
)
type loginApi struct{}
// LoginApi 暴露接口
func LoginApi() *loginApi {
return &loginApi{}
}
// Login 登录
func (l loginApi) Login(ctx *gin.Context) {
var p param.Login
if err := ctx.ShouldBind(&p); err != nil {
core.R(ctx).FailWithMessage(err.Error())
return
}
// 获取用户基础账号信息
userId, err := oauth2.OAuthServer.UserAuthorizationHandler(ctx.Writer, ctx.Request)
if err != nil {
log.Errorf("获取用户基础账号信息失败: %v", err)
core.R(ctx).FailWithMessage(err.Error())
return
}
// 重新组装登录参数
ctx.Request.Form = url.Values{
"username": {userId},
"password": {p.Password},
"scope": {"ALL"},
"grant_type": {"password"},
}
// 参数解析成功,进行登录
if err = oauth2.OAuthServer.HandleTokenRequest(ctx.Writer, ctx.Request); err != nil {
log.Errorf("登录失败:%s", err.Error())
core.R(ctx).FailWithMessage("系统错误,登录失败")
return
}
// 登录成功才更新登录时间
if ctx.Writer.Status() == http.StatusOK {
// 登录成功更新登录时间和IP
go repository.Login().UpdateLastLoginInfo(userId, ctx.ClientIP(), p.UserIdentity)
}
}
// Refresh 刷新登录Token
func (loginApi) Refresh(ctx *gin.Context) {
var p param.RefreshToken
if err := ctx.ShouldBind(&p); err != nil {
core.R(ctx).FailWithMessage("参数错误: " + err.Error())
return
}
// 刷新Token
if err := oauth2.OAuthServer.HandleTokenRequest(ctx.Writer, ctx.Request); err != nil {
log.Errorf("Token数据返回失败: %v", err.Error())
core.R(ctx).FailWithMessage("系统错误")
}
}
// Logout 退出登录
func (loginApi) Logout(ctx *gin.Context) {
log.Debug("退出登录啦")
r := core.R(ctx)
// Token字符串前缀
const bearerSchema string = "Bearer "
// 取出Token
tokenHeader := ctx.Request.Header.Get("Authorization")
tokenStr := tokenHeader[len(bearerSchema):]
// 取出原始RedisKey
baseDataId, err := client.Redis.Get(context.Background(), constant.OAuth2RedisKey+tokenStr).Result()
if err != nil {
r.FailWithMessage("Token信息获取失败")
return
}
baseDataStr, err := client.Redis.Get(context.Background(), constant.OAuth2RedisKey+baseDataId).Result()
if err != nil {
r.FailWithMessage("Token信息获取失败")
return
}
// 转换数据为Map
tokenData := make(map[string]any)
if err = json.Unmarshal([]byte(baseDataStr), &tokenData); err != nil {
r.FailWithMessage("系统错误: " + err.Error())
return
}
// 删除Redis缓存的数据
client.Redis.Del(context.Background(), constant.OAuth2RedisKey+baseDataId)
client.Redis.Del(context.Background(), fmt.Sprintf("%v%v", constant.OAuth2RedisKey, tokenData["Access"]))
client.Redis.Del(context.Background(), fmt.Sprintf("%v%v", constant.OAuth2RedisKey, tokenData["Refresh"]))
r.Ok()
}

104
api/app/user.go Normal file
View File

@@ -0,0 +1,104 @@
package app
import (
"Lee-WineList/api"
"Lee-WineList/common/constant"
"Lee-WineList/core"
"Lee-WineList/model/entity"
"Lee-WineList/model/param"
"Lee-WineList/model/vo"
"Lee-WineList/repository"
"Lee-WineList/utils"
"git.echol.cn/loser/logger/log"
"github.com/gin-gonic/gin"
"strings"
)
type userApi struct {
}
// UserApi 暴露接口
func UserApi() *userApi {
return &userApi{}
}
// GetUser 获取当前登录用户信息
func (u userApi) GetUser(ctx *gin.Context) {
// 取出当前登录用户
var ue entity.User
if api.GetUser(ctx, &ue, false, true); ctx.IsAborted() {
return
}
// 转换为VO
var v vo.UserVO
v.ParseOrdinary(ue)
core.R(ctx).OkWithData(v)
}
// BindingWeChat 绑定微信
func (u userApi) BindingWeChat(ctx *gin.Context) {
var p param.BindingWeChat
if err := ctx.ShouldBind(&p); err != nil {
core.R(ctx).FailWithMessage("参数错误" + err.Error())
return
}
// 取出当前登录用户
var loginUser entity.User
if api.GetUser(ctx, &loginUser, true, true); ctx.IsAborted() {
return
}
// 解析出UnionId和OpenId
unionId, openId, _, err := utils.WeChatUtils().GetWechatUnionId(p.Code)
if err != nil {
log.Errorf("获取微信UnionId失败%s", err.Error())
core.R(ctx).FailWithMessage("系统错误,请稍后再试")
return
}
log.Debugf("用户[%v]的UnionId为[%v]OpenId为[%v]", loginUser.Id, unionId, openId)
if repository.User().CheckUnionIdIsExist(unionId, openId) {
core.R(ctx).FailWithMessage("该微信已绑定其他账号")
return
}
// 解析成功,修改用户信息
loginUser.WechatUnionId = &unionId
loginUser.WechatOpenId = &openId
if err = repository.User().UpdateUserInfo(&loginUser); err != nil {
log.Errorf("修改用户信息失败:%s", err.Error())
core.R(ctx).FailWithMessage("系统错误,请稍后再试")
return
}
core.R(ctx).Ok()
}
// UpdateUser 修改用户信息
func (u userApi) UpdateUser(ctx *gin.Context) {
var p param.ChangeUserInfo
if err := ctx.ShouldBind(&p); err != nil {
core.R(ctx).FailWithMessage("参数错误: " + err.Error())
return
}
// 获取当前登录用户
var loginUser entity.User
if api.GetUser(ctx, &loginUser, false, true); ctx.IsAborted() {
return
}
// 修改资料
if p.Sex != constant.UserSexNone {
loginUser.Sex = p.Sex
}
if p.Nickname != "" {
loginUser.Nickname = p.Nickname
}
if p.Avatar != "" && strings.HasPrefix(p.Avatar, "http") {
loginUser.Avatar = p.Avatar
}
// 修改数据
if err := repository.User().UpdateUserInfo(&loginUser); err != nil {
log.Errorf("修改用户信息失败:%s", err.Error())
core.R(ctx).FailWithMessage("修改用户信息失败: " + err.Error())
return
}
core.R(ctx).Ok()
}

69
api/base.go Normal file
View File

@@ -0,0 +1,69 @@
package api
import (
"Lee-WineList/client"
"Lee-WineList/common/constant"
"Lee-WineList/core"
"Lee-WineList/model/entity"
"git.echol.cn/loser/logger/log"
"github.com/gin-gonic/gin"
"net/http"
)
// GetAdminUser 获取登录的管理员信息
func GetAdminUser(ctx *gin.Context, u *entity.AdminUser) {
userId := ctx.Request.Header.Get("userId")
if userId == "" {
ctx.Abort()
core.R(ctx).FailWithMessageAndCode("未授权操作", http.StatusUnauthorized)
return
}
u.Id = userId
// 查询用户信息
err := client.MySQL.Where("id = ?", u.Id).First(&u).Error
if err != nil {
log.Errorf("获取用户信息失败:%s", err.Error())
core.R(ctx).FailWithMessageAndCode("用户状态异常", http.StatusBadRequest)
ctx.Abort()
return
}
// 校验
if u.Status != constant.UserStatusActive {
core.R(ctx).FailWithMessageAndCode("用户已被禁用", http.StatusBadRequest)
ctx.Abort()
return
}
}
// GetUser 获取登录的普通用户信息dontResponse表示只获取用户信息不论对错, dontCheck表示不检查微信绑定
func GetUser(ctx *gin.Context, u *entity.User, dontResponse, dontCheck bool) {
userId := ctx.Request.Header.Get("userId")
if userId == "" {
if !dontResponse {
ctx.Abort()
core.R(ctx).FailWithMessageAndCode("未授权操作", http.StatusUnauthorized)
}
return
}
u.Id = userId
// 查询
err := client.MySQL.Take(&u).Error
if err != nil {
log.Errorf("获取用户信息失败:%s", err.Error())
ctx.Abort()
if !dontResponse {
core.R(ctx).FailWithMessageAndCode("用户状态异常", http.StatusBadRequest)
}
return
}
// 需要跳过微信绑定检验
if !dontCheck {
// 检查微信绑定
if u.WechatOpenId == nil || *u.WechatOpenId == "" {
log.Errorf("%v 未绑定微信", u.Nickname)
core.R(ctx).FailWithMessageAndCode("请先绑定微信", http.StatusForbidden)
ctx.Abort()
}
}
}