🎨 complete SMS login function
This commit is contained in:
51
.air.toml
Normal file
51
.air.toml
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
root = "."
|
||||||
|
testdata_dir = "testdata"
|
||||||
|
tmp_dir = "tmp"
|
||||||
|
|
||||||
|
[build]
|
||||||
|
args_bin = []
|
||||||
|
bin = "tmp\\main.exe"
|
||||||
|
cmd = "go build -o ./tmp/main.exe ."
|
||||||
|
delay = 1000
|
||||||
|
exclude_dir = ["assets", "tmp", "vendor", "testdata", ".idea", ".git"]
|
||||||
|
exclude_file = []
|
||||||
|
exclude_regex = ["_test.go"]
|
||||||
|
exclude_unchanged = false
|
||||||
|
follow_symlink = false
|
||||||
|
full_bin = ""
|
||||||
|
include_dir = []
|
||||||
|
include_ext = ["go", "tpl", "tmpl", "html"]
|
||||||
|
include_file = []
|
||||||
|
kill_delay = "0s"
|
||||||
|
log = "build-errors.log"
|
||||||
|
poll = false
|
||||||
|
poll_interval = 0
|
||||||
|
post_cmd = []
|
||||||
|
pre_cmd = []
|
||||||
|
rerun = false
|
||||||
|
rerun_delay = 500
|
||||||
|
send_interrupt = false
|
||||||
|
stop_on_error = false
|
||||||
|
|
||||||
|
[color]
|
||||||
|
app = ""
|
||||||
|
build = "yellow"
|
||||||
|
main = "magenta"
|
||||||
|
runner = "green"
|
||||||
|
watcher = "cyan"
|
||||||
|
|
||||||
|
[log]
|
||||||
|
main_only = false
|
||||||
|
time = false
|
||||||
|
|
||||||
|
[misc]
|
||||||
|
clean_on_exit = false
|
||||||
|
|
||||||
|
[proxy]
|
||||||
|
app_port = 0
|
||||||
|
enabled = false
|
||||||
|
proxy_port = 0
|
||||||
|
|
||||||
|
[screen]
|
||||||
|
clear_on_rebuild = false
|
||||||
|
keep_scroll = true
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -9,6 +9,7 @@
|
|||||||
*.so
|
*.so
|
||||||
*.dylib
|
*.dylib
|
||||||
.air.toml
|
.air.toml
|
||||||
|
test
|
||||||
|
|
||||||
# Test binary, built with `go test -c`
|
# Test binary, built with `go test -c`
|
||||||
*.test
|
*.test
|
||||||
|
@@ -1,14 +1,14 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"schisandra-cloud-album/api/auth_api"
|
|
||||||
"schisandra-cloud-album/api/captcha_api"
|
"schisandra-cloud-album/api/captcha_api"
|
||||||
"schisandra-cloud-album/api/sms_api"
|
"schisandra-cloud-album/api/sms_api"
|
||||||
|
"schisandra-cloud-album/api/user_api"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Apis 统一导出的api
|
// Apis 统一导出的api
|
||||||
type Apis struct {
|
type Apis struct {
|
||||||
AuthApi auth_api.AuthAPI
|
UserApi user_api.UserAPI
|
||||||
CaptchaApi captcha_api.CaptchaAPI
|
CaptchaApi captcha_api.CaptchaAPI
|
||||||
SmsApi sms_api.SmsAPI
|
SmsApi sms_api.SmsAPI
|
||||||
}
|
}
|
||||||
|
@@ -1,3 +0,0 @@
|
|||||||
package auth_api
|
|
||||||
|
|
||||||
type AuthAPI struct{}
|
|
@@ -1,159 +0,0 @@
|
|||||||
package auth_api
|
|
||||||
|
|
||||||
import (
|
|
||||||
ginI18n "github.com/gin-contrib/i18n"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"reflect"
|
|
||||||
"schisandra-cloud-album/common/result"
|
|
||||||
"schisandra-cloud-album/model"
|
|
||||||
"schisandra-cloud-album/service"
|
|
||||||
"schisandra-cloud-album/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
var authService = service.Service.AuthService
|
|
||||||
|
|
||||||
// GetUserList
|
|
||||||
// @Summary 获取所有用户列表
|
|
||||||
// @Tags 鉴权模块
|
|
||||||
// @Success 200 {string} json
|
|
||||||
// @Router /api/auth/user/List [get]
|
|
||||||
func (AuthAPI) GetUserList(c *gin.Context) {
|
|
||||||
userList := authService.GetUserList()
|
|
||||||
result.OkWithData(userList, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryUserByUsername
|
|
||||||
// @Summary 根据用户名查询用户
|
|
||||||
// @Tags 鉴权模块
|
|
||||||
// @Param username query string true "用户名"
|
|
||||||
// @Success 200 {string} json
|
|
||||||
// @Router /api/auth/user/query_by_username [get]
|
|
||||||
func (AuthAPI) QueryUserByUsername(c *gin.Context) {
|
|
||||||
username := c.Query("username")
|
|
||||||
user := authService.QueryUserByUsername(username)
|
|
||||||
if reflect.DeepEqual(user, model.ScaAuthUser{}) {
|
|
||||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "NotFoundUser"), c)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
result.OkWithData(user, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryUserByUuid
|
|
||||||
// @Summary 根据uuid查询用户
|
|
||||||
// @Tags 鉴权模块
|
|
||||||
// @Param uuid query string true "用户uuid"
|
|
||||||
// @Success 200 {string} json
|
|
||||||
// @Router /api/auth/user/query_by_uuid [get]
|
|
||||||
func (AuthAPI) QueryUserByUuid(c *gin.Context) {
|
|
||||||
uuid := c.Query("uuid")
|
|
||||||
user := authService.QueryUserByUuid(uuid)
|
|
||||||
if reflect.DeepEqual(user, model.ScaAuthUser{}) {
|
|
||||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "NotFoundUser"), c)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
result.OkWithData(user, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteUser 删除用户
|
|
||||||
// @Summary 删除用户
|
|
||||||
// @Tags 鉴权模块
|
|
||||||
// @Param uuid query string true "用户uuid"
|
|
||||||
// @Success 200 {string} json
|
|
||||||
// @Router /api/auth/user/delete [delete]
|
|
||||||
func (AuthAPI) DeleteUser(c *gin.Context) {
|
|
||||||
uuid := c.Query("uuid")
|
|
||||||
err := authService.DeleteUser(uuid)
|
|
||||||
if err != nil {
|
|
||||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "DeletedFailed"), c)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
result.OkWithMessage(ginI18n.MustGetMessage(c, "DeletedSuccess"), c)
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryUserByPhone 根据手机号查询用户
|
|
||||||
// @Summary 根据手机号查询用户
|
|
||||||
// @Tags 鉴权模块
|
|
||||||
// @Param phone query string true "手机号"
|
|
||||||
// @Success 200 {string} json
|
|
||||||
// @Router /api/auth/user/query_by_phone [get]
|
|
||||||
func (AuthAPI) QueryUserByPhone(c *gin.Context) {
|
|
||||||
phone := c.Query("phone")
|
|
||||||
user := authService.QueryUserByPhone(phone)
|
|
||||||
if reflect.DeepEqual(user, model.ScaAuthUser{}) {
|
|
||||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "NotFoundUser"), c)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
result.OkWithData(user, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AccountLogin 账号登录
|
|
||||||
// @Summary 账号登录
|
|
||||||
// @Tags 鉴权模块
|
|
||||||
// @Param account query string true "账号"
|
|
||||||
// @Param password query string true "密码"
|
|
||||||
// @Success 200 {string} json
|
|
||||||
// @Router /api/auth/user/login [post]
|
|
||||||
func (AuthAPI) AccountLogin(c *gin.Context) {
|
|
||||||
account := c.PostForm("account")
|
|
||||||
password := c.PostForm("password")
|
|
||||||
isPhone := utils.IsPhone(account)
|
|
||||||
if isPhone {
|
|
||||||
user := authService.QueryUserByPhone(account)
|
|
||||||
if reflect.DeepEqual(user, model.ScaAuthUser{}) {
|
|
||||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "PhoneNotRegister"), c)
|
|
||||||
} else {
|
|
||||||
verify := utils.Verify(password, *user.Password)
|
|
||||||
if verify {
|
|
||||||
result.OkWithData(user, c)
|
|
||||||
} else {
|
|
||||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "PasswordError"), c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
isEmail := utils.IsEmail(account)
|
|
||||||
if isEmail {
|
|
||||||
user := authService.QueryUserByEmail(account)
|
|
||||||
if reflect.DeepEqual(user, model.ScaAuthUser{}) {
|
|
||||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "EmailNotRegister"), c)
|
|
||||||
} else {
|
|
||||||
verify := utils.Verify(password, *user.Password)
|
|
||||||
if verify {
|
|
||||||
result.OkWithData(user, c)
|
|
||||||
} else {
|
|
||||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "PasswordError"), c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
isUsername := utils.IsUsername(account)
|
|
||||||
if isUsername {
|
|
||||||
user := authService.QueryUserByUsername(account)
|
|
||||||
if reflect.DeepEqual(user, model.ScaAuthUser{}) {
|
|
||||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "UsernameNotRegister"), c)
|
|
||||||
} else {
|
|
||||||
verify := utils.Verify(password, *user.Password)
|
|
||||||
if verify {
|
|
||||||
result.OkWithData(user, c)
|
|
||||||
} else {
|
|
||||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "PasswordError"), c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register 用户注册
|
|
||||||
// @Summary 用户注册
|
|
||||||
// @Tags 鉴权模块
|
|
||||||
// @Param user body model.ScaAuthUser true "用户信息"
|
|
||||||
// @Success 200 {string} json
|
|
||||||
// @Router /api/auth/user/register [post]
|
|
||||||
func (AuthAPI) Register(c *gin.Context) {
|
|
||||||
var user model.ScaAuthUser
|
|
||||||
_ = c.ShouldBindJSON(&user)
|
|
||||||
err := authService.AddUser(user)
|
|
||||||
if err != nil {
|
|
||||||
result.FailWithMessage("用户注册失败!", c)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
result.OkWithMessage("用户注册成功!", c)
|
|
||||||
}
|
|
@@ -10,7 +10,7 @@ import (
|
|||||||
"github.com/wenlng/go-captcha/v2/rotate"
|
"github.com/wenlng/go-captcha/v2/rotate"
|
||||||
"github.com/wenlng/go-captcha/v2/slide"
|
"github.com/wenlng/go-captcha/v2/slide"
|
||||||
"log"
|
"log"
|
||||||
"schisandra-cloud-album/api/captcha_api/model"
|
"schisandra-cloud-album/api/captcha_api/dto"
|
||||||
"schisandra-cloud-album/common/redis"
|
"schisandra-cloud-album/common/redis"
|
||||||
"schisandra-cloud-album/common/result"
|
"schisandra-cloud-album/common/result"
|
||||||
"schisandra-cloud-album/global"
|
"schisandra-cloud-album/global"
|
||||||
@@ -44,7 +44,7 @@ func (CaptchaAPI) GenerateRotateCaptcha(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
key := helper.StringToMD5(string(dotsByte))
|
key := helper.StringToMD5(string(dotsByte))
|
||||||
err = redis.Set(key, dotsByte, time.Minute).Err()
|
err = redis.Set("user:login:client:"+key, dotsByte, time.Minute).Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result.FailWithNull(c)
|
result.FailWithNull(c)
|
||||||
return
|
return
|
||||||
@@ -66,7 +66,7 @@ func (CaptchaAPI) GenerateRotateCaptcha(c *gin.Context) {
|
|||||||
// @Success 200 {string} json
|
// @Success 200 {string} json
|
||||||
// @Router /api/captcha/rotate/check [post]
|
// @Router /api/captcha/rotate/check [post]
|
||||||
func (CaptchaAPI) CheckRotateData(c *gin.Context) {
|
func (CaptchaAPI) CheckRotateData(c *gin.Context) {
|
||||||
rotateRequest := model.RotateCaptchaRequest{}
|
rotateRequest := dto.RotateCaptchaRequest{}
|
||||||
err := c.ShouldBindJSON(&rotateRequest)
|
err := c.ShouldBindJSON(&rotateRequest)
|
||||||
angle := rotateRequest.Angle
|
angle := rotateRequest.Angle
|
||||||
key := rotateRequest.Key
|
key := rotateRequest.Key
|
||||||
@@ -74,7 +74,7 @@ func (CaptchaAPI) CheckRotateData(c *gin.Context) {
|
|||||||
result.FailWithNull(c)
|
result.FailWithNull(c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cacheDataByte, err := redis.Get(key).Bytes()
|
cacheDataByte, err := redis.Get("user:login:client:" + key).Bytes()
|
||||||
if len(cacheDataByte) == 0 || err != nil {
|
if len(cacheDataByte) == 0 || err != nil {
|
||||||
result.FailWithCodeAndMessage(1011, ginI18n.MustGetMessage(c, "CaptchaExpired"), c)
|
result.FailWithCodeAndMessage(1011, ginI18n.MustGetMessage(c, "CaptchaExpired"), c)
|
||||||
return
|
return
|
||||||
@@ -126,7 +126,7 @@ func (CaptchaAPI) GenerateBasicTextCaptcha(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
key := helper.StringToMD5(string(dotsByte))
|
key := helper.StringToMD5(string(dotsByte))
|
||||||
err = redis.Set(key, dotsByte, time.Minute).Err()
|
err = redis.Set("user:login:client:"+key, dotsByte, time.Minute).Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result.FailWithNull(c)
|
result.FailWithNull(c)
|
||||||
return
|
return
|
||||||
@@ -154,7 +154,7 @@ func (CaptchaAPI) CheckClickData(c *gin.Context) {
|
|||||||
result.FailWithNull(c)
|
result.FailWithNull(c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cacheDataByte, err := redis.Get(key).Bytes()
|
cacheDataByte, err := redis.Get("user:login:client:" + key).Bytes()
|
||||||
if len(cacheDataByte) == 0 || err != nil {
|
if len(cacheDataByte) == 0 || err != nil {
|
||||||
result.FailWithNull(c)
|
result.FailWithNull(c)
|
||||||
return
|
return
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
package model
|
package dto
|
||||||
|
|
||||||
type RotateCaptchaRequest struct {
|
type RotateCaptchaRequest struct {
|
||||||
Angle int `json:"angle"`
|
Angle int `json:"angle"`
|
3
api/role_api/role.go
Normal file
3
api/role_api/role.go
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
package role_api
|
||||||
|
|
||||||
|
type RoleAPI struct{}
|
1
api/role_api/role_api.go
Normal file
1
api/role_api/role_api.go
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package role_api
|
@@ -7,9 +7,11 @@ import (
|
|||||||
"github.com/pkg6/go-sms/gateways"
|
"github.com/pkg6/go-sms/gateways"
|
||||||
"github.com/pkg6/go-sms/gateways/aliyun"
|
"github.com/pkg6/go-sms/gateways/aliyun"
|
||||||
"github.com/pkg6/go-sms/gateways/smsbao"
|
"github.com/pkg6/go-sms/gateways/smsbao"
|
||||||
|
"schisandra-cloud-album/common/redis"
|
||||||
"schisandra-cloud-album/common/result"
|
"schisandra-cloud-album/common/result"
|
||||||
"schisandra-cloud-album/global"
|
"schisandra-cloud-album/global"
|
||||||
"schisandra-cloud-album/utils"
|
"schisandra-cloud-album/utils"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SendMessageByAli 发送短信验证码
|
// SendMessageByAli 发送短信验证码
|
||||||
@@ -46,6 +48,8 @@ func (SmsAPI) SendMessageByAli(c *gin.Context) {
|
|||||||
result.FailWithMessage(ginI18n.MustGetMessage(c, "CaptchaSendFailed"), c)
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "CaptchaSendFailed"), c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
result.OkWithMessage(ginI18n.MustGetMessage(c, "CaptchaSendSuccess"), c)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendMessageBySmsBao 短信宝发送短信验证码
|
// SendMessageBySmsBao 短信宝发送短信验证码
|
||||||
@@ -78,3 +82,32 @@ func (SmsAPI) SendMessageBySmsBao(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
result.OkWithMessage(ginI18n.MustGetMessage(c, "CaptchaSendSuccess"), c)
|
result.OkWithMessage(ginI18n.MustGetMessage(c, "CaptchaSendSuccess"), c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendMessageTest 发送测试短信验证码
|
||||||
|
// @Summary 发送测试短信验证码
|
||||||
|
// @Description 发送测试短信验证码
|
||||||
|
// @Tags 短信验证码
|
||||||
|
// @Produce json
|
||||||
|
// @Param phone query string true "手机号"
|
||||||
|
// @Router /api/sms/test/send [get]
|
||||||
|
func (SmsAPI) SendMessageTest(c *gin.Context) {
|
||||||
|
phone := c.Query("phone")
|
||||||
|
if phone == "" {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "PhoneNotEmpty"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
isPhone := utils.IsPhone(phone)
|
||||||
|
if !isPhone {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "PhoneError"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
code := utils.GenValidateCode(6)
|
||||||
|
err := redis.Set("user:login:sms:"+phone, code, time.Minute).Err()
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Error(err)
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "CaptchaSendFailed"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result.OkWithMessage(ginI18n.MustGetMessage(c, "CaptchaSendSuccess"), c)
|
||||||
|
|
||||||
|
}
|
||||||
|
30
api/user_api/dto/request_dto.go
Normal file
30
api/user_api/dto/request_dto.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
import "encoding/json"
|
||||||
|
|
||||||
|
// RefreshTokenRequest 刷新token请求
|
||||||
|
type RefreshTokenRequest struct {
|
||||||
|
RefreshToken string `json:"refresh_token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PhoneLoginRequest 手机号登录请求
|
||||||
|
type PhoneLoginRequest struct {
|
||||||
|
Phone string `json:"phone"`
|
||||||
|
Captcha string `json:"captcha"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResponseData 返回数据
|
||||||
|
type ResponseData struct {
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
RefreshToken string `json:"refresh_token"`
|
||||||
|
ExpiresAt int64 `json:"expires_at"`
|
||||||
|
UID *string `json:"uid"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (res ResponseData) MarshalBinary() ([]byte, error) {
|
||||||
|
return json.Marshal(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (res ResponseData) UnmarshalBinary(data []byte) error {
|
||||||
|
return json.Unmarshal(data, &res)
|
||||||
|
}
|
3
api/user_api/user.go
Normal file
3
api/user_api/user.go
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
package user_api
|
||||||
|
|
||||||
|
type UserAPI struct{}
|
307
api/user_api/user_api.go
Normal file
307
api/user_api/user_api.go
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
package user_api
|
||||||
|
|
||||||
|
import (
|
||||||
|
ginI18n "github.com/gin-contrib/i18n"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/yitter/idgenerator-go/idgen"
|
||||||
|
"reflect"
|
||||||
|
"schisandra-cloud-album/api/user_api/dto"
|
||||||
|
"schisandra-cloud-album/common/enum"
|
||||||
|
"schisandra-cloud-album/common/redis"
|
||||||
|
"schisandra-cloud-album/common/result"
|
||||||
|
"schisandra-cloud-album/global"
|
||||||
|
"schisandra-cloud-album/model"
|
||||||
|
"schisandra-cloud-album/service"
|
||||||
|
"schisandra-cloud-album/utils"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var userService = service.Service.UserService
|
||||||
|
var userRoleService = service.Service.UserRoleService
|
||||||
|
|
||||||
|
// GetUserList
|
||||||
|
// @Summary 获取所有用户列表
|
||||||
|
// @Tags 鉴权模块
|
||||||
|
// @Success 200 {string} json
|
||||||
|
// @Router /api/auth/user/List [get]
|
||||||
|
func (UserAPI) GetUserList(c *gin.Context) {
|
||||||
|
userList := userService.GetUserList()
|
||||||
|
result.OkWithData(userList, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryUserByUsername
|
||||||
|
// @Summary 根据用户名查询用户
|
||||||
|
// @Tags 鉴权模块
|
||||||
|
// @Param username query string true "用户名"
|
||||||
|
// @Success 200 {string} json
|
||||||
|
// @Router /api/auth/user/query_by_username [get]
|
||||||
|
func (UserAPI) QueryUserByUsername(c *gin.Context) {
|
||||||
|
username := c.Query("username")
|
||||||
|
user := userService.QueryUserByUsername(username)
|
||||||
|
if reflect.DeepEqual(user, model.ScaAuthUser{}) {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "NotFoundUser"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result.OkWithData(user, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryUserByUuid
|
||||||
|
// @Summary 根据uuid查询用户
|
||||||
|
// @Tags 鉴权模块
|
||||||
|
// @Param uuid query string true "用户uuid"
|
||||||
|
// @Success 200 {string} json
|
||||||
|
// @Router /api/auth/user/query_by_uuid [get]
|
||||||
|
func (UserAPI) QueryUserByUuid(c *gin.Context) {
|
||||||
|
uuid := c.Query("uuid")
|
||||||
|
user := userService.QueryUserByUuid(uuid)
|
||||||
|
if reflect.DeepEqual(user, model.ScaAuthUser{}) {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "NotFoundUser"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result.OkWithData(user, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteUser 删除用户
|
||||||
|
// @Summary 删除用户
|
||||||
|
// @Tags 鉴权模块
|
||||||
|
// @Param uuid query string true "用户uuid"
|
||||||
|
// @Success 200 {string} json
|
||||||
|
// @Router /api/auth/user/delete [delete]
|
||||||
|
func (UserAPI) DeleteUser(c *gin.Context) {
|
||||||
|
uuid := c.Query("uuid")
|
||||||
|
err := userService.DeleteUser(uuid)
|
||||||
|
if err != nil {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "DeletedFailed"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result.OkWithMessage(ginI18n.MustGetMessage(c, "DeletedSuccess"), c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryUserByPhone 根据手机号查询用户
|
||||||
|
// @Summary 根据手机号查询用户
|
||||||
|
// @Tags 鉴权模块
|
||||||
|
// @Param phone query string true "手机号"
|
||||||
|
// @Success 200 {string} json
|
||||||
|
// @Router /api/auth/user/query_by_phone [get]
|
||||||
|
func (UserAPI) QueryUserByPhone(c *gin.Context) {
|
||||||
|
phone := c.Query("phone")
|
||||||
|
user := userService.QueryUserByPhone(phone)
|
||||||
|
if reflect.DeepEqual(user, model.ScaAuthUser{}) {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "NotFoundUser"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result.OkWithData(user, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccountLogin 账号登录
|
||||||
|
// @Summary 账号登录
|
||||||
|
// @Tags 鉴权模块
|
||||||
|
// @Param account query string true "账号"
|
||||||
|
// @Param password query string true "密码"
|
||||||
|
// @Success 200 {string} json
|
||||||
|
// @Router /api/user/login [post]
|
||||||
|
func (UserAPI) AccountLogin(c *gin.Context) {
|
||||||
|
account := c.PostForm("account")
|
||||||
|
password := c.PostForm("password")
|
||||||
|
isPhone := utils.IsPhone(account)
|
||||||
|
if isPhone {
|
||||||
|
user := userService.QueryUserByPhone(account)
|
||||||
|
if reflect.DeepEqual(user, model.ScaAuthUser{}) {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "PhoneNotRegister"), c)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
verify := utils.Verify(password, *user.Password)
|
||||||
|
if verify {
|
||||||
|
result.OkWithData(user, c)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "PasswordError"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isEmail := utils.IsEmail(account)
|
||||||
|
if isEmail {
|
||||||
|
user := userService.QueryUserByEmail(account)
|
||||||
|
if reflect.DeepEqual(user, model.ScaAuthUser{}) {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "EmailNotRegister"), c)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
verify := utils.Verify(password, *user.Password)
|
||||||
|
if verify {
|
||||||
|
result.OkWithData(user, c)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "PasswordError"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isUsername := utils.IsUsername(account)
|
||||||
|
if isUsername {
|
||||||
|
user := userService.QueryUserByUsername(account)
|
||||||
|
if reflect.DeepEqual(user, model.ScaAuthUser{}) {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "UsernameNotRegister"), c)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
verify := utils.Verify(password, *user.Password)
|
||||||
|
if verify {
|
||||||
|
result.OkWithData(user, c)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "PasswordError"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PhoneLogin 手机号登录/注册
|
||||||
|
// @Summary 手机号登录/注册
|
||||||
|
// @Tags 鉴权模块
|
||||||
|
// @Param phone query string true "手机号"
|
||||||
|
// @Param captcha query string true "验证码"
|
||||||
|
// @Success 200 {string} json
|
||||||
|
// @Router /api/user/phone_login [post]
|
||||||
|
func (UserAPI) PhoneLogin(c *gin.Context) {
|
||||||
|
request := dto.PhoneLoginRequest{}
|
||||||
|
err := c.ShouldBindJSON(&request)
|
||||||
|
if err != nil {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
phone := request.Phone
|
||||||
|
captcha := request.Captcha
|
||||||
|
if phone == "" || captcha == "" {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "PhoneAndCaptchaNotEmpty"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
isPhone := utils.IsPhone(phone)
|
||||||
|
if !isPhone {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "PhoneErrorFormat"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user := userService.QueryUserByPhone(phone)
|
||||||
|
if reflect.DeepEqual(user, model.ScaAuthUser{}) {
|
||||||
|
// 未注册
|
||||||
|
code := redis.Get("user:login:sms:" + phone)
|
||||||
|
if code == nil {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "CaptchaExpired"), c)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
uid := idgen.NextId()
|
||||||
|
uidStr := strconv.FormatInt(uid, 10)
|
||||||
|
createUser := model.ScaAuthUser{
|
||||||
|
UID: &uidStr,
|
||||||
|
Phone: &phone,
|
||||||
|
}
|
||||||
|
addUser, err := userService.AddUser(createUser)
|
||||||
|
if err != nil {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "RegisterUserError"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userRole := model.ScaAuthUserRole{
|
||||||
|
UserID: addUser.ID,
|
||||||
|
RoleID: enum.User,
|
||||||
|
}
|
||||||
|
e := userRoleService.AddUserRole(userRole)
|
||||||
|
if e != nil {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ids, err := userRoleService.GetUserRoleIdsByUserId(addUser.ID)
|
||||||
|
if err != nil {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
accessToken, refreshToken, expiresAt := utils.GenerateAccessTokenAndRefreshToken(utils.JWTPayload{UserID: addUser.UID, RoleID: ids})
|
||||||
|
|
||||||
|
data := dto.ResponseData{
|
||||||
|
AccessToken: accessToken,
|
||||||
|
RefreshToken: refreshToken,
|
||||||
|
ExpiresAt: expiresAt,
|
||||||
|
UID: addUser.UID,
|
||||||
|
}
|
||||||
|
fail := redis.Set("user:login:token:"+*addUser.UID, data, time.Hour*24*30).Err()
|
||||||
|
if fail != nil {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result.OkWithData(data, c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
code := redis.Get("user:login:sms:" + phone)
|
||||||
|
if code == nil {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "CaptchaExpired"), c)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
if captcha != code.Val() {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "CaptchaError"), c)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
ids, err := userRoleService.GetUserRoleIdsByUserId(user.ID)
|
||||||
|
if err != nil {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
accessToken, refreshToken, expiresAt := utils.GenerateAccessTokenAndRefreshToken(utils.JWTPayload{UserID: user.UID, RoleID: ids})
|
||||||
|
|
||||||
|
data := dto.ResponseData{
|
||||||
|
AccessToken: accessToken,
|
||||||
|
RefreshToken: refreshToken,
|
||||||
|
ExpiresAt: expiresAt,
|
||||||
|
UID: user.UID,
|
||||||
|
}
|
||||||
|
fail := redis.Set("user:login:token:"+*user.UID, data, time.Hour*24*30).Err()
|
||||||
|
if fail != nil {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginFailed"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result.OkWithData(data, c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// RefreshHandler 刷新token
|
||||||
|
// @Summary 刷新token
|
||||||
|
// @Tags 鉴权模块
|
||||||
|
// @Param refresh_token query string true "刷新token"
|
||||||
|
// @Success 200 {string} json
|
||||||
|
// @Router /api/auth/token/refresh [post]
|
||||||
|
func (UserAPI) RefreshHandler(c *gin.Context) {
|
||||||
|
refreshToken := c.Query("refresh_token")
|
||||||
|
if refreshToken == "" {
|
||||||
|
result.FailWithMessage("refresh_token不能为空!", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
parseRefreshToken, isUpd, err := utils.ParseToken(refreshToken)
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorln(err)
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginExpired"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if isUpd {
|
||||||
|
accessTokenString, refreshTokenString, expiresAt := utils.GenerateAccessTokenAndRefreshToken(utils.JWTPayload{UserID: parseRefreshToken.UserID, RoleID: parseRefreshToken.RoleID})
|
||||||
|
data := dto.ResponseData{
|
||||||
|
AccessToken: accessTokenString,
|
||||||
|
RefreshToken: refreshTokenString,
|
||||||
|
ExpiresAt: expiresAt,
|
||||||
|
UID: parseRefreshToken.UserID,
|
||||||
|
}
|
||||||
|
fail := redis.Set("user:login:token:"+*parseRefreshToken.UserID, data, time.Hour*24*30).Err()
|
||||||
|
if fail != nil {
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginExpired"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result.OkWithData(data, c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
7
common/enum/role.go
Normal file
7
common/enum/role.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package enum
|
||||||
|
|
||||||
|
var (
|
||||||
|
SuperAdmin int64 = 1
|
||||||
|
Admin int64 = 2
|
||||||
|
User int64 = 3
|
||||||
|
)
|
@@ -1,10 +1,8 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
type JWT struct {
|
type JWT struct {
|
||||||
Secret string `yaml:"secret"`
|
Secret string `yaml:"secret"`
|
||||||
Expiration string `yaml:"expiration"`
|
HeaderKey string `yaml:"header-key"`
|
||||||
RefreshExpiration string `yaml:"refresh-expiration"`
|
HeaderPrefix string `yaml:"header-prefix"`
|
||||||
RefreshTokenKey string `yaml:"refresh-token-key"`
|
Issuer string `yaml:"issuer"`
|
||||||
HeaderKey string `yaml:"header-key"`
|
|
||||||
HeaderPrefix string `yaml:"header-prefix"`
|
|
||||||
}
|
}
|
||||||
|
10
core/idgenerator.go
Normal file
10
core/idgenerator.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import "github.com/yitter/idgenerator-go/idgen"
|
||||||
|
|
||||||
|
func InitIDGenerator() {
|
||||||
|
var options = idgen.NewIdGeneratorOptions(1)
|
||||||
|
options.WorkerIdBitLength = 6 // 默认值6,限定 WorkerId 最大值为2^6-1,即默认最多支持64个节点。
|
||||||
|
options.SeqBitLength = 6 // 默认值6,限制每毫秒生成的ID个数。若生成速度超过5万个/秒,建议加大 SeqBitLength 到 10。
|
||||||
|
idgen.SetIdGenerator(options)
|
||||||
|
}
|
@@ -176,7 +176,7 @@ const docTemplate = `{
|
|||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/model.ScaAuthUser"
|
"$ref": "#/definitions/dto.ScaAuthUser"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -429,7 +429,7 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
"model.ScaAuthUser": {
|
"dto.ScaAuthUser": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"avatar": {
|
"avatar": {
|
||||||
|
4
go.mod
4
go.mod
@@ -28,7 +28,7 @@ require (
|
|||||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||||
github.com/bytedance/sonic v1.12.0 // indirect
|
github.com/bytedance/sonic v1.12.0 // indirect
|
||||||
github.com/bytedance/sonic/loader v0.2.0 // indirect
|
github.com/bytedance/sonic/loader v0.2.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
@@ -41,6 +41,7 @@ require (
|
|||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.22.0 // indirect
|
github.com/go-playground/validator/v10 v10.22.0 // indirect
|
||||||
|
github.com/go-redis/redis/v8 v8.11.5 // indirect
|
||||||
github.com/go-sql-driver/mysql v1.8.1 // indirect
|
github.com/go-sql-driver/mysql v1.8.1 // indirect
|
||||||
github.com/goccy/go-json v0.10.3 // indirect
|
github.com/goccy/go-json v0.10.3 // indirect
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
||||||
@@ -60,6 +61,7 @@ require (
|
|||||||
github.com/pkg6/go-sms v0.1.2 // indirect
|
github.com/pkg6/go-sms v0.1.2 // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||||
|
github.com/yitter/idgenerator-go v1.3.3 // indirect
|
||||||
golang.org/x/arch v0.8.0 // indirect
|
golang.org/x/arch v0.8.0 // indirect
|
||||||
golang.org/x/image v0.18.0 // indirect
|
golang.org/x/image v0.18.0 // indirect
|
||||||
golang.org/x/mod v0.19.0 // indirect
|
golang.org/x/mod v0.19.0 // indirect
|
||||||
|
6
go.sum
6
go.sum
@@ -15,6 +15,8 @@ github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP
|
|||||||
github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||||
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||||
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||||
@@ -53,6 +55,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
|
|||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao=
|
github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao=
|
||||||
github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||||
|
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||||
|
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||||
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||||
@@ -151,6 +155,8 @@ github.com/wenlng/go-captcha-assets v1.0.1 h1:AdjRFMKmadPRWRTv0XEYfjDvcaayZ2yExI
|
|||||||
github.com/wenlng/go-captcha-assets v1.0.1/go.mod h1:yQqc7rRbxgLCg+tWtVp+7Y317D1wIZDan/yIwt8wSac=
|
github.com/wenlng/go-captcha-assets v1.0.1/go.mod h1:yQqc7rRbxgLCg+tWtVp+7Y317D1wIZDan/yIwt8wSac=
|
||||||
github.com/wenlng/go-captcha/v2 v2.0.0 h1:7Z4Zy09SIHgvj9e8ZxP4VhYOwg7IHt8kGlVrE5jP5Z8=
|
github.com/wenlng/go-captcha/v2 v2.0.0 h1:7Z4Zy09SIHgvj9e8ZxP4VhYOwg7IHt8kGlVrE5jP5Z8=
|
||||||
github.com/wenlng/go-captcha/v2 v2.0.0/go.mod h1:5hac1em3uXoyC5ipZ0xFv9umNM/waQvYAQdr0cx/h34=
|
github.com/wenlng/go-captcha/v2 v2.0.0/go.mod h1:5hac1em3uXoyC5ipZ0xFv9umNM/waQvYAQdr0cx/h34=
|
||||||
|
github.com/yitter/idgenerator-go v1.3.3 h1:i6rzmpbCL0vlmr/tuW5+lSQzNuDG9vYBjIYRvnRcHE8=
|
||||||
|
github.com/yitter/idgenerator-go v1.3.3/go.mod h1:VVjbqFjGUsIkaXVkXEdmx1LiXUL3K1NvyxWPJBPbBpE=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
||||||
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||||
|
@@ -33,3 +33,11 @@ CaptchaSendSuccess = "captcha send successfully!"
|
|||||||
CaptchaTooOften = "captcha too often!"
|
CaptchaTooOften = "captcha too often!"
|
||||||
PhoneNotEmpty = "phone number can not be empty!"
|
PhoneNotEmpty = "phone number can not be empty!"
|
||||||
EmailNotEmpty = "email can not be empty!"
|
EmailNotEmpty = "email can not be empty!"
|
||||||
|
AuthVerifyFailed = "auth verify failed!, please try again!"
|
||||||
|
AuthVerifySuccess = "auth verify successfully!"
|
||||||
|
AuthVerifyExpired = "auth verify expired!"
|
||||||
|
ParamsError = "params error!"
|
||||||
|
PhoneAndCaptchaNotEmpty = "phone number and captcha can not be empty!"
|
||||||
|
PhoneErrorFormat = "phone number error format!"
|
||||||
|
RegisterUserError = "register user error!"
|
||||||
|
LoginExpired = "login expired!, please try again!"
|
||||||
|
@@ -33,3 +33,11 @@ CaptchaSendSuccess = "验证码发送成功!"
|
|||||||
CaptchaTooOften = "验证码发送过于频繁!"
|
CaptchaTooOften = "验证码发送过于频繁!"
|
||||||
PhoneNotEmpty = "手机号不能为空!"
|
PhoneNotEmpty = "手机号不能为空!"
|
||||||
EmailNotEmpty = "邮箱不能为空!"
|
EmailNotEmpty = "邮箱不能为空!"
|
||||||
|
AuthVerifyFailed = "认证失败!,请重新登录!"
|
||||||
|
AuthVerifySuccess = "认证成功!"
|
||||||
|
AuthVerifyExpired = "认证已过期!,请重新登录!"
|
||||||
|
ParamsError = "参数错误!"
|
||||||
|
PhoneAndCaptchaNotEmpty = "手机号和验证码不能为空!"
|
||||||
|
PhoneErrorFormat = "手机号格式错误!"
|
||||||
|
RegisterUserError = "注册用户错误!"
|
||||||
|
LoginExpired = "登录已过期!,请重新登录!"
|
||||||
|
11
main.go
11
main.go
@@ -9,11 +9,12 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// 初始化配置
|
// 初始化配置
|
||||||
core.InitConfig() // 读取配置文件
|
core.InitConfig() // 读取配置文件
|
||||||
core.InitLogger() // 初始化日志
|
core.InitLogger() // 初始化日志
|
||||||
core.InitGorm() // 初始化数据库
|
core.InitGorm() // 初始化数据库
|
||||||
core.InitRedis() // 初始化redis
|
core.InitRedis() // 初始化redis
|
||||||
core.InitCaptcha() // 初始化验证码
|
core.InitCaptcha() // 初始化验证码
|
||||||
|
core.InitIDGenerator() // 初始化ID生成器
|
||||||
// 命令行参数绑定
|
// 命令行参数绑定
|
||||||
option := cmd.Parse()
|
option := cmd.Parse()
|
||||||
if cmd.IsStopWeb(&option) {
|
if cmd.IsStopWeb(&option) {
|
||||||
|
38
middleware/jwt.go
Normal file
38
middleware/jwt.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
ginI18n "github.com/gin-contrib/i18n"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"schisandra-cloud-album/common/result"
|
||||||
|
"schisandra-cloud-album/global"
|
||||||
|
"schisandra-cloud-album/utils"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func JWTAuthMiddleware() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
// 默认双Token放在请求头Authorization的Bearer中,并以空格隔开
|
||||||
|
authHeader := c.GetHeader(global.CONFIG.JWT.HeaderKey)
|
||||||
|
if authHeader == "" {
|
||||||
|
c.Abort()
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "AuthVerifyFailed"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
headerPrefix := global.CONFIG.JWT.HeaderPrefix
|
||||||
|
accessToken := strings.TrimPrefix(authHeader, headerPrefix+" ")
|
||||||
|
|
||||||
|
if accessToken == "undefined" || accessToken == "" {
|
||||||
|
c.Abort()
|
||||||
|
result.FailWithMessage(ginI18n.MustGetMessage(c, "AuthVerifyFailed"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
parseToken, isUpd, err := utils.ParseToken(accessToken)
|
||||||
|
if err != nil || !isUpd {
|
||||||
|
c.Abort()
|
||||||
|
result.FailWithCodeAndMessage(401, ginI18n.MustGetMessage(c, "AuthVerifyExpired"), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Set("userId", parseToken.UserID)
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
@@ -1,6 +1,7 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -9,7 +10,7 @@ const TableNameScaAuthUser = "sca_auth_user"
|
|||||||
// ScaAuthUser 用户表
|
// ScaAuthUser 用户表
|
||||||
type ScaAuthUser struct {
|
type ScaAuthUser struct {
|
||||||
ID int64 `gorm:"column:id;type:bigint(255);primaryKey;autoIncrement:true;comment:自增ID" json:"-"` // 自增ID
|
ID int64 `gorm:"column:id;type:bigint(255);primaryKey;autoIncrement:true;comment:自增ID" json:"-"` // 自增ID
|
||||||
UUID *string `gorm:"column:uuid;type:varchar(255);comment:唯一ID" json:"uuid"` // 唯一ID
|
UID *string `gorm:"column:uid;type:varchar(255);comment:唯一ID" json:"uid"` // 唯一ID
|
||||||
Username *string `gorm:"column:username;type:varchar(32);comment:用户名" json:"username"` // 用户名
|
Username *string `gorm:"column:username;type:varchar(32);comment:用户名" json:"username"` // 用户名
|
||||||
Nickname *string `gorm:"column:nickname;type:varchar(32);comment:昵称" json:"nickname"` // 昵称
|
Nickname *string `gorm:"column:nickname;type:varchar(32);comment:昵称" json:"nickname"` // 昵称
|
||||||
Email *string `gorm:"column:email;type:varchar(32);comment:邮箱" json:"email"` // 邮箱
|
Email *string `gorm:"column:email;type:varchar(32);comment:邮箱" json:"email"` // 邮箱
|
||||||
@@ -17,14 +18,14 @@ type ScaAuthUser struct {
|
|||||||
Password *string `gorm:"column:password;type:varchar(64);comment:密码" json:"-"` // 密码
|
Password *string `gorm:"column:password;type:varchar(64);comment:密码" json:"-"` // 密码
|
||||||
Gender *string `gorm:"column:gender;type:varchar(32);comment:性别" json:"gender"` // 性别
|
Gender *string `gorm:"column:gender;type:varchar(32);comment:性别" json:"gender"` // 性别
|
||||||
Avatar *string `gorm:"column:avatar;type:varchar(255);comment:头像" json:"avatar"` // 头像
|
Avatar *string `gorm:"column:avatar;type:varchar(255);comment:头像" json:"avatar"` // 头像
|
||||||
Status *int64 `gorm:"column:status;type:tinyint(4);comment:状态 0 正常 1 封禁" json:"status"` // 状态 0 正常 1 封禁
|
Status *int64 `gorm:"column:status;type:tinyint(4);default:0;comment:状态 0 正常 1 封禁" json:"status"` // 状态 0 正常 1 封禁
|
||||||
Introduce *string `gorm:"column:introduce;type:varchar(255);comment:介绍" json:"introduce"` // 介绍
|
Introduce *string `gorm:"column:introduce;type:varchar(255);comment:介绍" json:"introduce"` // 介绍
|
||||||
ExtJSON *string `gorm:"column:ext_json;type:varchar(255);comment:额外字段" json:"-"` // 额外字段
|
ExtJSON *string `gorm:"column:ext_json;type:varchar(255);comment:额外字段" json:"-"` // 额外字段
|
||||||
CreatedBy *string `gorm:"column:created_by;type:varchar(32);comment:创建人" json:"created_by"` // 创建人
|
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"` // 创建时间
|
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"` // 更新人
|
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"` // 更新时间
|
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:是否删除 0 未删除 1 已删除" json:"-"` // 是否删除 0 未删除 1 已删除
|
Deleted *int64 `gorm:"column:deleted;type:int(11);default:0;comment:是否删除 0 未删除 1 已删除" json:"-"` // 是否删除 0 未删除 1 已删除
|
||||||
Blog *string `gorm:"column:blog;type:varchar(255);comment:博客" json:"blog"` // 博客
|
Blog *string `gorm:"column:blog;type:varchar(255);comment:博客" json:"blog"` // 博客
|
||||||
Location *string `gorm:"column:location;type:varchar(255);comment:地址" json:"location"` // 地址
|
Location *string `gorm:"column:location;type:varchar(255);comment:地址" json:"location"` // 地址
|
||||||
Company *string `gorm:"column:company;type:varchar(255);comment:公司" json:"company"` // 公司
|
Company *string `gorm:"column:company;type:varchar(255);comment:公司" json:"company"` // 公司
|
||||||
@@ -34,3 +35,11 @@ type ScaAuthUser struct {
|
|||||||
func (*ScaAuthUser) TableName() string {
|
func (*ScaAuthUser) TableName() string {
|
||||||
return TableNameScaAuthUser
|
return TableNameScaAuthUser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (user *ScaAuthUser) MarshalBinary() ([]byte, error) {
|
||||||
|
return json.Marshal(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (user *ScaAuthUser) UnmarshalBinary(data []byte) error {
|
||||||
|
return json.Unmarshal(data, user)
|
||||||
|
}
|
||||||
|
@@ -1,19 +0,0 @@
|
|||||||
package modules
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"schisandra-cloud-album/api"
|
|
||||||
)
|
|
||||||
|
|
||||||
var authApi = api.Api.AuthApi
|
|
||||||
|
|
||||||
func AuthRouter(router *gin.RouterGroup) {
|
|
||||||
group := router.Group("auth")
|
|
||||||
group.GET("/user/List", authApi.GetUserList)
|
|
||||||
group.GET("/user/query_by_username", authApi.QueryUserByUsername)
|
|
||||||
group.GET("/user/query_by_uuid", authApi.QueryUserByUuid)
|
|
||||||
group.DELETE("/user/delete", authApi.DeleteUser)
|
|
||||||
group.GET("/user/query_by_phone", authApi.QueryUserByPhone)
|
|
||||||
group.POST("/user/login", authApi.AccountLogin)
|
|
||||||
group.POST("/user/register", authApi.Register)
|
|
||||||
}
|
|
@@ -11,4 +11,5 @@ func SmsRouter(router *gin.RouterGroup) {
|
|||||||
group := router.Group("/sms")
|
group := router.Group("/sms")
|
||||||
group.GET("/ali/send", smsApi.SendMessageByAli)
|
group.GET("/ali/send", smsApi.SendMessageByAli)
|
||||||
group.GET("/smsbao/send", smsApi.SendMessageBySmsBao)
|
group.GET("/smsbao/send", smsApi.SendMessageBySmsBao)
|
||||||
|
group.GET("/test/send", smsApi.SendMessageTest)
|
||||||
}
|
}
|
||||||
|
25
router/modules/user_router.go
Normal file
25
router/modules/user_router.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package modules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"schisandra-cloud-album/api"
|
||||||
|
"schisandra-cloud-album/middleware"
|
||||||
|
)
|
||||||
|
|
||||||
|
var userApi = api.Api.UserApi
|
||||||
|
|
||||||
|
// UserRouter 用户相关路由 有auth接口组需要token验证,没有auth接口组不需要token验证
|
||||||
|
func UserRouter(router *gin.RouterGroup) {
|
||||||
|
userGroup := router.Group("user")
|
||||||
|
{
|
||||||
|
userGroup.POST("/login", userApi.AccountLogin)
|
||||||
|
userGroup.POST("/phone_login", userApi.PhoneLogin)
|
||||||
|
}
|
||||||
|
authGroup := router.Group("auth").Use(middleware.JWTAuthMiddleware())
|
||||||
|
{
|
||||||
|
authGroup.GET("/user/List", userApi.GetUserList)
|
||||||
|
authGroup.GET("/user/query_by_uuid", userApi.QueryUserByUuid)
|
||||||
|
authGroup.POST("/token/refresh", userApi.RefreshHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -23,7 +23,7 @@ func InitRouter() *gin.Engine {
|
|||||||
publicGroup.Use(middleware.I18n())
|
publicGroup.Use(middleware.I18n())
|
||||||
|
|
||||||
modules.SwaggerRouter(router) // 注册swagger路由
|
modules.SwaggerRouter(router) // 注册swagger路由
|
||||||
modules.AuthRouter(publicGroup) // 注册鉴权路由
|
modules.UserRouter(publicGroup) // 注册鉴权路由
|
||||||
modules.CaptchaRouter(publicGroup) // 注册验证码路由
|
modules.CaptchaRouter(publicGroup) // 注册验证码路由
|
||||||
modules.SmsRouter(publicGroup) // 注册短信验证码路由
|
modules.SmsRouter(publicGroup) // 注册短信验证码路由
|
||||||
return router
|
return router
|
||||||
|
@@ -1,3 +0,0 @@
|
|||||||
package auth_service
|
|
||||||
|
|
||||||
type AuthService struct{}
|
|
3
service/role_service/role.go
Normal file
3
service/role_service/role.go
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
package role_service
|
||||||
|
|
||||||
|
type RoleService struct{}
|
15
service/role_service/role_service.go
Normal file
15
service/role_service/role_service.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package role_service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"schisandra-cloud-album/global"
|
||||||
|
"schisandra-cloud-album/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetRoleById : 通过Id获取角色信息
|
||||||
|
func (RoleService) GetRoleById(id int64) (model.ScaAuthRole, error) {
|
||||||
|
var role model.ScaAuthRole
|
||||||
|
if err := global.DB.Where("id = ? and deleted = 0", id).First(&role).Error; err != nil {
|
||||||
|
return model.ScaAuthRole{}, err
|
||||||
|
}
|
||||||
|
return role, nil
|
||||||
|
}
|
@@ -1,12 +1,16 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"schisandra-cloud-album/service/auth_service"
|
"schisandra-cloud-album/service/role_service"
|
||||||
|
"schisandra-cloud-album/service/user_role_service"
|
||||||
|
"schisandra-cloud-album/service/user_service"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Services 统一导出的service
|
// Services 统一导出的service
|
||||||
type Services struct {
|
type Services struct {
|
||||||
AuthService auth_service.AuthService
|
UserService user_service.UserService
|
||||||
|
RoleService role_service.RoleService
|
||||||
|
UserRoleService user_role_service.UserRoleService
|
||||||
}
|
}
|
||||||
|
|
||||||
// Service new函数实例化,实例化完成后会返回结构体地指针类型
|
// Service new函数实例化,实例化完成后会返回结构体地指针类型
|
||||||
|
3
service/user_role_service/user_role.go
Normal file
3
service/user_role_service/user_role.go
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
package user_role_service
|
||||||
|
|
||||||
|
type UserRoleService struct{}
|
23
service/user_role_service/user_role_service.go
Normal file
23
service/user_role_service/user_role_service.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
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 = ?", 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
|
||||||
|
}
|
3
service/user_service/user.go
Normal file
3
service/user_service/user.go
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
package user_service
|
||||||
|
|
||||||
|
type UserService struct{}
|
@@ -1,4 +1,4 @@
|
|||||||
package auth_service
|
package user_service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
@@ -8,52 +8,60 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// GetUserList 获取所有用户列表
|
// GetUserList 获取所有用户列表
|
||||||
func (AuthService) GetUserList() []*model.ScaAuthUser {
|
func (UserService) GetUserList() []*model.ScaAuthUser {
|
||||||
data := make([]*model.ScaAuthUser, 0)
|
data := make([]*model.ScaAuthUser, 0)
|
||||||
global.DB.Where("deleted = 0 ").Find(&data)
|
global.DB.Where("deleted = 0 ").Find(&data)
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryUserByUsername 根据用户名查询用户
|
// QueryUserByUsername 根据用户名查询用户
|
||||||
func (AuthService) QueryUserByUsername(username string) model.ScaAuthUser {
|
func (UserService) QueryUserByUsername(username string) model.ScaAuthUser {
|
||||||
authUser := model.ScaAuthUser{}
|
authUser := model.ScaAuthUser{}
|
||||||
global.DB.Where("username = ? and deleted = 0", username).First(&authUser)
|
global.DB.Where("username = ? and deleted = 0", username).First(&authUser)
|
||||||
return authUser
|
return authUser
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryUserByUuid 根据用户uuid查询用户
|
// QueryUserByUuid 根据用户uuid查询用户
|
||||||
func (AuthService) QueryUserByUuid(uuid string) model.ScaAuthUser {
|
func (UserService) QueryUserByUuid(uuid string) model.ScaAuthUser {
|
||||||
authUser := model.ScaAuthUser{}
|
authUser := model.ScaAuthUser{}
|
||||||
global.DB.Where("uuid = ? and deleted = 0", uuid).First(&authUser)
|
global.DB.Where("uuid = ? and deleted = 0", uuid).First(&authUser)
|
||||||
return authUser
|
return authUser
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddUser 添加用户
|
// AddUser 添加用户
|
||||||
func (AuthService) AddUser(user model.ScaAuthUser) error {
|
func (UserService) AddUser(user model.ScaAuthUser) (model.ScaAuthUser, error) {
|
||||||
return global.DB.Create(&user).Error
|
if err := global.DB.Create(&user).Error; err != nil {
|
||||||
|
return model.ScaAuthUser{}, err
|
||||||
|
}
|
||||||
|
// 查询创建后的用户信息
|
||||||
|
var createdUser model.ScaAuthUser
|
||||||
|
if err := global.DB.First(&createdUser, user.ID).Error; err != nil {
|
||||||
|
return model.ScaAuthUser{}, err
|
||||||
|
}
|
||||||
|
return createdUser, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateUser 更新用户
|
// UpdateUser 更新用户
|
||||||
func (AuthService) UpdateUser(user model.ScaAuthUser) *gorm.DB {
|
func (UserService) UpdateUser(user model.ScaAuthUser) *gorm.DB {
|
||||||
authUser := model.ScaAuthUser{}
|
authUser := model.ScaAuthUser{}
|
||||||
return global.DB.Model(&authUser).Where("uuid = ?", user.UUID).Updates(user)
|
return global.DB.Model(&authUser).Where("uuid = ?", user.UID).Updates(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteUser 删除用户
|
// DeleteUser 删除用户
|
||||||
func (AuthService) DeleteUser(uuid string) error {
|
func (UserService) DeleteUser(uuid string) error {
|
||||||
authUser := model.ScaAuthUser{}
|
authUser := model.ScaAuthUser{}
|
||||||
return global.DB.Model(&authUser).Where("uuid = ?", uuid).Updates(&model.ScaAuthUser{Deleted: &enum.DELETED}).Error
|
return global.DB.Model(&authUser).Where("uuid = ?", uuid).Updates(&model.ScaAuthUser{Deleted: &enum.DELETED}).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryUserByPhone 根据手机号查询用户
|
// QueryUserByPhone 根据手机号查询用户
|
||||||
func (AuthService) QueryUserByPhone(phone string) model.ScaAuthUser {
|
func (UserService) QueryUserByPhone(phone string) model.ScaAuthUser {
|
||||||
authUser := model.ScaAuthUser{}
|
authUser := model.ScaAuthUser{}
|
||||||
global.DB.Where("phone = ? and deleted = 0", phone).First(&authUser)
|
global.DB.Where("phone = ? and deleted = 0", phone).First(&authUser)
|
||||||
return authUser
|
return authUser
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryUserByEmail 根据邮箱查询用户
|
// QueryUserByEmail 根据邮箱查询用户
|
||||||
func (AuthService) QueryUserByEmail(email string) model.ScaAuthUser {
|
func (UserService) QueryUserByEmail(email string) model.ScaAuthUser {
|
||||||
authUser := model.ScaAuthUser{}
|
authUser := model.ScaAuthUser{}
|
||||||
global.DB.Where("email = ? and deleted = 0", email).First(&authUser)
|
global.DB.Where("email = ? and deleted = 0", email).First(&authUser)
|
||||||
return authUser
|
return authUser
|
54
utils/jwt.go
54
utils/jwt.go
@@ -7,9 +7,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type JWTPayload struct {
|
type JWTPayload struct {
|
||||||
UserID int `json:"user_id"`
|
UserID *string `json:"user_id"`
|
||||||
Role string `json:"role"`
|
RoleID []*int64 `json:"role_id"`
|
||||||
Username string `json:"username"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type JWTClaims struct {
|
type JWTClaims struct {
|
||||||
@@ -17,10 +16,11 @@ type JWTClaims struct {
|
|||||||
jwt.RegisteredClaims
|
jwt.RegisteredClaims
|
||||||
}
|
}
|
||||||
|
|
||||||
var MySecret = []byte(global.CONFIG.JWT.Secret)
|
var MySecret []byte
|
||||||
|
|
||||||
// GenerateToken generates a JWT token with the given payload
|
// GenerateToken generates a JWT token with the given payload
|
||||||
func GenerateToken(payload JWTPayload) (string, error) {
|
func GenerateToken(payload JWTPayload) (string, error) {
|
||||||
|
MySecret = []byte(global.CONFIG.JWT.Secret)
|
||||||
claims := JWTClaims{
|
claims := JWTClaims{
|
||||||
JWTPayload: payload,
|
JWTPayload: payload,
|
||||||
RegisteredClaims: jwt.RegisteredClaims{
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
@@ -33,17 +33,55 @@ func GenerateToken(payload JWTPayload) (string, error) {
|
|||||||
return token.SignedString(MySecret)
|
return token.SignedString(MySecret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GenerateAccessTokenAndRefreshToken generates a JWT token with the given payload, and returns the accessToken and refreshToken
|
||||||
|
func GenerateAccessTokenAndRefreshToken(payload JWTPayload) (string, string, int64) {
|
||||||
|
MySecret = []byte(global.CONFIG.JWT.Secret)
|
||||||
|
// accessToken 的数据
|
||||||
|
accessClaims := JWTClaims{
|
||||||
|
JWTPayload: payload,
|
||||||
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 2)),
|
||||||
|
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||||
|
NotBefore: jwt.NewNumericDate(time.Now()),
|
||||||
|
Issuer: global.CONFIG.JWT.Issuer,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
refreshClaims := JWTClaims{
|
||||||
|
JWTPayload: payload,
|
||||||
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24 * 7)), // 7天
|
||||||
|
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||||
|
NotBefore: jwt.NewNumericDate(time.Now()),
|
||||||
|
Issuer: global.CONFIG.JWT.Issuer,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
accessToken := jwt.NewWithClaims(jwt.SigningMethodHS256, accessClaims)
|
||||||
|
refreshToken := jwt.NewWithClaims(jwt.SigningMethodHS256, refreshClaims)
|
||||||
|
accessTokenString, err := accessToken.SignedString(MySecret)
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Error(err)
|
||||||
|
return "", "", 0
|
||||||
|
}
|
||||||
|
refreshTokenString, err := refreshToken.SignedString(MySecret)
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Error(err)
|
||||||
|
return "", "", 0
|
||||||
|
}
|
||||||
|
return accessTokenString, refreshTokenString, refreshClaims.ExpiresAt.Time.Unix()
|
||||||
|
}
|
||||||
|
|
||||||
// ParseToken parses a JWT token and returns the payload
|
// ParseToken parses a JWT token and returns the payload
|
||||||
func ParseToken(tokenString string) (*JWTPayload, error) {
|
func ParseToken(tokenString string) (*JWTPayload, bool, error) {
|
||||||
|
MySecret = []byte(global.CONFIG.JWT.Secret)
|
||||||
token, err := jwt.ParseWithClaims(tokenString, &JWTClaims{}, func(token *jwt.Token) (interface{}, error) {
|
token, err := jwt.ParseWithClaims(tokenString, &JWTClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||||||
return MySecret, nil
|
return MySecret, nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Error(err)
|
global.LOG.Error(err)
|
||||||
return nil, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
if claims, ok := token.Claims.(*JWTClaims); ok && token.Valid {
|
if claims, ok := token.Claims.(*JWTClaims); ok && token.Valid {
|
||||||
return &claims.JWTPayload, nil
|
return &claims.JWTPayload, true, nil
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user