This commit is contained in:
aozhiwei 2023-09-29 15:50:09 +08:00
parent 6c1d10338a
commit 7e2a64c320
10 changed files with 33 additions and 623 deletions

View File

@ -1,2 +0,0 @@
package api

View File

@ -1,115 +0,0 @@
package api
import (
"f5"
"github.com/gin-gonic/gin"
"main/model"
"math/rand"
"net/http"
"q5"
)
func (server *Server) listGuilds(ctx *gin.Context) {
guilds, err := model.ListGuilds()
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to list guilds"})
return
}
ctx.JSON(http.StatusOK, guilds)
}
func randLeaderId() string {
randomNum := generateRandomNumber(100000, 999999)
return q5.ToString(randomNum)
}
type createGuildRequest struct {
Name string `json:"name" binding:"required"`
LeaderId string `json:"leader_id" binding:"required"`
}
func (server *Server) createGuild(ctx *gin.Context) {
var req createGuildRequest
if err := ctx.ShouldBindJSON(&req); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
var guild model.Guild
guild.GuildId = f5.GetApp().NewUuid()
guild.Name = req.Name
guild.LeaderId = randLeaderId()
autoId, err := model.CreateGuild(&guild)
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create guild"})
return
}
ctx.JSON(http.StatusCreated, gin.H{"autoId": autoId, "guildId": guild.GuildId})
}
type getGuildReq struct {
GuildId int64 `uri:"guild_id" binding:"required,min=1"`
}
func (server *Server) getGuild(ctx *gin.Context) {
var req getGuildReq
if err := ctx.ShouldBindUri(&req); err != nil {
ctx.JSON(http.StatusBadRequest, errorResponse(err))
return
}
guild, err := model.GetGuild(req.GuildId)
if err != nil {
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}
ctx.JSON(http.StatusOK, guild)
}
type deleteGuildReq struct {
GuildId int64 `uri:"guild_id" binding:"required,min=1"`
}
func (server *Server) deleteGuild(ctx *gin.Context) {
var req deleteGuildReq
if err := ctx.ShouldBindUri(&req); err != nil {
ctx.JSON(http.StatusBadRequest, errorResponse(err))
return
}
err := model.DeleteGuild(req.GuildId)
if err != nil {
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}
ctx.JSON(http.StatusOK, "OK")
}
type updateGuildNoticeReq struct {
GuildId int64 `uri:"guild_id" binding:"required,min=1"`
Notice int64 `uri:"notice" binding:"required,min=1"`
}
// TODO
func (server *Server) updateGuildNotice(ctx *gin.Context) {
var req deleteGuildReq
if err := ctx.ShouldBindUri(&req); err != nil {
ctx.JSON(http.StatusBadRequest, errorResponse(err))
return
}
err := model.DeleteGuild(req.GuildId)
if err != nil {
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}
ctx.JSON(http.StatusOK, "OK")
}
func generateRandomNumber(min, max int) int {
return rand.Intn(max-min+1) + min
}

View File

@ -1,65 +0,0 @@
package api
import (
"errors"
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"main/token"
)
const (
authorizationHeaderKey = "authorization"
authorizationTypeBasic = "basic"
authorizationTypeBearer = "bearer"
authorizationPayloadKey = "authorization_payload"
)
func authMiddleware(tokenMaker token.Maker) gin.HandlerFunc {
return func(ctx *gin.Context) {
authorizationHeader := ctx.GetHeader(authorizationHeaderKey)
if len(authorizationHeader) == 0 {
err := errors.New("authorization header is not provided")
ctx.AbortWithStatusJSON(http.StatusUnauthorized, errorResponse(err))
return
}
fields := strings.Fields(authorizationHeader)
if len(fields) < 2 {
err := errors.New("invalid authorization header format")
ctx.AbortWithStatusJSON(http.StatusUnauthorized, errorResponse(err))
return
}
// Use http basic
// Headers key: Authorization
// Headers value: Basic cm9vdDoxMjM0NTY=
authorizationType := strings.ToLower(fields[0])
if authorizationType == authorizationTypeBasic {
user, password, hasAuth := ctx.Request.BasicAuth()
if hasAuth && user == "root" && password == "123456" {
ctx.Next()
return
}
}
// Use accounts from db
if authorizationType != authorizationTypeBearer {
err := fmt.Errorf("unsupported authorization type %s", authorizationType)
ctx.AbortWithStatusJSON(http.StatusUnauthorized, errorResponse(err))
return
}
accessToken := fields[1]
payload, err := tokenMaker.VerifyToken(accessToken)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusUnauthorized, errorResponse(err))
return
}
ctx.Set(authorizationPayloadKey, payload)
ctx.Next()
}
}

View File

@ -1,69 +0,0 @@
package api
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/jmoiron/sqlx"
"main/token"
)
// Server serves HTTP requests for our banking service.
type Server struct {
store *sqlx.DB
tokenMaker token.Maker
router *gin.Engine
}
/*
Install
go get github.com/jmoiron/sqlx
go get -u github.com/golang-jwt/jwt/v5
go get -u github.com/o1egl/paseto
go get golang.org/x/crypto/bcrypt
*/
var TokenSymmetricKey = "12345678901234567890123456789012"
func NewServer(store *sqlx.DB) (*Server, error) {
// NewPasetoMaker or NewJWTMaker, First use NewPasetoMaker
tokenMaker, err := token.NewPasetoMaker(TokenSymmetricKey)
if err != nil {
return nil, fmt.Errorf("cannot create token maker: %w", err)
}
server := &Server{
store: store,
tokenMaker: tokenMaker,
}
server.setupRouter()
return server, nil
}
func (server *Server) setupRouter() {
router := gin.Default()
// Default routers
router.GET("/welcome", server.welcome)
router.POST("/create_user", server.createUser)
router.POST("/login", server.loginUser)
// Authentication routers
authRoutes := router.Group("/").Use(authMiddleware(server.tokenMaker))
authRoutes.GET("/users", server.listUsers)
authRoutes.GET("/users/:user_id", server.getUser)
authRoutes.GET("/guilds/:guild_id", server.getGuild)
authRoutes.POST("/guilds", server.createGuild)
authRoutes.DELETE("/guilds/:guild_id", server.deleteGuild)
server.router = router
}
func (server *Server) Start(address string) error {
return server.router.Run(address)
}
func errorResponse(err error) gin.H {
return gin.H{"error": err.Error()}
}

View File

@ -1,166 +0,0 @@
package api
import (
"fmt"
"github.com/gin-gonic/gin"
"main/model"
"net/http"
"time"
)
type createUserRequest struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required,min=6"`
}
type loginUserRequest struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required,min=6"`
}
type loginUserResponse struct {
SessionID int64 `json:"session_id"`
AccessToken string `json:"access_token"`
AccessTokenExpiresAt time.Time `json:"access_token_expires_at"`
RefreshToken string `json:"refresh_token"`
RefreshTokenExpiresAt time.Time `json:"refresh_token_expires_at"`
User userResponse `json:"user"`
}
type userResponse struct {
Username string `json:"username"`
}
func newUserResponse(user *model.User) userResponse {
return userResponse{
Username: user.Username,
}
}
type CreateUserParams struct {
Username string `json:"username"`
Password string `json:"password"`
}
func (server *Server) welcome(ctx *gin.Context) {
ctx.JSON(http.StatusOK, "welcome")
}
func (server *Server) createUser(ctx *gin.Context) {
var req createUserRequest
if err := ctx.ShouldBindJSON(&req); err != nil {
ctx.JSON(http.StatusBadRequest, errorResponse(err))
return
}
var createUserParams model.User
createUserParams.Username = req.Username
createUserParams.Password = req.Password
userId, err := model.CreateUser(&createUserParams)
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create user"})
return
}
ctx.JSON(http.StatusCreated, gin.H{"userId": userId, "userName": createUserParams.Username})
}
func (server *Server) loginUser(ctx *gin.Context) {
var req loginUserRequest
if err := ctx.ShouldBindJSON(&req); err != nil {
ctx.JSON(http.StatusBadRequest, errorResponse(err))
return
}
user, err := model.GetUserByUsername(req.Username)
if err != nil {
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}
if !CheckPassword(req.Password, user.Password) {
ctx.JSON(http.StatusUnauthorized, errorResponse(err))
return
}
// 检查用户是否已经登录,
// 1. 更新会话信息, 2. 终止旧会话, 3. 阻止新登录
hasSession := server.IsUserLoggedIn(req.Username)
if hasSession != nil {
if hasSession.ExpiresAt.After(time.Now()) {
err = fmt.Errorf("session not expired")
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}
}
accessTokenDuration, _ := time.ParseDuration("15m")
accessToken, accessPayload, err := server.tokenMaker.CreateToken(
user.Username,
accessTokenDuration,
)
if err != nil {
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}
refreshTokenDuration, _ := time.ParseDuration("24h")
refreshToken, refreshPayload, err := server.tokenMaker.CreateToken(
user.Username,
refreshTokenDuration,
)
if err != nil {
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}
createSessionParams := model.Session{
Id: refreshPayload.ID,
Username: refreshPayload.Username,
RefreshToken: refreshToken,
ClientIp: ctx.ClientIP(),
UserAgent: ctx.Request.UserAgent(),
ExpiresAt: refreshPayload.ExpiredAt,
}
session, err := model.CreateSession(&createSessionParams)
if err != nil {
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}
rsp := loginUserResponse{
SessionID: session.Id,
AccessToken: accessToken,
AccessTokenExpiresAt: accessPayload.ExpiredAt,
RefreshToken: refreshToken,
RefreshTokenExpiresAt: refreshPayload.ExpiredAt,
User: newUserResponse(user),
}
ctx.JSON(http.StatusOK, rsp)
}
func CheckPassword(password, hasPassword string) bool {
return password == hasPassword
}
func (server *Server) listUsers(ctx *gin.Context) {
users, err := model.ListUsers()
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to list users"})
return
}
ctx.JSON(http.StatusOK, users)
}
func (server *Server) getUser(ctx *gin.Context) {
}
func (server *Server) IsUserLoggedIn(username string) *model.Session {
session := model.GetSessionByUsername(username)
if session != nil {
return session
}
return nil
}

View File

@ -1,9 +1,9 @@
package main
import (
"adminsever/api"
"adminsever/db"
"f5"
//"adminsever/api"
//"adminsever/db"
//"f5"
"github.com/gin-gonic/gin"
"golang.org/x/sync/errgroup"
"net/http"
@ -42,6 +42,7 @@ func (this *GinMgr) router() http.Handler {
}
func runGinServer() {
/*
store := db.GetDB()
server, err := api.NewServer(store)
if err != nil {
@ -50,5 +51,5 @@ func runGinServer() {
err = server.Start("localhost:8080")
if err != nil {
f5.GetSysLog().Info("cannot start server err:%v \n", err)
}
}*/
}

View File

@ -1,82 +0,0 @@
package model
import (
"database/sql"
"log"
"main/db"
)
type Guild struct {
AutoId int64 `db:"idx"`
GuildId int64 `db:"guild_id"`
Name string `db:"name"`
LeaderId string `db:"leader_account_id"`
Avatar int32 `db:"avatar"`
Notice sql.NullString `db:"notice"`
JoinCond int32 `db:"join_cond"`
JoinCondValue int32 `db:"join_cond_value"`
TotalStars int32 `db:"total_stars"`
TotalKills int32 `db:"total_kills"`
ChickenDinners int32 `db:"chicken_dinners"`
MaxMembers int32 `db:"max_members"`
}
func CreateGuild(guild *Guild) (int64, error) {
query := "INSERT INTO t_guild (guild_id, name, leader_account_id) VALUES (?, ?, ?)"
result, err := db.GetDB().Exec(query, guild.GuildId, guild.Name, guild.LeaderId)
if err != nil {
log.Printf("Error creating guild: %v", err)
return 0, err
}
autoId, err := result.LastInsertId()
if err != nil {
log.Printf("Error getting last insert ID: %v", err)
return 0, err
}
return autoId, nil
}
func GetGuild(guildId int64) (*Guild, error) {
query := "SELECT idx, guild_id, name, leader_account_id, avatar, notice, join_cond, join_cond_value, total_stars, total_kills, chicken_dinners, max_members FROM t_guild WHERE guild_id = ?"
var guild Guild
err := db.GetDB().Get(&guild, query, guildId)
if err != nil {
if err == sql.ErrNoRows {
return nil, nil // 不存在
}
log.Printf("Error getting guild by ID: %v", err)
return nil, err
}
return &guild, nil
}
func UpdateGuildNotice(guild *Guild) error {
query := "UPDATE t_guild SET `notice`=? WHERE guild_id = ?"
_, err := db.GetDB().Exec(query, guild.Notice, guild.GuildId)
if err != nil {
log.Printf("Error updating guild notice: %v", err)
return err
}
return nil
}
func DeleteGuild(guildId int64) error {
query := "UPDATE t_guild SET `is_deleted`=? WHERE guild_id = ?"
_, err := db.GetDB().Exec(query, 1, guildId)
if err != nil {
log.Printf("Error deleting guild: %v", err)
return err
}
return nil
}
func ListGuilds() ([]Guild, error) {
query := "SELECT idx, guild_id, name, leader_account_id, avatar, notice, join_cond, join_cond_value, total_stars, total_kills, chicken_dinners, max_members FROM t_guild WHERE is_deleted=0"
var guilds []Guild
err := db.GetDB().Select(&guilds, query)
if err != nil {
log.Printf("Error listing users: %v", err)
return nil, err
}
return guilds, nil
}

View File

@ -1,43 +0,0 @@
package model
import (
"database/sql"
"main/db"
"time"
)
type Session struct {
Id int64 `db:"id"`
Username string `db:"username"`
RefreshToken string `db:"refresh_token"`
ClientIp string `db:"client_ip"`
UserAgent string `db:"user_agent"`
ExpiresAt time.Time `db:"expires_at"`
}
func CreateSession(session *Session) (*Session, error) {
query := "REPLACE INTO t_sessions (id, username, refresh_token, client_ip, user_agent, expires_at) VALUES (?, ?, ?, ?, ?, ?)"
result, err := db.GetDB().Exec(query, session.Id, session.Username, session.RefreshToken, session.ClientIp, session.UserAgent, session.ExpiresAt)
if err != nil {
return nil, err
}
_, err = result.LastInsertId()
if err != nil {
return nil, err
}
return session, nil
}
func GetSessionByUsername(username string) *Session {
query := "SELECT id, username, refresh_token, client_ip, user_agent, expires_at FROM t_sessions WHERE username = ?"
var session Session
err := db.GetDB().Get(&session, query, username)
if err != nil {
if err == sql.ErrNoRows {
return nil
}
return nil
}
return &session
}

View File

@ -0,0 +1,28 @@
package system
import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/gofrs/uuid/v5"
)
type SysUser struct {
global.GVA_MODEL
UUID uuid.UUID `json:"uuid" gorm:"index;comment:用户UUID"` // 用户UUID
Username string `json:"userName" gorm:"index;comment:用户登录名"` // 用户登录名
Password string `json:"-" gorm:"comment:用户登录密码"` // 用户登录密码
NickName string `json:"nickName" gorm:"default:系统用户;comment:用户昵称"` // 用户昵称
SideMode string `json:"sideMode" gorm:"default:dark;comment:用户侧边主题"` // 用户侧边主题
HeaderImg string `json:"headerImg" gorm:"default:https://qmplusimg.henrongyi.top/gva_header.jpg;comment:用户头像"` // 用户头像
BaseColor string `json:"baseColor" gorm:"default:#fff;comment:基础颜色"` // 基础颜色
ActiveColor string `json:"activeColor" gorm:"default:#1890ff;comment:活跃颜色"` // 活跃颜色
AuthorityId uint `json:"authorityId" gorm:"default:888;comment:用户角色ID"` // 用户角色ID
Authority SysAuthority `json:"authority" gorm:"foreignKey:AuthorityId;references:AuthorityId;comment:用户角色"`
Authorities []SysAuthority `json:"authorities" gorm:"many2many:sys_user_authority;"`
Phone string `json:"phone" gorm:"comment:用户手机号"` // 用户手机号
Email string `json:"email" gorm:"comment:用户邮箱"` // 用户邮箱
Enable int `json:"enable" gorm:"default:1;comment:用户是否被冻结 1正常 2冻结"` //用户是否被冻结 1正常 2冻结
}
func (SysUser) TableName() string {
return "t_sys_users"
}

View File

@ -1,77 +0,0 @@
package model
import (
"database/sql"
"log"
"main/db"
)
type User struct {
Id string `db:"id"`
Username string `db:"username"`
Password string `db:"password"`
}
// CreateUser 创建新用户
func CreateUser(user *User) (int64, error) {
query := "INSERT INTO t_users (username, password) VALUES (?, ?)"
result, err := db.GetDB().Exec(query, user.Username, user.Password)
if err != nil {
log.Printf("Error creating user: %v", err)
return 0, err
}
userID, err := result.LastInsertId()
if err != nil {
log.Printf("Error getting last insert ID: %v", err)
return 0, err
}
return userID, nil
}
func GetUserByUsername(username string) (*User, error) {
query := "SELECT id, username, password FROM t_users WHERE username = ?"
var user User
err := db.GetDB().Get(&user, query, username)
if err != nil {
if err == sql.ErrNoRows {
return nil, nil // 用户不存在
}
log.Printf("Error getting user by ID: %v", err)
return nil, err
}
return &user, nil
}
// UpdateUser 更新用户信息
func UpdateUser(user *User) error {
query := "UPDATE users SET username WHERE id = ?"
_, err := db.GetDB().Exec(query, user.Username, user.Id)
if err != nil {
log.Printf("Error updating user: %v", err)
return err
}
return nil
}
// DeleteUser 删除用户
func DeleteUser(userID int64) error {
query := "DELETE FROM users WHERE id = ?"
_, err := db.GetDB().Exec(query, userID)
if err != nil {
log.Printf("Error deleting user: %v", err)
return err
}
return nil
}
// ListUsers 获取所有用户列表
func ListUsers() ([]User, error) {
query := "SELECT id, username, password FROM t_users"
var users []User
err := db.GetDB().Select(&users, query)
if err != nil {
log.Printf("Error listing users: %v", err)
return nil, err
}
return users, nil
}