⚡ update qq/gitee/github oauth2 login
This commit is contained in:
14
api/api.go
14
api/api.go
@@ -3,6 +3,8 @@ package api
|
||||
import (
|
||||
"schisandra-cloud-album/api/captcha_api"
|
||||
"schisandra-cloud-album/api/oauth_api"
|
||||
"schisandra-cloud-album/api/permission_api"
|
||||
"schisandra-cloud-album/api/role_api"
|
||||
"schisandra-cloud-album/api/sms_api"
|
||||
"schisandra-cloud-album/api/user_api"
|
||||
"schisandra-cloud-album/api/websocket_api"
|
||||
@@ -10,11 +12,13 @@ import (
|
||||
|
||||
// Apis 统一导出的api
|
||||
type Apis struct {
|
||||
UserApi user_api.UserAPI
|
||||
CaptchaApi captcha_api.CaptchaAPI
|
||||
SmsApi sms_api.SmsAPI
|
||||
OAuthApi oauth_api.OAuthAPI
|
||||
WebsocketApi websocket_api.WebsocketAPI
|
||||
UserApi user_api.UserAPI
|
||||
CaptchaApi captcha_api.CaptchaAPI
|
||||
SmsApi sms_api.SmsAPI
|
||||
OAuthApi oauth_api.OAuthAPI
|
||||
WebsocketApi websocket_api.WebsocketAPI
|
||||
RoleApi role_api.RoleAPI
|
||||
PermissionApi permission_api.PermissionAPI
|
||||
}
|
||||
|
||||
// Api new函数实例化,实例化完成后会返回结构体地指针类型
|
||||
|
@@ -142,100 +142,112 @@ func (OAuthAPI) GiteeCallback(c *gin.Context) {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||
return
|
||||
}
|
||||
// 通过 code, 获取 token
|
||||
var tokenAuthUrl = GetGiteeTokenAuthUrl(code)
|
||||
var token *Token
|
||||
if token, err = GetGiteeToken(tokenAuthUrl); err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 通过token,获取用户信息
|
||||
var userInfo map[string]interface{}
|
||||
if userInfo, err = GetGiteeUserInfo(token); err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
// 异步获取 token
|
||||
var tokenChan = make(chan *Token)
|
||||
var errChan = make(chan error)
|
||||
go func() {
|
||||
var tokenAuthUrl = GetGiteeTokenAuthUrl(code)
|
||||
token, err := GetGiteeToken(tokenAuthUrl)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
tokenChan <- token
|
||||
}()
|
||||
|
||||
userInfoBytes, err := json.Marshal(userInfo)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
var giteeUser GiteeUser
|
||||
err = json.Unmarshal(userInfoBytes, &giteeUser)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
// 异步获取用户信息
|
||||
var userInfoChan = make(chan map[string]interface{})
|
||||
go func() {
|
||||
token := <-tokenChan
|
||||
if token == nil {
|
||||
errChan <- errors.New("failed to get token")
|
||||
return
|
||||
}
|
||||
userInfo, err := GetGiteeUserInfo(token)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
userInfoChan <- userInfo
|
||||
}()
|
||||
|
||||
Id := strconv.Itoa(giteeUser.ID)
|
||||
userSocial, err := userSocialService.QueryUserSocialByUUID(Id, enum.OAuthSourceGitee)
|
||||
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
// 第一次登录,创建用户
|
||||
uid := idgen.NextId()
|
||||
uidStr := strconv.FormatInt(uid, 10)
|
||||
user := model.ScaAuthUser{
|
||||
UID: &uidStr,
|
||||
Username: &giteeUser.Login,
|
||||
Nickname: &giteeUser.Name,
|
||||
Avatar: &giteeUser.AvatarURL,
|
||||
Blog: &giteeUser.Blog,
|
||||
Email: &giteeUser.Email,
|
||||
}
|
||||
addUser, err := userService.AddUser(user)
|
||||
// 等待结果
|
||||
select {
|
||||
case err = <-errChan:
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
case userInfo := <-userInfoChan:
|
||||
userInfoBytes, err := json.Marshal(userInfo)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
gitee := enum.OAuthSourceGitee
|
||||
userSocial = model.ScaAuthUserSocial{
|
||||
UserID: &addUser.ID,
|
||||
UUID: &Id,
|
||||
Source: &gitee,
|
||||
}
|
||||
err = userSocialService.AddUserSocial(userSocial)
|
||||
var giteeUser GiteeUser
|
||||
err = json.Unmarshal(userInfoBytes, &giteeUser)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
userRole := model.ScaAuthUserRole{
|
||||
UserID: uidStr,
|
||||
RoleID: enum.User,
|
||||
|
||||
Id := strconv.Itoa(giteeUser.ID)
|
||||
userSocial, err := userSocialService.QueryUserSocialByUUID(Id, enum.OAuthSourceGitee)
|
||||
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
db := global.DB
|
||||
tx := db.Begin() // 开始事务
|
||||
if tx.Error != nil {
|
||||
global.LOG.Error(tx.Error)
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
}()
|
||||
// 第一次登录,创建用户
|
||||
uid := idgen.NextId()
|
||||
uidStr := strconv.FormatInt(uid, 10)
|
||||
user := model.ScaAuthUser{
|
||||
UID: &uidStr,
|
||||
Username: &giteeUser.Login,
|
||||
Nickname: &giteeUser.Name,
|
||||
Avatar: &giteeUser.AvatarURL,
|
||||
Blog: &giteeUser.Blog,
|
||||
Email: &giteeUser.Email,
|
||||
}
|
||||
addUser, err := userService.AddUser(user)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
gitee := enum.OAuthSourceGitee
|
||||
userSocial = model.ScaAuthUserSocial{
|
||||
UserID: &uidStr,
|
||||
UUID: &Id,
|
||||
Source: &gitee,
|
||||
}
|
||||
err = userSocialService.AddUserSocial(userSocial)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
_, err = global.Casbin.AddRoleForUser(uidStr, enum.User)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
if err := tx.Commit().Error; err != nil {
|
||||
tx.Rollback()
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
HandleLoginResponse(c, *addUser.UID)
|
||||
} else {
|
||||
HandleLoginResponse(c, *userSocial.UserID)
|
||||
}
|
||||
err = userRoleService.AddUserRole(userRole)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
res, data := HandelUserLogin(addUser)
|
||||
if !res {
|
||||
return
|
||||
}
|
||||
tokenData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
formattedScript := fmt.Sprintf(script, tokenData, global.CONFIG.System.Web)
|
||||
c.Data(http.StatusOK, "text/html; charset=utf-8", []byte(formattedScript))
|
||||
} else {
|
||||
user, err := userService.QueryUserById(userSocial.UserID)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
res, data := HandelUserLogin(user)
|
||||
if !res {
|
||||
return
|
||||
}
|
||||
tokenData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
formattedScript := fmt.Sprintf(script, tokenData, global.CONFIG.System.Web)
|
||||
c.Data(http.StatusOK, "text/html; charset=utf-8", []byte(formattedScript))
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@@ -148,99 +148,116 @@ func (OAuthAPI) Callback(c *gin.Context) {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||
return
|
||||
}
|
||||
// 通过 code, 获取 token
|
||||
var tokenAuthUrl = GetTokenAuthUrl(code)
|
||||
var token *Token
|
||||
if token, err = GetToken(tokenAuthUrl); err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 通过token,获取用户信息
|
||||
var userInfo map[string]interface{}
|
||||
if userInfo, err = GetUserInfo(token); err != nil {
|
||||
// 使用channel来接收异步操作的结果
|
||||
tokenChan := make(chan *Token)
|
||||
userInfoChan := make(chan map[string]interface{})
|
||||
errChan := make(chan error)
|
||||
|
||||
// 异步获取token
|
||||
go func() {
|
||||
var tokenAuthUrl = GetTokenAuthUrl(code)
|
||||
token, err := GetToken(tokenAuthUrl)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
tokenChan <- token
|
||||
}()
|
||||
|
||||
// 异步获取用户信息
|
||||
go func() {
|
||||
token := <-tokenChan
|
||||
if token == nil {
|
||||
return
|
||||
}
|
||||
userInfo, err := GetUserInfo(token)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
userInfoChan <- userInfo
|
||||
}()
|
||||
|
||||
select {
|
||||
case err = <-errChan:
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
//json 转 struct
|
||||
userInfoBytes, err := json.Marshal(userInfo)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
case userInfo := <-userInfoChan:
|
||||
if userInfo == nil {
|
||||
global.LOG.Error(<-errChan)
|
||||
return
|
||||
}
|
||||
// 继续处理用户信息
|
||||
userInfoBytes, err := json.Marshal(<-userInfoChan)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
var gitHubUser GitHubUser
|
||||
err = json.Unmarshal(userInfoBytes, &gitHubUser)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
Id := strconv.Itoa(gitHubUser.ID)
|
||||
userSocial, err := userSocialService.QueryUserSocialByUUID(Id, enum.OAuthSourceGithub)
|
||||
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
db := global.DB
|
||||
tx := db.Begin() // 开始事务
|
||||
if tx.Error != nil {
|
||||
global.LOG.Error(tx.Error)
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
}()
|
||||
// 第一次登录,创建用户
|
||||
uid := idgen.NextId()
|
||||
uidStr := strconv.FormatInt(uid, 10)
|
||||
user := model.ScaAuthUser{
|
||||
UID: &uidStr,
|
||||
Username: &gitHubUser.Login,
|
||||
Nickname: &gitHubUser.Name,
|
||||
Avatar: &gitHubUser.AvatarURL,
|
||||
Blog: &gitHubUser.Blog,
|
||||
Email: &gitHubUser.Email,
|
||||
}
|
||||
addUser, err := userService.AddUser(user)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
github := enum.OAuthSourceGithub
|
||||
userSocial = model.ScaAuthUserSocial{
|
||||
UserID: &uidStr,
|
||||
UUID: &Id,
|
||||
Source: &github,
|
||||
}
|
||||
err = userSocialService.AddUserSocial(userSocial)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
_, err = global.Casbin.AddRoleForUser(uidStr, enum.User)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
if err := tx.Commit().Error; err != nil {
|
||||
tx.Rollback()
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
HandleLoginResponse(c, *addUser.UID)
|
||||
} else {
|
||||
HandleLoginResponse(c, *userSocial.UserID)
|
||||
}
|
||||
return
|
||||
}
|
||||
var gitHubUser GitHubUser
|
||||
err = json.Unmarshal(userInfoBytes, &gitHubUser)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
Id := strconv.Itoa(gitHubUser.ID)
|
||||
userSocial, err := userSocialService.QueryUserSocialByUUID(Id, enum.OAuthSourceGithub)
|
||||
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
// 第一次登录,创建用户
|
||||
uid := idgen.NextId()
|
||||
uidStr := strconv.FormatInt(uid, 10)
|
||||
user := model.ScaAuthUser{
|
||||
UID: &uidStr,
|
||||
Username: &gitHubUser.Login,
|
||||
Nickname: &gitHubUser.Name,
|
||||
Avatar: &gitHubUser.AvatarURL,
|
||||
Blog: &gitHubUser.Blog,
|
||||
Email: &gitHubUser.Email,
|
||||
}
|
||||
addUser, err := userService.AddUser(user)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
github := enum.OAuthSourceGithub
|
||||
userSocial = model.ScaAuthUserSocial{
|
||||
UserID: &addUser.ID,
|
||||
UUID: &Id,
|
||||
Source: &github,
|
||||
}
|
||||
err = userSocialService.AddUserSocial(userSocial)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
userRole := model.ScaAuthUserRole{
|
||||
UserID: uidStr,
|
||||
RoleID: enum.User,
|
||||
}
|
||||
err = userRoleService.AddUserRole(userRole)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
res, data := HandelUserLogin(addUser)
|
||||
if !res {
|
||||
return
|
||||
}
|
||||
tokenData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
formattedScript := fmt.Sprintf(script, tokenData, global.CONFIG.System.Web)
|
||||
c.Data(http.StatusOK, "text/html; charset=utf-8", []byte(formattedScript))
|
||||
} else {
|
||||
user, err := userService.QueryUserById(userSocial.UserID)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
res, data := HandelUserLogin(user)
|
||||
if !res {
|
||||
return
|
||||
}
|
||||
tokenData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
formattedScript := fmt.Sprintf(script, tokenData, global.CONFIG.System.Web)
|
||||
c.Data(http.StatusOK, "text/html; charset=utf-8", []byte(formattedScript))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@@ -2,10 +2,13 @@ package oauth_api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"schisandra-cloud-album/api/user_api/dto"
|
||||
"schisandra-cloud-album/common/constant"
|
||||
"schisandra-cloud-album/common/redis"
|
||||
"schisandra-cloud-album/model"
|
||||
"schisandra-cloud-album/global"
|
||||
"schisandra-cloud-album/service"
|
||||
"schisandra-cloud-album/utils"
|
||||
"time"
|
||||
@@ -14,11 +17,7 @@ import (
|
||||
type OAuthAPI struct{}
|
||||
|
||||
var userService = service.Service.UserService
|
||||
var userRoleService = service.Service.UserRoleService
|
||||
var userSocialService = service.Service.UserSocialService
|
||||
var rolePermissionService = service.Service.RolePermissionService
|
||||
var permissionServiceService = service.Service.PermissionService
|
||||
var roleService = service.Service.RoleService
|
||||
|
||||
type Token struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
@@ -31,50 +30,82 @@ var script = `
|
||||
</script>
|
||||
`
|
||||
|
||||
func HandleLoginResponse(c *gin.Context, uid string) {
|
||||
res, data := HandelUserLogin(uid)
|
||||
if !res {
|
||||
return
|
||||
}
|
||||
tokenData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
formattedScript := fmt.Sprintf(script, tokenData, global.CONFIG.System.Web)
|
||||
c.Data(http.StatusOK, "text/html; charset=utf-8", []byte(formattedScript))
|
||||
return
|
||||
}
|
||||
|
||||
// HandelUserLogin 处理用户登录
|
||||
func HandelUserLogin(user model.ScaAuthUser) (bool, map[string]interface{}) {
|
||||
ids, err := userRoleService.GetUserRoleIdsByUserId(user.ID)
|
||||
if err != nil {
|
||||
func HandelUserLogin(userId string) (bool, map[string]interface{}) {
|
||||
// 使用goroutine生成accessToken
|
||||
accessTokenChan := make(chan string)
|
||||
errChan := make(chan error)
|
||||
go func() {
|
||||
accessToken, err := utils.GenerateAccessToken(utils.AccessJWTPayload{UserID: &userId})
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
accessTokenChan <- accessToken
|
||||
}()
|
||||
|
||||
// 使用goroutine生成refreshToken
|
||||
refreshTokenChan := make(chan string)
|
||||
expiresAtChan := make(chan int64)
|
||||
go func() {
|
||||
refreshToken, expiresAt := utils.GenerateRefreshToken(utils.RefreshJWTPayload{UserID: &userId}, time.Hour*24*7)
|
||||
refreshTokenChan <- refreshToken
|
||||
expiresAtChan <- expiresAt
|
||||
}()
|
||||
|
||||
// 等待accessToken和refreshToken生成完成
|
||||
var accessToken string
|
||||
var refreshToken string
|
||||
var expiresAt int64
|
||||
var err error
|
||||
select {
|
||||
case accessToken = <-accessTokenChan:
|
||||
case err = <-errChan:
|
||||
global.LOG.Error(err)
|
||||
return false, nil
|
||||
}
|
||||
permissionIds := rolePermissionService.QueryPermissionIdsByRoleId(ids)
|
||||
permissions, err := permissionServiceService.GetPermissionsByIds(permissionIds)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
select {
|
||||
case refreshToken = <-refreshTokenChan:
|
||||
case expiresAt = <-expiresAtChan:
|
||||
}
|
||||
serializedPermissions, err := json.Marshal(permissions)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
wrong := redis.Set(constant.UserAuthPermissionRedisKey+*user.UID, serializedPermissions, 0).Err()
|
||||
if wrong != nil {
|
||||
return false, nil
|
||||
}
|
||||
roleList, err := roleService.GetRoleListByIds(ids)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
serializedRoleList, err := json.Marshal(roleList)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
er := redis.Set(constant.UserAuthRoleRedisKey+*user.UID, serializedRoleList, 0).Err()
|
||||
if er != nil {
|
||||
return false, nil
|
||||
}
|
||||
accessToken, err := utils.GenerateAccessToken(utils.AccessJWTPayload{UserID: user.UID, RoleID: ids})
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
refreshToken, expiresAt := utils.GenerateRefreshToken(utils.RefreshJWTPayload{UserID: user.UID, RoleID: ids}, time.Hour*24*7)
|
||||
|
||||
data := dto.ResponseData{
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
ExpiresAt: expiresAt,
|
||||
UID: user.UID,
|
||||
UID: &userId,
|
||||
}
|
||||
fail := redis.Set(constant.UserLoginTokenRedisKey+*user.UID, data, time.Hour*24*7).Err()
|
||||
if fail != nil {
|
||||
|
||||
// 使用goroutine将数据存入redis
|
||||
redisErrChan := make(chan error)
|
||||
go func() {
|
||||
fail := redis.Set(constant.UserLoginTokenRedisKey+userId, data, time.Hour*24*7).Err()
|
||||
if fail != nil {
|
||||
redisErrChan <- fail
|
||||
return
|
||||
}
|
||||
redisErrChan <- nil
|
||||
}()
|
||||
|
||||
// 等待redis操作完成
|
||||
redisErr := <-redisErrChan
|
||||
if redisErr != nil {
|
||||
global.LOG.Error(redisErr)
|
||||
return false, nil
|
||||
}
|
||||
responseData := map[string]interface{}{
|
||||
|
@@ -173,23 +173,61 @@ func (OAuthAPI) QQCallback(c *gin.Context) {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||
return
|
||||
}
|
||||
|
||||
// 通过 code, 获取 token
|
||||
var tokenAuthUrl = GetQQTokenAuthUrl(code)
|
||||
tokenChan := make(chan *QQToken)
|
||||
errChan := make(chan error)
|
||||
go func() {
|
||||
token, err := GetQQToken(tokenAuthUrl)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
tokenChan <- token
|
||||
}()
|
||||
var token *QQToken
|
||||
if token, err = GetQQToken(tokenAuthUrl); err != nil {
|
||||
select {
|
||||
case token = <-tokenChan:
|
||||
case err = <-errChan:
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 通过 token,获取 openid
|
||||
authQQme, err := GetQQUserOpenID(token)
|
||||
if err != nil {
|
||||
openIDChan := make(chan *AuthQQme)
|
||||
errChan = make(chan error)
|
||||
go func() {
|
||||
authQQme, err := GetQQUserOpenID(token)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
openIDChan <- authQQme
|
||||
}()
|
||||
var authQQme *AuthQQme
|
||||
select {
|
||||
case authQQme = <-openIDChan:
|
||||
case err = <-errChan:
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 通过token,获取用户信息
|
||||
userInfoChan := make(chan map[string]interface{})
|
||||
errChan = make(chan error)
|
||||
go func() {
|
||||
userInfo, err := GetQQUserUserInfo(token, authQQme.OpenID)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
userInfoChan <- userInfo
|
||||
}()
|
||||
var userInfo map[string]interface{}
|
||||
if userInfo, err = GetQQUserUserInfo(token, authQQme.OpenID); err != nil {
|
||||
select {
|
||||
case userInfo = <-userInfoChan:
|
||||
case err = <-errChan:
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
@@ -205,8 +243,20 @@ func (OAuthAPI) QQCallback(c *gin.Context) {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
userSocial, err := userSocialService.QueryUserSocialByOpenID(authQQme.OpenID, enum.OAuthSourceQQ)
|
||||
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
db := global.DB
|
||||
tx := db.Begin() // 开始事务
|
||||
if tx.Error != nil {
|
||||
global.LOG.Error(tx.Error)
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
}()
|
||||
// 第一次登录,创建用户
|
||||
uid := idgen.NextId()
|
||||
uidStr := strconv.FormatInt(uid, 10)
|
||||
@@ -221,59 +271,36 @@ func (OAuthAPI) QQCallback(c *gin.Context) {
|
||||
}
|
||||
addUser, err := userService.AddUser(user)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
qq := enum.OAuthSourceQQ
|
||||
userSocial = model.ScaAuthUserSocial{
|
||||
UserID: &addUser.ID,
|
||||
UserID: &uidStr,
|
||||
OpenID: &authQQme.OpenID,
|
||||
Source: &qq,
|
||||
}
|
||||
err = userSocialService.AddUserSocial(userSocial)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
userRole := model.ScaAuthUserRole{
|
||||
UserID: uidStr,
|
||||
RoleID: enum.User,
|
||||
}
|
||||
err = userRoleService.AddUserRole(userRole)
|
||||
_, err = global.Casbin.AddRoleForUser(uidStr, enum.User)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
res, data := HandelUserLogin(addUser)
|
||||
if !res {
|
||||
return
|
||||
}
|
||||
tokenData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
if err := tx.Commit().Error; err != nil {
|
||||
tx.Rollback()
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
formattedScript := fmt.Sprintf(script, tokenData, global.CONFIG.System.Web)
|
||||
c.Data(http.StatusOK, "text/html; charset=utf-8", []byte(formattedScript))
|
||||
HandleLoginResponse(c, *addUser.UID)
|
||||
return
|
||||
} else {
|
||||
user, err := userService.QueryUserById(userSocial.UserID)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
res, data := HandelUserLogin(user)
|
||||
if !res {
|
||||
return
|
||||
}
|
||||
tokenData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
formattedScript := fmt.Sprintf(script, tokenData, global.CONFIG.System.Web)
|
||||
c.Data(http.StatusOK, "text/html; charset=utf-8", []byte(formattedScript))
|
||||
return
|
||||
HandleLoginResponse(c, *userSocial.UserID)
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -26,9 +26,12 @@ import (
|
||||
"schisandra-cloud-album/utils"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var mu sync.Mutex
|
||||
|
||||
// GenerateClientId 生成客户端ID
|
||||
// @Summary 生成客户端ID
|
||||
// @Description 生成客户端ID
|
||||
@@ -44,6 +47,9 @@ func (OAuthAPI) GenerateClientId(c *gin.Context) {
|
||||
if ip == "" {
|
||||
ip = c.ClientIP()
|
||||
}
|
||||
// 加锁
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
// 从Redis获取客户端ID
|
||||
clientId := redis.Get(constant.UserLoginClientRedisKey + ip).Val()
|
||||
@@ -70,10 +76,7 @@ func (OAuthAPI) GenerateClientId(c *gin.Context) {
|
||||
// @Router /api/oauth/callback_notify [POST]
|
||||
func (OAuthAPI) CallbackNotify(c *gin.Context) {
|
||||
rs, err := global.Wechat.Server.Notify(c.Request, func(event contract.EventInterface) interface{} {
|
||||
fmt.Dump("event", event)
|
||||
|
||||
switch event.GetMsgType() {
|
||||
|
||||
case models2.CALLBACK_MSG_TYPE_EVENT:
|
||||
switch event.GetEvent() {
|
||||
case models.CALLBACK_EVENT_SUBSCRIBE:
|
||||
@@ -122,7 +125,6 @@ func (OAuthAPI) CallbackNotify(c *gin.Context) {
|
||||
println(err.Error())
|
||||
return "error"
|
||||
}
|
||||
fmt.Dump(msg)
|
||||
}
|
||||
return messages.NewText("ok")
|
||||
|
||||
@@ -177,6 +179,7 @@ func (OAuthAPI) GetTempQrCode(c *gin.Context) {
|
||||
data := response.ResponseQRCodeCreate{}
|
||||
err := json.Unmarshal([]byte(qrcode), &data)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
result.OK(ginI18n.MustGetMessage(c, "QRCodeGetSuccess"), data.Url, c)
|
||||
@@ -184,17 +187,20 @@ func (OAuthAPI) GetTempQrCode(c *gin.Context) {
|
||||
}
|
||||
data, err := global.Wechat.QRCode.Temporary(c.Request.Context(), clientId, 30*24*3600)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "QRCodeGetFailed"), c)
|
||||
return
|
||||
}
|
||||
serializedData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "QRCodeGetFailed"), c)
|
||||
return
|
||||
}
|
||||
wrong := redis.Set(constant.UserLoginQrcodeRedisKey+ip+":"+clientId, serializedData, time.Hour*24*30).Err()
|
||||
|
||||
if wrong != nil {
|
||||
global.LOG.Error(wrong)
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "QRCodeGetFailed"), c)
|
||||
return
|
||||
}
|
||||
@@ -208,45 +214,98 @@ func wechatLoginHandler(openId string, clientId string) bool {
|
||||
}
|
||||
authUserSocial, err := userSocialService.QueryUserSocialByOpenID(openId, enum.OAuthSourceWechat)
|
||||
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
tx := global.DB.Begin()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
}()
|
||||
|
||||
uid := idgen.NextId()
|
||||
uidStr := strconv.FormatInt(uid, 10)
|
||||
createUser := model.ScaAuthUser{
|
||||
UID: &uidStr,
|
||||
Username: &openId,
|
||||
}
|
||||
addUser, err := userService.AddUser(createUser)
|
||||
if err != nil {
|
||||
|
||||
// 异步添加用户
|
||||
addUserChan := make(chan *model.ScaAuthUser, 1)
|
||||
errChan := make(chan error, 1)
|
||||
go func() {
|
||||
addUser, err := userService.AddUser(createUser)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
addUserChan <- &addUser
|
||||
}()
|
||||
|
||||
var addUser *model.ScaAuthUser
|
||||
select {
|
||||
case addUser = <-addUserChan:
|
||||
case err := <-errChan:
|
||||
tx.Rollback()
|
||||
global.LOG.Error(err)
|
||||
return false
|
||||
}
|
||||
|
||||
wechat := enum.OAuthSourceWechat
|
||||
userSocial := model.ScaAuthUserSocial{
|
||||
UserID: &addUser.ID,
|
||||
UserID: &uidStr,
|
||||
OpenID: &openId,
|
||||
Source: &wechat,
|
||||
}
|
||||
wrong := userSocialService.AddUserSocial(userSocial)
|
||||
if wrong != nil {
|
||||
return false
|
||||
|
||||
// 异步添加用户社交信息
|
||||
wrongChan := make(chan error, 1)
|
||||
go func() {
|
||||
wrong := userSocialService.AddUserSocial(userSocial)
|
||||
wrongChan <- wrong
|
||||
}()
|
||||
|
||||
select {
|
||||
case wrong := <-wrongChan:
|
||||
if wrong != nil {
|
||||
tx.Rollback()
|
||||
global.LOG.Error(wrong)
|
||||
return false
|
||||
}
|
||||
}
|
||||
userRole := model.ScaAuthUserRole{
|
||||
UserID: uidStr,
|
||||
RoleID: enum.User,
|
||||
|
||||
// 异步添加角色
|
||||
roleErrChan := make(chan error, 1)
|
||||
go func() {
|
||||
_, err := global.Casbin.AddRoleForUser(uidStr, enum.User)
|
||||
roleErrChan <- err
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-roleErrChan:
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
global.LOG.Error(err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
e := userRoleService.AddUserRole(userRole)
|
||||
if e != nil {
|
||||
return false
|
||||
}
|
||||
res := handelUserLogin(addUser, clientId)
|
||||
if !res {
|
||||
return false
|
||||
|
||||
// 异步处理用户登录
|
||||
resChan := make(chan bool, 1)
|
||||
go func() {
|
||||
res := handelUserLogin(*addUser.UID, clientId)
|
||||
resChan <- res
|
||||
}()
|
||||
|
||||
select {
|
||||
case res := <-resChan:
|
||||
if !res {
|
||||
tx.Rollback()
|
||||
return false
|
||||
}
|
||||
}
|
||||
tx.Commit()
|
||||
return true
|
||||
} else {
|
||||
user, err := userService.QueryUserById(authUserSocial.UserID)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
res := handelUserLogin(user, clientId)
|
||||
res := handelUserLogin(*authUserSocial.UserID, clientId)
|
||||
if !res {
|
||||
return false
|
||||
}
|
||||
@@ -255,70 +314,47 @@ func wechatLoginHandler(openId string, clientId string) bool {
|
||||
}
|
||||
|
||||
// handelUserLogin 处理用户登录
|
||||
func handelUserLogin(user model.ScaAuthUser, clientId string) bool {
|
||||
ids, err := userRoleService.GetUserRoleIdsByUserId(user.ID)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
permissionIds := rolePermissionService.QueryPermissionIdsByRoleId(ids)
|
||||
permissions, err := permissionServiceService.GetPermissionsByIds(permissionIds)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
serializedPermissions, err := json.Marshal(permissions)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
wrong := redis.Set(constant.UserAuthPermissionRedisKey+*user.UID, serializedPermissions, 0).Err()
|
||||
if wrong != nil {
|
||||
return false
|
||||
}
|
||||
roleList, err := roleService.GetRoleListByIds(ids)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
serializedRoleList, err := json.Marshal(roleList)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
er := redis.Set(constant.UserAuthRoleRedisKey+*user.UID, serializedRoleList, 0).Err()
|
||||
if er != nil {
|
||||
return false
|
||||
}
|
||||
accessToken, err := utils.GenerateAccessToken(utils.AccessJWTPayload{UserID: user.UID, RoleID: ids})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
refreshToken, expiresAt := utils.GenerateRefreshToken(utils.RefreshJWTPayload{UserID: user.UID, RoleID: ids}, time.Hour*24*7)
|
||||
data := dto.ResponseData{
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
ExpiresAt: expiresAt,
|
||||
UID: user.UID,
|
||||
}
|
||||
fail := redis.Set(constant.UserLoginTokenRedisKey+*user.UID, data, time.Hour*24*7).Err()
|
||||
if fail != nil {
|
||||
return false
|
||||
}
|
||||
responseData := map[string]interface{}{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": data,
|
||||
"success": true,
|
||||
}
|
||||
tokenData, err := json.Marshal(responseData)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
// gws方式发送消息
|
||||
err = websocket_api.Handler.SendMessageToClient(clientId, tokenData)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
// gorilla websocket方式发送消息
|
||||
//res := websocket_api.SendMessageData(clientId, responseData)
|
||||
//if !res {
|
||||
// return false
|
||||
//}
|
||||
return true
|
||||
func handelUserLogin(userId string, clientId string) bool {
|
||||
resultChan := make(chan bool, 1)
|
||||
|
||||
go func() {
|
||||
accessToken, err := utils.GenerateAccessToken(utils.AccessJWTPayload{UserID: &userId})
|
||||
if err != nil {
|
||||
resultChan <- false
|
||||
return
|
||||
}
|
||||
refreshToken, expiresAt := utils.GenerateRefreshToken(utils.RefreshJWTPayload{UserID: &userId}, time.Hour*24*7)
|
||||
data := dto.ResponseData{
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
ExpiresAt: expiresAt,
|
||||
UID: &userId,
|
||||
}
|
||||
fail := redis.Set(constant.UserLoginTokenRedisKey+userId, data, time.Hour*24*7).Err()
|
||||
if fail != nil {
|
||||
resultChan <- false
|
||||
return
|
||||
}
|
||||
responseData := map[string]interface{}{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": data,
|
||||
"success": true,
|
||||
}
|
||||
tokenData, err := json.Marshal(responseData)
|
||||
if err != nil {
|
||||
resultChan <- false
|
||||
return
|
||||
}
|
||||
// gws方式发送消息
|
||||
err = websocket_api.Handler.SendMessageToClient(clientId, tokenData)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
resultChan <- false
|
||||
return
|
||||
}
|
||||
resultChan <- true
|
||||
}()
|
||||
|
||||
return <-resultChan
|
||||
}
|
||||
|
11
api/permission_api/dto/request_dto.go
Normal file
11
api/permission_api/dto/request_dto.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package dto
|
||||
|
||||
import "schisandra-cloud-album/model"
|
||||
|
||||
type AddPermissionRequestDto struct {
|
||||
Permissions []model.ScaAuthPermission `json:"permissions"`
|
||||
}
|
||||
type AddPermissionToRoleRequestDto struct {
|
||||
RoleKey string `json:"role_key"`
|
||||
Permissions []model.ScaAuthPermission `json:"permissions"`
|
||||
}
|
3
api/permission_api/permission.go
Normal file
3
api/permission_api/permission.go
Normal file
@@ -0,0 +1,3 @@
|
||||
package permission_api
|
||||
|
||||
type PermissionAPI struct{}
|
36
api/permission_api/permission_api.go
Normal file
36
api/permission_api/permission_api.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package permission_api
|
||||
|
||||
import (
|
||||
ginI18n "github.com/gin-contrib/i18n"
|
||||
"github.com/gin-gonic/gin"
|
||||
"schisandra-cloud-album/api/permission_api/dto"
|
||||
"schisandra-cloud-album/common/result"
|
||||
"schisandra-cloud-album/global"
|
||||
"schisandra-cloud-album/service"
|
||||
)
|
||||
|
||||
var permissionService = service.Service.PermissionService
|
||||
|
||||
// AddPermissions 批量添加权限
|
||||
// @Summary 批量添加权限
|
||||
// @Description 批量添加权限
|
||||
// @Tags 权限管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param permissions body dto.AddPermissionRequestDto true "权限列表"
|
||||
// @Router /api/auth/permission/add [post]
|
||||
func (PermissionAPI) AddPermissions(c *gin.Context) {
|
||||
addPermissionRequestDto := dto.AddPermissionRequestDto{}
|
||||
err := c.ShouldBindJSON(&addPermissionRequestDto)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = permissionService.CreatePermissions(addPermissionRequestDto.Permissions)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CreatedFailed"), c)
|
||||
return
|
||||
}
|
||||
result.OkWithMessage(ginI18n.MustGetMessage(c, "CreatedSuccess"), c)
|
||||
return
|
||||
}
|
11
api/role_api/dto/request_dto.go
Normal file
11
api/role_api/dto/request_dto.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package dto
|
||||
|
||||
type RoleRequestDto struct {
|
||||
RoleName string `json:"role_name"`
|
||||
RoleKey string `json:"role_key"`
|
||||
}
|
||||
|
||||
type AddRoleToUserRequestDto struct {
|
||||
Uid string `json:"uid"`
|
||||
RoleKey string `json:"role_key"`
|
||||
}
|
@@ -1 +1,64 @@
|
||||
package role_api
|
||||
|
||||
import (
|
||||
ginI18n "github.com/gin-contrib/i18n"
|
||||
"github.com/gin-gonic/gin"
|
||||
"schisandra-cloud-album/api/role_api/dto"
|
||||
"schisandra-cloud-album/common/result"
|
||||
"schisandra-cloud-album/global"
|
||||
"schisandra-cloud-album/model"
|
||||
"schisandra-cloud-album/service"
|
||||
)
|
||||
|
||||
var roleService = service.Service.RoleService
|
||||
|
||||
// CreateRole 创建角色
|
||||
// @Summary 创建角色
|
||||
// @Description 创建角色
|
||||
// @Tags 角色
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param roleRequestDto body dto.RoleRequestDto true "角色信息"
|
||||
// @Router /api/auth/role/create [post]
|
||||
func (RoleAPI) CreateRole(c *gin.Context) {
|
||||
roleRequestDto := dto.RoleRequestDto{}
|
||||
err := c.ShouldBindJSON(&roleRequestDto)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CreatedFailed"), c)
|
||||
return
|
||||
}
|
||||
role := model.ScaAuthRole{
|
||||
RoleName: roleRequestDto.RoleName,
|
||||
RoleKey: roleRequestDto.RoleKey,
|
||||
}
|
||||
err = roleService.AddRole(role)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CreatedFailed"), c)
|
||||
return
|
||||
}
|
||||
result.OkWithMessage(ginI18n.MustGetMessage(c, "CreatedSuccess"), c)
|
||||
}
|
||||
|
||||
// AddRoleToUser 给指定用户添加角色
|
||||
// @Summary 给指定用户添加角色
|
||||
// @Description 给指定用户添加角色
|
||||
// @Tags 角色
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param addRoleToUserRequestDto body dto.AddRoleToUserRequestDto true "给指定用户添加角色"
|
||||
// @Router /api/auth/role/add_role_to_user [post]
|
||||
func (RoleAPI) AddRoleToUser(c *gin.Context) {
|
||||
addRoleToUserRequestDto := dto.AddRoleToUserRequestDto{}
|
||||
err := c.ShouldBindJSON(&addRoleToUserRequestDto)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
user, err := global.Casbin.AddRoleForUser(addRoleToUserRequestDto.Uid, addRoleToUserRequestDto.RoleKey)
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return
|
||||
}
|
||||
result.OkWithData(user, c)
|
||||
}
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package user_api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
ginI18n "github.com/gin-contrib/i18n"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/yitter/idgenerator-go/idgen"
|
||||
@@ -20,10 +19,6 @@ import (
|
||||
)
|
||||
|
||||
var userService = service.Service.UserService
|
||||
var userRoleService = service.Service.UserRoleService
|
||||
var rolePermissionService = service.Service.RolePermissionService
|
||||
var permissionServiceService = service.Service.PermissionService
|
||||
var roleService = service.Service.RoleService
|
||||
|
||||
// GetUserList
|
||||
// @Summary 获取所有用户列表
|
||||
@@ -146,12 +141,8 @@ func (UserAPI) AddUser(c *gin.Context) {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "AddUserError"), c)
|
||||
return
|
||||
}
|
||||
userRole := model.ScaAuthUserRole{
|
||||
UserID: uidStr,
|
||||
RoleID: enum.User,
|
||||
}
|
||||
e := userRoleService.AddUserRole(userRole)
|
||||
if e != nil {
|
||||
_, err = global.Casbin.AddRoleForUser(uidStr, enum.User)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "AddUserRoleError"), c)
|
||||
return
|
||||
}
|
||||
@@ -258,11 +249,30 @@ func (UserAPI) PhoneLogin(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
user := userService.QueryUserByPhone(phone)
|
||||
if reflect.DeepEqual(user, model.ScaAuthUser{}) {
|
||||
// 未注册
|
||||
// 异步查询用户信息
|
||||
userChan := make(chan *model.ScaAuthUser)
|
||||
go func() {
|
||||
user := userService.QueryUserByPhone(phone)
|
||||
userChan <- &user
|
||||
}()
|
||||
|
||||
// 异步获取验证码
|
||||
codeChan := make(chan string)
|
||||
go func() {
|
||||
code := redis.Get(constant.UserLoginSmsRedisKey + phone)
|
||||
if code == nil {
|
||||
codeChan <- ""
|
||||
} else {
|
||||
codeChan <- code.Val()
|
||||
}
|
||||
}()
|
||||
|
||||
user := <-userChan
|
||||
code := <-codeChan
|
||||
|
||||
if reflect.DeepEqual(user, model.ScaAuthUser{}) {
|
||||
// 未注册
|
||||
if code == "" {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CaptchaExpired"), c)
|
||||
return
|
||||
} else {
|
||||
@@ -277,35 +287,29 @@ func (UserAPI) PhoneLogin(c *gin.Context) {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "RegisterUserError"), c)
|
||||
return
|
||||
}
|
||||
userRole := model.ScaAuthUserRole{
|
||||
UserID: uidStr,
|
||||
RoleID: enum.User,
|
||||
}
|
||||
e := userRoleService.AddUserRole(userRole)
|
||||
if e != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
|
||||
|
||||
_, err = global.Casbin.AddRoleForUser(uidStr, enum.User)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "RegisterUserError"), c)
|
||||
return
|
||||
}
|
||||
handelUserLogin(addUser, request.AutoLogin, c)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
code := redis.Get(constant.UserLoginSmsRedisKey + phone)
|
||||
if code == nil {
|
||||
if code == "" {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CaptchaExpired"), c)
|
||||
return
|
||||
} else {
|
||||
if captcha != code.Val() {
|
||||
if captcha != code {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CaptchaError"), c)
|
||||
return
|
||||
} else {
|
||||
handelUserLogin(user, request.AutoLogin, c)
|
||||
handelUserLogin(*user, request.AutoLogin, c)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// RefreshHandler 刷新token
|
||||
@@ -333,7 +337,7 @@ func (UserAPI) RefreshHandler(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
if isUpd {
|
||||
accessTokenString, err := utils.GenerateAccessToken(utils.AccessJWTPayload{UserID: parseRefreshToken.UserID, RoleID: parseRefreshToken.RoleID})
|
||||
accessTokenString, err := utils.GenerateAccessToken(utils.AccessJWTPayload{UserID: parseRefreshToken.UserID})
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginExpired"), c)
|
||||
return
|
||||
@@ -362,42 +366,7 @@ func (UserAPI) RefreshHandler(c *gin.Context) {
|
||||
|
||||
// handelUserLogin 处理用户登录
|
||||
func handelUserLogin(user model.ScaAuthUser, autoLogin bool, c *gin.Context) {
|
||||
ids, err := userRoleService.GetUserRoleIdsByUserId(user.ID)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
|
||||
return
|
||||
}
|
||||
permissionIds := rolePermissionService.QueryPermissionIdsByRoleId(ids)
|
||||
permissions, err := permissionServiceService.GetPermissionsByIds(permissionIds)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
|
||||
return
|
||||
}
|
||||
serializedPermissions, err := json.Marshal(permissions)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
|
||||
return
|
||||
}
|
||||
wrong := redis.Set(constant.UserAuthPermissionRedisKey+*user.UID, serializedPermissions, 0).Err()
|
||||
if wrong != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
|
||||
return
|
||||
}
|
||||
roleList, err := roleService.GetRoleListByIds(ids)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
serializedRoleList, err := json.Marshal(roleList)
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
|
||||
return
|
||||
}
|
||||
er := redis.Set(constant.UserAuthRoleRedisKey+*user.UID, serializedRoleList, 0).Err()
|
||||
if er != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
|
||||
return
|
||||
}
|
||||
accessToken, err := utils.GenerateAccessToken(utils.AccessJWTPayload{UserID: user.UID, RoleID: ids})
|
||||
accessToken, err := utils.GenerateAccessToken(utils.AccessJWTPayload{UserID: user.UID})
|
||||
if err != nil {
|
||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
|
||||
return
|
||||
@@ -408,7 +377,7 @@ func handelUserLogin(user model.ScaAuthUser, autoLogin bool, c *gin.Context) {
|
||||
} else {
|
||||
days = time.Hour * 24 * 1
|
||||
}
|
||||
refreshToken, expiresAt := utils.GenerateRefreshToken(utils.RefreshJWTPayload{UserID: user.UID, RoleID: ids}, days)
|
||||
refreshToken, expiresAt := utils.GenerateRefreshToken(utils.RefreshJWTPayload{UserID: user.UID}, days)
|
||||
data := dto.ResponseData{
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
|
@@ -12,8 +12,6 @@ func MakeMigration() {
|
||||
&model.ScaAuthUser{},
|
||||
&model.ScaAuthPermission{},
|
||||
&model.ScaAuthRole{},
|
||||
&model.ScaAuthRolePermission{},
|
||||
&model.ScaAuthUserRole{},
|
||||
&model.ScaAuthUserDevice{},
|
||||
&model.ScaAuthUserSocial{},
|
||||
)
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package enum
|
||||
|
||||
var (
|
||||
SuperAdmin int64 = 1
|
||||
Admin int64 = 2
|
||||
User int64 = 3
|
||||
Root string = "root"
|
||||
Admin string = "admin"
|
||||
User string = "user"
|
||||
)
|
||||
|
10
config/conf_casbin.go
Normal file
10
config/conf_casbin.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package config
|
||||
|
||||
type Casbin struct {
|
||||
// 权限模型文件路径
|
||||
ModelPath string `yaml:"model-path"`
|
||||
// 数据库前缀
|
||||
TablePrefix string `yaml:"table-prefix"`
|
||||
// 数据库表明
|
||||
TableName string `yaml:"table-name"`
|
||||
}
|
@@ -2,9 +2,9 @@ package config
|
||||
|
||||
// Logger 配置
|
||||
type Logger struct {
|
||||
Level string `yaml:"level"` // 日志级别
|
||||
Prefix string `yaml:"prefix"` // 日志前缀
|
||||
Director string `yaml:"director"` // 日志文件存放目录
|
||||
ShowLine bool `yaml:"show-line"` // 是否显示文件行号
|
||||
LogInConsole string `yaml:"log-in-console"` // 是否在控制台打印日志
|
||||
Level string `yaml:"level"` // 日志级别
|
||||
Prefix string `yaml:"prefix"` // 日志前缀
|
||||
Director string `yaml:"director"` // 日志文件存放目录
|
||||
ShowLine bool `yaml:"show-line"` // 是否显示文件行号
|
||||
LogName string `yaml:"log-name"` // 日志文件名
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@ type System struct {
|
||||
Port string `yaml:"port"` //端口号
|
||||
Env string `yaml:"env"` //环境
|
||||
Web string `yaml:"web"` //web地址
|
||||
Ip string `yaml:"ip"` //ip地址
|
||||
}
|
||||
|
||||
func (s *System) Addr() string {
|
||||
|
@@ -11,4 +11,5 @@ type Config struct {
|
||||
Wechat Wechat `yaml:"wechat"`
|
||||
OAuth OAuth `yaml:"oauth"`
|
||||
Swagger Swagger `yaml:"swagger"`
|
||||
Casbin Casbin `yaml:"casbin"`
|
||||
}
|
||||
|
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/wenlng/go-captcha/v2/click"
|
||||
"github.com/wenlng/go-captcha/v2/rotate"
|
||||
"github.com/wenlng/go-captcha/v2/slide"
|
||||
"log"
|
||||
"schisandra-cloud-album/global"
|
||||
)
|
||||
|
||||
@@ -47,13 +46,13 @@ func initTextCaptcha() {
|
||||
// fonts
|
||||
fonts, err := fzshengsksjw.GetFont()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
global.LOG.Fatalln(err)
|
||||
}
|
||||
|
||||
// background images
|
||||
imgs, err := images.GetImages()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
global.LOG.Fatalln(err)
|
||||
}
|
||||
|
||||
// thumb images
|
||||
@@ -119,13 +118,13 @@ func initClickShapeCaptcha() {
|
||||
// click.WithUseShapeOriginalColor(false) -> Random rewriting of graphic colors
|
||||
shapeMaps, err := shapes.GetShapes()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
global.LOG.Fatalln(err)
|
||||
}
|
||||
|
||||
// background images
|
||||
imgs, err := images.GetImages()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
global.LOG.Fatalln(err)
|
||||
}
|
||||
|
||||
// set resources
|
||||
@@ -146,12 +145,12 @@ func initsSlideCaptcha() {
|
||||
// background images
|
||||
imgs, err := images.GetImages()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
global.LOG.Fatalln(err)
|
||||
}
|
||||
|
||||
graphs, err := tiles.GetTiles()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
global.LOG.Fatalln(err)
|
||||
}
|
||||
|
||||
var newGraphs = make([]*slide.GraphImage, 0, len(graphs))
|
||||
@@ -182,7 +181,7 @@ func initRotateCaptcha() {
|
||||
// background images
|
||||
imgs, err := images.GetImages()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
global.LOG.Fatalln(err)
|
||||
}
|
||||
|
||||
// set resources
|
||||
@@ -203,12 +202,12 @@ func initSlideRegionCaptcha() {
|
||||
// background image
|
||||
imgs, err := images.GetImages()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
global.LOG.Fatalln(err)
|
||||
}
|
||||
|
||||
graphs, err := tiles.GetTiles()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
global.LOG.Fatalln(err)
|
||||
}
|
||||
var newGraphs = make([]*slide.GraphImage, 0, len(graphs))
|
||||
for i := 0; i < len(graphs); i++ {
|
||||
|
@@ -14,13 +14,22 @@ var (
|
||||
|
||||
func InitCasbin() {
|
||||
once.Do(func() {
|
||||
adapter, _ := gormadapter.NewAdapterByDBUseTableName(global.DB, "sca_sys_", "casbin_rule")
|
||||
m, err := model.NewModelFromFile("config/rbac_model.pml")
|
||||
adapter, err := gormadapter.NewAdapterByDBUseTableName(global.DB, global.CONFIG.Casbin.TablePrefix, global.CONFIG.Casbin.TableName)
|
||||
if err != nil {
|
||||
global.LOG.Error(err.Error())
|
||||
panic(err)
|
||||
}
|
||||
e, _ := casbin.NewCachedEnforcer(m, adapter)
|
||||
m, err := model.NewModelFromFile(global.CONFIG.Casbin.ModelPath)
|
||||
if err != nil {
|
||||
global.LOG.Error(err.Error())
|
||||
panic(err)
|
||||
}
|
||||
e, err := casbin.NewCachedEnforcer(m, adapter)
|
||||
if err != nil {
|
||||
global.LOG.Error(err.Error())
|
||||
panic(err)
|
||||
}
|
||||
e.EnableCache(true)
|
||||
e.SetExpireTime(60 * 60)
|
||||
err = e.LoadPolicy()
|
||||
if err != nil {
|
||||
|
11
core/gorm.go
11
core/gorm.go
@@ -34,8 +34,9 @@ func MySQlConnect() *gorm.DB {
|
||||
|
||||
})
|
||||
} else {
|
||||
logfile, _ := os.OpenFile("/tmp/logs/mysql.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
|
||||
mysqlLogger = logger.New(
|
||||
log.New(os.Stdout, "\r\n", log.LstdFlags),
|
||||
log.New(logfile, "\r\n", log.LstdFlags),
|
||||
logger.Config{
|
||||
SlowThreshold: time.Second, //慢sql日志
|
||||
LogLevel: logger.Error, //级别
|
||||
@@ -46,12 +47,16 @@ func MySQlConnect() *gorm.DB {
|
||||
}
|
||||
|
||||
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
|
||||
Logger: mysqlLogger,
|
||||
Logger: mysqlLogger,
|
||||
PrepareStmt: true,
|
||||
})
|
||||
if err != nil {
|
||||
global.LOG.Fatalf(fmt.Sprintf("[%s] MySQL 连接失败", dsn))
|
||||
}
|
||||
sqlDB, _ := db.DB()
|
||||
sqlDB, err := db.DB()
|
||||
if err != nil {
|
||||
global.LOG.Fatalf(fmt.Sprintf("[%s] MySQL 获取DB失败", dsn))
|
||||
}
|
||||
sqlDB.SetMaxIdleConns(global.CONFIG.MySQL.MaxIdleConnes)
|
||||
sqlDB.SetMaxOpenConns(global.CONFIG.MySQL.MaxOpenConnes)
|
||||
sqlDB.SetConnMaxLifetime(time.Hour * 4) //连接最大复用时间
|
||||
|
@@ -1,80 +1,24 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/sirupsen/logrus"
|
||||
"os"
|
||||
"path"
|
||||
"schisandra-cloud-album/global"
|
||||
"schisandra-cloud-album/middleware"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
red = 31
|
||||
yellow = 33
|
||||
blue = 34
|
||||
gray = 37
|
||||
)
|
||||
|
||||
type LogFormatter struct{}
|
||||
|
||||
func (f *LogFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
||||
//根据不同的level显示不同的颜色
|
||||
var levelColor int
|
||||
switch entry.Level {
|
||||
case logrus.DebugLevel, logrus.TraceLevel:
|
||||
levelColor = gray
|
||||
case logrus.WarnLevel:
|
||||
levelColor = yellow
|
||||
case logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel:
|
||||
levelColor = red
|
||||
default:
|
||||
levelColor = blue
|
||||
}
|
||||
var b *bytes.Buffer
|
||||
if entry.Buffer != nil {
|
||||
b = entry.Buffer
|
||||
} else {
|
||||
b = &bytes.Buffer{}
|
||||
}
|
||||
log := global.CONFIG.Logger
|
||||
// 自定义日期格式
|
||||
timestamp := entry.Time.Format("2006-01-02 15:04:05")
|
||||
if entry.HasCaller() {
|
||||
//自定义文件路径
|
||||
funcVal := entry.Caller.Function
|
||||
fileVal := fmt.Sprintf("%s:%d", path.Base(entry.Caller.File), entry.Caller.Line)
|
||||
//自定义输出格式
|
||||
fmt.Fprintf(b, "%s[%s] \x1b[%dm[%s]\x1b[0m %s %s : %s\n", log.Prefix, timestamp, levelColor, entry.Level, fileVal, funcVal, entry.Message)
|
||||
} else {
|
||||
fmt.Fprintf(b, "%s[%s] \x1b[%dm[%s]\x1b[0m : %s\n", log.Prefix, timestamp, levelColor, entry.Level, entry.Message)
|
||||
}
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
func InitLogger() *logrus.Logger {
|
||||
newLog := logrus.New()
|
||||
newLog.SetOutput(os.Stdout) //设置输出类型
|
||||
newLog.SetReportCaller(global.CONFIG.Logger.ShowLine) //设置是否显示函数名和行号
|
||||
newLog.SetFormatter(&LogFormatter{}) //设置日志格式
|
||||
func InitLogger() {
|
||||
// 按照日期格式化输出
|
||||
mylog := middleware.NewDateLog(&middleware.DateLogConfig{
|
||||
Date: time.Now().Format("2006-01-02"),
|
||||
Path: global.CONFIG.Logger.Director,
|
||||
Name: global.CONFIG.Logger.LogName,
|
||||
})
|
||||
log := mylog.Init()
|
||||
level, err := logrus.ParseLevel(global.CONFIG.Logger.Level)
|
||||
if err != nil {
|
||||
level = logrus.InfoLevel
|
||||
}
|
||||
newLog.SetLevel(level) //设置日志级别
|
||||
global.LOG = newLog
|
||||
initDefaultLogger()
|
||||
return newLog
|
||||
}
|
||||
|
||||
func initDefaultLogger() {
|
||||
//全局日志
|
||||
logrus.SetOutput(os.Stdout) //设置输出类型
|
||||
logrus.SetReportCaller(global.CONFIG.Logger.ShowLine) //设置是否显示函数名和行号
|
||||
logrus.SetFormatter(&LogFormatter{}) //设置日志格式
|
||||
level, err := logrus.ParseLevel(global.CONFIG.Logger.Level)
|
||||
if err != nil {
|
||||
level = logrus.InfoLevel
|
||||
}
|
||||
logrus.SetLevel(level) //设置日志级别
|
||||
log.SetLevel(level) //设置日志级别
|
||||
global.LOG = log
|
||||
}
|
||||
|
@@ -13,10 +13,10 @@ func InitWechat() {
|
||||
Secret: global.CONFIG.Wechat.AppSecret,
|
||||
Token: global.CONFIG.Wechat.Token,
|
||||
AESKey: global.CONFIG.Wechat.AESKey,
|
||||
//Log: officialAccount.Log{
|
||||
// Level: "debug",
|
||||
// File: "./wechat.log",
|
||||
//},
|
||||
Log: officialAccount.Log{
|
||||
Level: "error",
|
||||
File: "./wechat.log",
|
||||
},
|
||||
ResponseType: os.Getenv("response_type"),
|
||||
HttpDebug: true,
|
||||
Debug: true,
|
||||
@@ -27,6 +27,7 @@ func InitWechat() {
|
||||
}),
|
||||
})
|
||||
if err != nil {
|
||||
global.LOG.Error(err.Error())
|
||||
panic(err)
|
||||
}
|
||||
global.Wechat = OfficialAccountApp
|
||||
|
76
docs/docs.go
76
docs/docs.go
@@ -15,6 +15,60 @@ const docTemplate = `{
|
||||
"host": "{{.Host}}",
|
||||
"basePath": "{{.BasePath}}",
|
||||
"paths": {
|
||||
"/api/auth/role/add_role_to_user": {
|
||||
"post": {
|
||||
"description": "给指定用户添加角色",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"角色"
|
||||
],
|
||||
"summary": "给指定用户添加角色",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "给指定用户添加角色",
|
||||
"name": "addRoleToUserRequestDto",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.AddRoleToUserRequestDto"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {}
|
||||
}
|
||||
},
|
||||
"/api/auth/role/create": {
|
||||
"post": {
|
||||
"description": "创建角色",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"角色"
|
||||
],
|
||||
"summary": "创建角色",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "角色信息",
|
||||
"name": "roleRequestDto",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.RoleRequestDto"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {}
|
||||
}
|
||||
},
|
||||
"/api/auth/user/List": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -735,6 +789,17 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.AddRoleToUserRequestDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"role_key": {
|
||||
"type": "string"
|
||||
},
|
||||
"uid": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.AddUserRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -779,6 +844,17 @@ const docTemplate = `{
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.RoleRequestDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"role_key": {
|
||||
"type": "string"
|
||||
},
|
||||
"role_name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
@@ -4,6 +4,60 @@
|
||||
"contact": {}
|
||||
},
|
||||
"paths": {
|
||||
"/api/auth/role/add_role_to_user": {
|
||||
"post": {
|
||||
"description": "给指定用户添加角色",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"角色"
|
||||
],
|
||||
"summary": "给指定用户添加角色",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "给指定用户添加角色",
|
||||
"name": "addRoleToUserRequestDto",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.AddRoleToUserRequestDto"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {}
|
||||
}
|
||||
},
|
||||
"/api/auth/role/create": {
|
||||
"post": {
|
||||
"description": "创建角色",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"角色"
|
||||
],
|
||||
"summary": "创建角色",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "角色信息",
|
||||
"name": "roleRequestDto",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.RoleRequestDto"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {}
|
||||
}
|
||||
},
|
||||
"/api/auth/user/List": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -724,6 +778,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.AddRoleToUserRequestDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"role_key": {
|
||||
"type": "string"
|
||||
},
|
||||
"uid": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.AddUserRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -768,6 +833,17 @@
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.RoleRequestDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"role_key": {
|
||||
"type": "string"
|
||||
},
|
||||
"role_name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,6 +8,13 @@ definitions:
|
||||
password:
|
||||
type: string
|
||||
type: object
|
||||
dto.AddRoleToUserRequestDto:
|
||||
properties:
|
||||
role_key:
|
||||
type: string
|
||||
uid:
|
||||
type: string
|
||||
type: object
|
||||
dto.AddUserRequest:
|
||||
properties:
|
||||
password:
|
||||
@@ -37,9 +44,52 @@ definitions:
|
||||
repassword:
|
||||
type: string
|
||||
type: object
|
||||
dto.RoleRequestDto:
|
||||
properties:
|
||||
role_key:
|
||||
type: string
|
||||
role_name:
|
||||
type: string
|
||||
type: object
|
||||
info:
|
||||
contact: {}
|
||||
paths:
|
||||
/api/auth/role/add_role_to_user:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 给指定用户添加角色
|
||||
parameters:
|
||||
- description: 给指定用户添加角色
|
||||
in: body
|
||||
name: addRoleToUserRequestDto
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.AddRoleToUserRequestDto'
|
||||
produces:
|
||||
- application/json
|
||||
responses: {}
|
||||
summary: 给指定用户添加角色
|
||||
tags:
|
||||
- 角色
|
||||
/api/auth/role/create:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 创建角色
|
||||
parameters:
|
||||
- description: 角色信息
|
||||
in: body
|
||||
name: roleRequestDto
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.RoleRequestDto'
|
||||
produces:
|
||||
- application/json
|
||||
responses: {}
|
||||
summary: 创建角色
|
||||
tags:
|
||||
- 角色
|
||||
/api/auth/user/List:
|
||||
get:
|
||||
responses:
|
||||
|
8
go.mod
8
go.mod
@@ -6,12 +6,16 @@ require (
|
||||
github.com/ArtisanCloud/PowerLibs/v3 v3.2.5
|
||||
github.com/ArtisanCloud/PowerWeChat/v3 v3.2.38
|
||||
github.com/BurntSushi/toml v1.3.2
|
||||
github.com/casbin/casbin/v2 v2.98.0
|
||||
github.com/casbin/gorm-adapter/v3 v3.28.0
|
||||
github.com/gin-contrib/cors v1.7.2
|
||||
github.com/gin-contrib/i18n v1.1.3
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/juju/ratelimit v1.0.2
|
||||
github.com/lxzan/gws v1.8.5
|
||||
github.com/pkg6/go-sms v0.1.2
|
||||
github.com/redis/go-redis/v9 v9.6.1
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
@@ -37,8 +41,6 @@ require (
|
||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||
github.com/bytedance/sonic v1.12.0 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.0 // indirect
|
||||
github.com/casbin/casbin/v2 v2.98.0 // indirect
|
||||
github.com/casbin/gorm-adapter/v3 v3.28.0 // indirect
|
||||
github.com/casbin/govaluate v1.2.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
||||
@@ -71,11 +73,9 @@ require (
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/juju/ratelimit v1.0.2 // indirect
|
||||
github.com/klauspost/compress v1.17.5 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/lxzan/gws v1.8.5 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/microsoft/go-mssqldb v1.6.0 // indirect
|
||||
|
22
go.sum
22
go.sum
@@ -9,14 +9,20 @@ github.com/ArtisanCloud/PowerWeChat/v3 v3.2.38/go.mod h1:9CbKc6nODhoM8TVjoXqujrA
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0/go.mod h1:ON4tFdPTwRcgWEaVDrN3584Ef+b7GgSJaXxe5fW9t4M=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1 h1:/iHxaJhsFr0+xVFfbMr5vxz848jyiWuIEDhYq3y5odY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.2.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0 h1:yfJe15aSwEQ6Oo6J+gdfdulPNoZ3TEhmbhLIoxZcA+U=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0/go.mod h1:Q28U+75mpCaSCDowNEmhIo/rmgdkqmkmzI7N6TGR4UY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0 h1:T028gtTPiYt/RMUfs8nVsAL7FDQrfLlrm/NnRG/zcC4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0/go.mod h1:cw4zVQgBby0Z5f2v0itn6se2dDP17nTjbZFXW5uPyHA=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0 h1:HCc0+LpPfpCKs6LGGLAhwBARt9632unrVcI6i8s/8os=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
@@ -105,10 +111,13 @@ github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei
|
||||
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
@@ -151,9 +160,12 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
|
||||
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lxzan/gws v1.8.5 h1:6x+wW3EHtoGFNeCtZP1OVZ1IHrpZZzDaEjQGg1lUJqU=
|
||||
github.com/lxzan/gws v1.8.5/go.mod h1:FcGeRMB7HwGuTvMLR24ku0Zx0p6RXqeKASeMc4VYgi4=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
@@ -163,8 +175,6 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
|
||||
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE=
|
||||
github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ=
|
||||
github.com/microsoft/go-mssqldb v1.6.0 h1:mM3gYdVwEPFrlg/Dvr2DNVEgYFG7L42l+dGc67NNNpc=
|
||||
github.com/microsoft/go-mssqldb v1.6.0/go.mod h1:00mDtPbeQCRGC1HwOOR5K/gr30P1NcEG0vx6Kbv2aJU=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@@ -180,6 +190,7 @@ github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaR
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@@ -194,9 +205,8 @@ github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJ
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230126093431-47fa9a501578 h1:VstopitMQi3hZP0fzvnsLmzXZdQGc4bEcgu24cp+d4M=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230126093431-47fa9a501578/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
@@ -337,14 +347,10 @@ gorm.io/datatypes v1.2.1/go.mod h1:hYK6OTb/1x+m96PgoZZq10UXJ6RvEBb9kRDQ2yyhzGs=
|
||||
gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
|
||||
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
|
||||
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
|
||||
gorm.io/driver/postgres v1.5.0 h1:u2FXTy14l45qc3UeCJ7QaAXZmZfDDv0YrthvmRq1l0U=
|
||||
gorm.io/driver/postgres v1.5.0/go.mod h1:FUZXzO+5Uqg5zzwzv4KK49R8lvGIyscBOqYrtI1Ce9A=
|
||||
gorm.io/driver/postgres v1.5.7 h1:8ptbNJTDbEmhdr62uReG5BGkdQyeasu/FZHxI0IMGnM=
|
||||
gorm.io/driver/postgres v1.5.7/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA=
|
||||
gorm.io/driver/sqlite v1.5.0 h1:zKYbzRCpBrT1bNijRnxLDJWPjVfImGEn0lSnUY5gZ+c=
|
||||
gorm.io/driver/sqlite v1.5.0/go.mod h1:kDMDfntV9u/vuMmz8APHtHF0b4nyBB7sfCieC6G8k8I=
|
||||
gorm.io/driver/sqlserver v1.4.1 h1:t4r4r6Jam5E6ejqP7N82qAJIJAht27EGT41HyPfXRw0=
|
||||
gorm.io/driver/sqlserver v1.4.1/go.mod h1:DJ4P+MeZbc5rvY58PnmN1Lnyvb5gw5NPzGshHDnJLig=
|
||||
gorm.io/driver/sqlserver v1.5.3 h1:rjupPS4PVw+rjJkfvr8jn2lJ8BMhT4UW5FwuJY0P3Z0=
|
||||
gorm.io/driver/sqlserver v1.5.3/go.mod h1:B+CZ0/7oFJ6tAlefsKoyxdgDCXJKSgwS2bMOQZT0I00=
|
||||
gorm.io/gen v0.3.26 h1:sFf1j7vNStimPRRAtH4zz5NiHM+1dr6eA9aaRdplyhY=
|
||||
|
1
main.go
1
main.go
@@ -8,6 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// 初始化配置
|
||||
core.InitConfig() // 读取配置文件
|
||||
core.InitLogger() // 初始化日志
|
||||
|
157
middleware/logger_date.go
Normal file
157
middleware/logger_date.go
Normal file
@@ -0,0 +1,157 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"schisandra-cloud-album/global"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var (
|
||||
ccRed = 1
|
||||
ccYellow = 3
|
||||
ccBlue = 4
|
||||
ccCyan = 6
|
||||
ccGray = 7
|
||||
)
|
||||
|
||||
type LogConsoleFormatter struct{}
|
||||
|
||||
func (s *LogConsoleFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
||||
timestamp := time.Now().Local().Format("2006-01-02 15:04:05")
|
||||
var color int
|
||||
switch entry.Level {
|
||||
|
||||
case logrus.ErrorLevel:
|
||||
color = ccRed
|
||||
case logrus.WarnLevel:
|
||||
color = ccYellow
|
||||
case logrus.InfoLevel:
|
||||
color = ccBlue
|
||||
case logrus.DebugLevel:
|
||||
color = ccCyan
|
||||
default:
|
||||
color = ccGray
|
||||
}
|
||||
// 设置 buffer 缓冲区
|
||||
var b *bytes.Buffer
|
||||
if entry.Buffer == nil {
|
||||
b = &bytes.Buffer{}
|
||||
} else {
|
||||
b = entry.Buffer
|
||||
}
|
||||
fileVal := fmt.Sprintf("%s:%d", filepath.Base(entry.Caller.File), entry.Caller.Line)
|
||||
fmt.Fprintf(b, "[%s] \033[3%dm[%s]\033[0m [%s] %s %s\n", global.CONFIG.Logger.Prefix, color, entry.Level, timestamp, fileVal, entry.Message)
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
type LogFileFormatter struct{}
|
||||
|
||||
func (s *LogFileFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
||||
timestamp := time.Now().Local().Format("2006-01-02 15:04:05")
|
||||
var file string
|
||||
var length int
|
||||
if entry.Caller != nil {
|
||||
file = filepath.Base(entry.Caller.File)
|
||||
length = entry.Caller.Line
|
||||
}
|
||||
msg := fmt.Sprintf("[%s] %s [%s:%d] %s\n", strings.ToUpper(entry.Level.String()), timestamp, file, length, entry.Message)
|
||||
return []byte(msg), nil
|
||||
}
|
||||
|
||||
type ConsoleHook struct {
|
||||
formatter logrus.Formatter
|
||||
}
|
||||
|
||||
func (hook *ConsoleHook) Levels() []logrus.Level {
|
||||
return logrus.AllLevels
|
||||
}
|
||||
func (hook *ConsoleHook) Fire(entry *logrus.Entry) error {
|
||||
originalFormatter := entry.Logger.Formatter
|
||||
entry.Logger.Formatter = hook.formatter
|
||||
defer func() { entry.Logger.Formatter = originalFormatter }()
|
||||
line, err := entry.Logger.Formatter.Format(entry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = os.Stdout.Write(line)
|
||||
return err
|
||||
}
|
||||
|
||||
type FileHook struct {
|
||||
formatter logrus.Formatter
|
||||
file *os.File
|
||||
}
|
||||
|
||||
func (hook *FileHook) Levels() []logrus.Level {
|
||||
return logrus.AllLevels
|
||||
}
|
||||
|
||||
func (hook *FileHook) Fire(entry *logrus.Entry) error {
|
||||
originalFormatter := entry.Logger.Formatter
|
||||
entry.Logger.Formatter = hook.formatter
|
||||
defer func() { entry.Logger.Formatter = originalFormatter }()
|
||||
line, err := entry.Logger.Formatter.Format(entry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = hook.file.Write(line)
|
||||
return err
|
||||
}
|
||||
|
||||
type DateLogConfig struct {
|
||||
Date string
|
||||
Path string
|
||||
Name string
|
||||
}
|
||||
|
||||
func NewDateLog(d *DateLogConfig) *DateLogConfig {
|
||||
return &DateLogConfig{
|
||||
Date: d.Date,
|
||||
Path: d.Path,
|
||||
Name: d.Name,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DateLogConfig) Init() *logrus.Logger {
|
||||
// 实例化 logrus
|
||||
log := logrus.New()
|
||||
// 设置是否输出文件名和行号信息
|
||||
log.SetReportCaller(global.CONFIG.Logger.ShowLine)
|
||||
// 将 logrus 的默认输出丢弃,确保日志只通过 hooks 输出
|
||||
log.SetOutput(io.Discard)
|
||||
|
||||
// 控制台输出的 hook
|
||||
consoleHook := &ConsoleHook{
|
||||
formatter: &LogConsoleFormatter{},
|
||||
}
|
||||
// 添加控制台输出的 hook
|
||||
log.AddHook(consoleHook)
|
||||
|
||||
// 文件路径
|
||||
filename := fmt.Sprintf("%s/%s/%s.log", d.Path, d.Date, d.Name)
|
||||
// 创建目录
|
||||
if err := os.MkdirAll(fmt.Sprintf("%s/%s", d.Path, d.Date), os.ModePerm); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// 打开文件,如果文件不存在,则创建文件
|
||||
file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// 文件输出的 hook
|
||||
fileHook := &FileHook{
|
||||
formatter: &LogFileFormatter{},
|
||||
file: file,
|
||||
}
|
||||
// 添加文件输出的 hook
|
||||
log.AddHook(fileHook)
|
||||
return log
|
||||
}
|
116
middleware/logger_level.go
Normal file
116
middleware/logger_level.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
allLog = "all"
|
||||
errLog = "err"
|
||||
warnLog = "warn"
|
||||
infoLog = "info"
|
||||
debugLog = "debug"
|
||||
)
|
||||
|
||||
type LevelFormatter struct{}
|
||||
|
||||
func (l *LevelFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
||||
timestamp := time.Now().Local().Format("2006-01-02 15:04:05")
|
||||
var file string
|
||||
var len int
|
||||
if entry.Caller != nil {
|
||||
file = filepath.Base(entry.Caller.File)
|
||||
len = entry.Caller.Line
|
||||
}
|
||||
msg := fmt.Sprintf("[%s] %s [%s:%d] %s\n", strings.ToUpper(entry.Level.String()), timestamp, file, len, entry.Message)
|
||||
return []byte(msg), nil
|
||||
}
|
||||
|
||||
type LevelConfig struct {
|
||||
Date string
|
||||
Name string
|
||||
Path string
|
||||
}
|
||||
|
||||
func NewLevelLog(d *LevelConfig) *LevelConfig {
|
||||
return &LevelConfig{
|
||||
Date: d.Date,
|
||||
Path: d.Path,
|
||||
Name: d.Name,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LevelConfig) Init() *logrus.Logger {
|
||||
log := logrus.New()
|
||||
log.SetReportCaller(true)
|
||||
log.SetOutput(io.Discard)
|
||||
|
||||
err := os.MkdirAll(fmt.Sprintf("%s/%s", l.Path, l.Date), os.ModePerm)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
allFile, _ := os.OpenFile(fmt.Sprintf("%s/%s/%s-%s.log", l.Path, l.Date, l.Name, allLog), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
|
||||
errFile, _ := os.OpenFile(fmt.Sprintf("%s/%s/%s-%s.log", l.Path, l.Date, l.Name, errLog), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
|
||||
warnFile, _ := os.OpenFile(fmt.Sprintf("%s/%s/%s-%s.log", l.Path, l.Date, l.Name, warnLog), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
|
||||
infoFile, _ := os.OpenFile(fmt.Sprintf("%s/%s/%s-%s.log", l.Path, l.Date, l.Name, infoLog), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
|
||||
debugFile, _ := os.OpenFile(fmt.Sprintf("%s/%s/%s-%s.log", l.Path, l.Date, l.Name, debugLog), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
|
||||
|
||||
fileHook := &LevelHook{
|
||||
formatter: &LevelFormatter{},
|
||||
file: allFile,
|
||||
errFile: errFile,
|
||||
warnFile: warnFile,
|
||||
infoFile: infoFile,
|
||||
debugFile: debugFile,
|
||||
}
|
||||
|
||||
log.AddHook(fileHook)
|
||||
return log
|
||||
}
|
||||
|
||||
type LevelHook struct {
|
||||
formatter logrus.Formatter
|
||||
file *os.File
|
||||
errFile *os.File
|
||||
warnFile *os.File
|
||||
infoFile *os.File
|
||||
debugFile *os.File
|
||||
}
|
||||
|
||||
func (l *LevelHook) Levels() []logrus.Level {
|
||||
return logrus.AllLevels
|
||||
}
|
||||
|
||||
func (l *LevelHook) Fire(entry *logrus.Entry) error {
|
||||
originalFormatter := entry.Logger.Formatter
|
||||
entry.Logger.Formatter = l.formatter
|
||||
defer func() { entry.Logger.Formatter = originalFormatter }()
|
||||
line, err := entry.Logger.Formatter.Format(entry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = l.file.Write(line)
|
||||
|
||||
switch entry.Level {
|
||||
case logrus.ErrorLevel:
|
||||
_, err = l.errFile.Write(line)
|
||||
case logrus.WarnLevel:
|
||||
_, err = l.warnFile.Write(line)
|
||||
case logrus.InfoLevel:
|
||||
_, err = l.infoFile.Write(line)
|
||||
case logrus.DebugLevel:
|
||||
_, err = l.debugFile.Write(line)
|
||||
default:
|
||||
panic("unhandled default case")
|
||||
}
|
||||
return err
|
||||
}
|
@@ -1,24 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const TableNameScaAuthRolePermission = "sca_auth_role_permission"
|
||||
|
||||
// ScaAuthRolePermission 角色-权限映射表
|
||||
type ScaAuthRolePermission struct {
|
||||
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;comment:主键ID" json:"id"` // 主键ID
|
||||
RoleID int64 `gorm:"column:role_id;type:bigint(20);not null;comment:角色ID" json:"role_id"` // 角色ID
|
||||
PermissionID int64 `gorm:"column:permission_id;type:bigint(20);not null;comment:权限ID" json:"permission_id"` // 权限ID
|
||||
CreatedBy *string `gorm:"column:created_by;type:varchar(32);comment:创建人" json:"created_by"` // 创建人
|
||||
CreatedTime *time.Time `gorm:"column:created_time;type:datetime;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_time"` // 创建时间
|
||||
UpdateBy *string `gorm:"column:update_by;type:varchar(32);comment:更新人" json:"update_by"` // 更新人
|
||||
UpdateTime *time.Time `gorm:"column:update_time;type:datetime;default:CURRENT_TIMESTAMP;comment:更新时间" json:"update_time"` // 更新时间
|
||||
Deleted *int64 `gorm:"column:deleted;type:int(11);comment:是否删除" json:"deleted"` // 是否删除
|
||||
}
|
||||
|
||||
// TableName ScaAuthRolePermission's table name
|
||||
func (*ScaAuthRolePermission) TableName() string {
|
||||
return TableNameScaAuthRolePermission
|
||||
}
|
@@ -1,24 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const TableNameScaAuthUserRole = "sca_auth_user_role"
|
||||
|
||||
// ScaAuthUserRole 用户-角色映射表
|
||||
type ScaAuthUserRole struct {
|
||||
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;comment:主键ID" json:"id"` // 主键ID
|
||||
UserID string `gorm:"column:user_id;type:varchar(255);not null;comment:用户ID" json:"user_id"` // 用户ID
|
||||
RoleID int64 `gorm:"column:role_id;type:bigint(20);not null;comment:角色ID" json:"role_id"` // 角色ID
|
||||
CreatedBy *string `gorm:"column:created_by;type:varchar(32);comment:创建人" json:"created_by"` // 创建人
|
||||
CreatedTime *time.Time `gorm:"column:created_time;type:datetime;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_time"` // 创建时间
|
||||
UpdateBy *string `gorm:"column:update_by;type:varchar(32);comment:更新人" json:"update_by"` // 更新人
|
||||
UpdateTime *time.Time `gorm:"column:update_time;type:datetime;default:CURRENT_TIMESTAMP;comment:更新时间" json:"update_time"` // 更新时间
|
||||
Deleted *int64 `gorm:"column:deleted;type:int(11);comment:是否删除" json:"deleted"` // 是否删除
|
||||
}
|
||||
|
||||
// TableName ScaAuthUserRole's table name
|
||||
func (*ScaAuthUserRole) TableName() string {
|
||||
return TableNameScaAuthUserRole
|
||||
}
|
@@ -9,7 +9,7 @@ const TableNameScaAuthUserSocial = "sca_auth_user_social"
|
||||
// ScaAuthUserSocial 社会用户信息表
|
||||
type ScaAuthUserSocial struct {
|
||||
ID int64 `gorm:"column:id;type:bigint(20);primaryKey;comment:主键ID" json:"id"` // 主键ID
|
||||
UserID *int64 `gorm:"column:user_id;type:bigint(20);not null;comment:用户ID" json:"user_id"` // 用户ID
|
||||
UserID *string `gorm:"column:user_id;type:varchar(255);not null;comment:用户ID" json:"user_id"` // 用户ID
|
||||
UUID *string `gorm:"column:uuid;type:varchar(255);comment:第三方系统的唯一ID" json:"uuid"` // 第三方系统的唯一ID
|
||||
Source *string `gorm:"column:source;type:varchar(255);comment:第三方用户来源" json:"source"` // 第三方用户来源
|
||||
AccessToken *string `gorm:"column:access_token;type:varchar(255);comment:用户的授权令牌" json:"access_token"` // 用户的授权令牌
|
||||
|
@@ -14,8 +14,8 @@ func OauthRouter(router *gin.RouterGroup) {
|
||||
{
|
||||
wechatRouter.GET("/generate_client_id", oauth.GenerateClientId)
|
||||
wechatRouter.GET("/get_temp_qrcode", oauth.GetTempQrCode)
|
||||
wechatRouter.GET("/callback", oauth.CallbackVerify)
|
||||
//wechatRouter.POST("/callback", oauth.CallbackNotify)
|
||||
//wechatRouter.GET("/callback", oauth.CallbackVerify)
|
||||
wechatRouter.POST("/callback", oauth.CallbackNotify)
|
||||
}
|
||||
githubRouter := group.Group("/github")
|
||||
{
|
||||
|
16
router/modules/role_router.go
Normal file
16
router/modules/role_router.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package modules
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"schisandra-cloud-album/api"
|
||||
"schisandra-cloud-album/middleware"
|
||||
)
|
||||
|
||||
var roleApi = api.Api.RoleApi
|
||||
|
||||
func RoleRouter(router *gin.RouterGroup) {
|
||||
group := router.Group("/auth")
|
||||
group.Use(middleware.JWTAuthMiddleware())
|
||||
group.POST("/role/create", roleApi.CreateRole)
|
||||
group.POST("/role/add_role_to_user", roleApi.AddRoleToUser)
|
||||
}
|
@@ -12,14 +12,21 @@ import (
|
||||
func InitRouter() *gin.Engine {
|
||||
gin.SetMode(global.CONFIG.System.Env)
|
||||
router := gin.Default()
|
||||
err := router.SetTrustedProxies([]string{"127.0.0.1"})
|
||||
err := router.SetTrustedProxies([]string{global.CONFIG.System.Ip})
|
||||
if err != nil {
|
||||
global.LOG.Error(err)
|
||||
return nil
|
||||
}
|
||||
router.Use(middleware.RateLimitMiddleware(time.Millisecond*100, 20)) // 限流中间件
|
||||
publicGroup := router.Group("api")
|
||||
// 跨域设置
|
||||
publicGroup.Use(cors.Default()).Use(middleware.RateLimitMiddleware(time.Millisecond*100, 20))
|
||||
publicGroup.Use(cors.New(cors.Config{
|
||||
AllowOrigins: []string{global.CONFIG.System.Web},
|
||||
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"},
|
||||
AllowHeaders: []string{"Origin", "Content-Length", "Content-Type", "Authorization", "X-CSRF-Token", "Accept-Language"},
|
||||
AllowCredentials: true,
|
||||
MaxAge: 12 * time.Hour,
|
||||
}))
|
||||
// 国际化设置
|
||||
publicGroup.Use(middleware.I18n())
|
||||
|
||||
@@ -29,5 +36,6 @@ func InitRouter() *gin.Engine {
|
||||
modules.SmsRouter(publicGroup) // 注册短信验证码路由
|
||||
modules.OauthRouter(publicGroup) // 注册oauth路由
|
||||
modules.WebsocketRouter(publicGroup) // 注册websocket路由
|
||||
modules.RoleRouter(publicGroup) // 注册角色路由
|
||||
return router
|
||||
}
|
||||
|
@@ -13,3 +13,11 @@ func (PermissionService) GetPermissionsByIds(ids []int64) ([]model.ScaAuthPermis
|
||||
}
|
||||
return permissions, nil
|
||||
}
|
||||
|
||||
// CreatePermissions 批量创建权限
|
||||
func (PermissionService) CreatePermissions(permissions []model.ScaAuthPermission) error {
|
||||
if err := global.DB.Model(&model.ScaAuthPermission{}).CreateInBatches(&permissions, len(permissions)).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -1,3 +0,0 @@
|
||||
package role_permission_service
|
||||
|
||||
type RolePermissionService struct{}
|
@@ -1,17 +0,0 @@
|
||||
package role_permission_service
|
||||
|
||||
import (
|
||||
"schisandra-cloud-album/global"
|
||||
"schisandra-cloud-album/model"
|
||||
)
|
||||
|
||||
// QueryPermissionIdsByRoleId 通过角色ID列表查询权限ID列表
|
||||
func (RolePermissionService) QueryPermissionIdsByRoleId(roleIds []*int64) []int64 {
|
||||
var permissionIds []int64
|
||||
rolePermission := model.ScaAuthRolePermission{}
|
||||
if err := global.DB.Model(&rolePermission).Where("role_id IN ?", roleIds).Pluck("permission_id", &permissionIds).Error; err != nil {
|
||||
global.LOG.Error(err)
|
||||
return nil
|
||||
}
|
||||
return permissionIds
|
||||
}
|
@@ -13,3 +13,11 @@ func (RoleService) GetRoleListByIds(id []*int64) ([]model.ScaAuthRole, error) {
|
||||
}
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
// AddRole 新增角色
|
||||
func (RoleService) AddRole(role model.ScaAuthRole) error {
|
||||
if err := global.DB.Create(&role).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -2,21 +2,17 @@ package service
|
||||
|
||||
import (
|
||||
"schisandra-cloud-album/service/permission_service"
|
||||
"schisandra-cloud-album/service/role_permission_service"
|
||||
"schisandra-cloud-album/service/role_service"
|
||||
"schisandra-cloud-album/service/user_role_service"
|
||||
"schisandra-cloud-album/service/user_service"
|
||||
"schisandra-cloud-album/service/user_social_service"
|
||||
)
|
||||
|
||||
// Services 统一导出的service
|
||||
type Services struct {
|
||||
UserService user_service.UserService
|
||||
RoleService role_service.RoleService
|
||||
UserRoleService user_role_service.UserRoleService
|
||||
RolePermissionService role_permission_service.RolePermissionService
|
||||
PermissionService permission_service.PermissionService
|
||||
UserSocialService user_social_service.UserSocialService
|
||||
UserService user_service.UserService
|
||||
RoleService role_service.RoleService
|
||||
PermissionService permission_service.PermissionService
|
||||
UserSocialService user_social_service.UserSocialService
|
||||
}
|
||||
|
||||
// Service new函数实例化,实例化完成后会返回结构体地指针类型
|
||||
|
@@ -1,3 +0,0 @@
|
||||
package user_role_service
|
||||
|
||||
type UserRoleService struct{}
|
@@ -1,32 +0,0 @@
|
||||
package user_role_service
|
||||
|
||||
import (
|
||||
"schisandra-cloud-album/global"
|
||||
"schisandra-cloud-album/model"
|
||||
)
|
||||
|
||||
// GetUserRoleIdsByUserId 通过用户ID获取用户角色ID列表
|
||||
func (UserRoleService) GetUserRoleIdsByUserId(userId int64) ([]*int64, error) {
|
||||
var roleIds []*int64
|
||||
if err := global.DB.Table("sca_auth_user_role").Where("user_id = ? and deleted = 0 ", userId).Pluck("role_id", &roleIds).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return roleIds, nil
|
||||
}
|
||||
|
||||
// AddUserRole 新增用户角色
|
||||
func (UserRoleService) AddUserRole(userRole model.ScaAuthUserRole) error {
|
||||
if err := global.DB.Create(&userRole).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAllUserRoles 返回所有用户的角色列表
|
||||
func (UserRoleService) GetAllUserRoles() ([]*model.ScaAuthUserRole, error) {
|
||||
var userRoles []*model.ScaAuthUserRole
|
||||
if err := global.DB.Table("sca_auth_user_role").Where("deleted = 0").Find(&userRoles).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return userRoles, nil
|
||||
}
|
10
utils/jwt.go
10
utils/jwt.go
@@ -9,14 +9,12 @@ import (
|
||||
)
|
||||
|
||||
type RefreshJWTPayload struct {
|
||||
UserID *string `json:"user_id"`
|
||||
RoleID []*int64 `json:"role_id"`
|
||||
Type *string `json:"type" default:"refresh"`
|
||||
UserID *string `json:"user_id"`
|
||||
Type *string `json:"type" default:"refresh"`
|
||||
}
|
||||
type AccessJWTPayload struct {
|
||||
UserID *string `json:"user_id"`
|
||||
RoleID []*int64 `json:"role_id"`
|
||||
Type *string `json:"type" default:"access"`
|
||||
UserID *string `json:"user_id"`
|
||||
Type *string `json:"type" default:"access"`
|
||||
}
|
||||
type AccessJWTClaims struct {
|
||||
AccessJWTPayload
|
||||
|
Reference in New Issue
Block a user