Add register, login

This commit is contained in:
殷勇 2023-09-08 14:10:20 +08:00
parent d00e579458
commit 8d460c8e2e
12 changed files with 418 additions and 93 deletions

58
database/admindb.sql Normal file
View File

@ -0,0 +1,58 @@
drop table if exists t_users;
CREATE TABLE t_users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL
);
drop table if exists t_roles;
CREATE TABLE t_roles (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL UNIQUE
);
CREATE TABLE permissions (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL UNIQUE
);
drop table if exists t_permissions;
CREATE TABLE t_permissions (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL UNIQUE
);
drop table if exists t_user_roles;
CREATE TABLE t_user_roles (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
role_id INT
);
drop table if exists t_role_permissions;
CREATE TABLE t_role_permissions (
id INT AUTO_INCREMENT PRIMARY KEY,
role_id INT,
permission_id INT
);
drop table if exists t_actions;
create table t_actions
(
id int AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL UNIQUE
);
drop table if exists t_sessions;
create table if not exists t_sessions (
id bigint,
username varchar(255) not null default "",
refresh_token varchar(255) not null default "",
client_ip varchar(255) not null default "",
user_agent varchar(255) NOT NULL default "",
is_blocked tinyint not null default "0",
expires_at int not null default "0",
created_at int not null default "0",
primary key id(id),
unique key username(username)
);

View File

@ -12,8 +12,8 @@ import (
const (
authorizationHeaderKey = "authorization"
authorizationTypeBearer = "bearer"
authorizationTypeBasic = "basic"
authorizationTypeBearer = "bearer"
authorizationPayloadKey = "authorization_payload"
)
@ -33,11 +33,11 @@ func authMiddleware(tokenMaker token.Maker) gin.HandlerFunc {
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()
@ -45,6 +45,7 @@ func authMiddleware(tokenMaker token.Maker) gin.HandlerFunc {
}
}
// Use accounts from db
if authorizationType != authorizationTypeBearer {
err := fmt.Errorf("unsupported authorization type %s", authorizationType)
ctx.AbortWithStatusJSON(http.StatusUnauthorized, errorResponse(err))

View File

@ -1,6 +1,7 @@
package api
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/jmoiron/sqlx"
"main/token"
@ -13,9 +14,26 @@ type Server struct {
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
*/
var TokenSymmetricKey = "12345678901234567890123456789012"
func NewServer(store *sqlx.DB) (*Server, error) {
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()
@ -26,12 +44,13 @@ 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("/accounts", server.listAccounts)
authRoutes.GET("/guilds", server.listGuilds)
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)

View File

@ -8,18 +8,126 @@ import (
)
type createUserRequest struct {
Username string `json:"username" binding:"required,alphanum"`
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required,min=6"`
FullName string `json:"full_name" binding:"required"`
Email string `json:"email" binding:"required,email"`
}
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"`
FullName string `json:"full_name"`
Email string `json:"email"`
PasswordChangedAt time.Time `json:"password_changed_at"`
CreatedAt time.Time `json:"created_at"`
}
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
}
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
}
var createSessionParams model.Session
createSessionParams.Id = refreshPayload.ID
createSessionParams.Username = req.Username
createSessionParams.RefreshToken = refreshToken
createSessionParams.UserAgent = ctx.Request.UserAgent()
createSessionParams.ClientIp = ctx.ClientIP()
createSessionParams.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) {
@ -31,70 +139,6 @@ func (server *Server) listUsers(ctx *gin.Context) {
ctx.JSON(http.StatusOK, users)
}
func (server *Server) createUser(ctx *gin.Context) {
var req createUserRequest
if err := ctx.ShouldBindJSON(&req); err != nil {
ctx.JSON(http.StatusBadRequest, errorResponse(err))
return
}
rsp := ""
ctx.JSON(http.StatusOK, rsp)
}
type loginUserRequest struct {
Username string `json:"username" binding:"required,alphanum"`
Password string `json:"password" binding:"required,min=6"`
}
type loginUserResponse struct {
SessionID string `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 Account struct {
ID int64 `json:"id"`
Owner string `json:"owner"`
Balance int64 `json:"balance"`
Currency string `json:"currency"`
}
func (server *Server) welcome(ctx *gin.Context) {
ctx.JSON(http.StatusOK, "welcome")
}
func (server *Server) loginUser(ctx *gin.Context) {
ctx.JSON(http.StatusOK, "loginUser")
}
func (server *Server) createAccount(ctx *gin.Context) {
func (server *Server) getUser(ctx *gin.Context) {
}
func (server *Server) getAccount(ctx *gin.Context) {
}
func (server *Server) listAccounts(ctx *gin.Context) {
account1 := &Account{
1,
"2",
3,
"4",
}
account2 := &Account{
11,
"22",
33,
"44",
}
var accounts []*Account
accounts = append(accounts, account1)
accounts = append(accounts, account2)
ctx.JSON(http.StatusOK, accounts)
}

View File

@ -12,7 +12,7 @@ var db *sqlx.DB
func InitDB() {
var err error
dsn := "root:keji178@tcp(login-test.kingsome.cn:3306)/frienddb_dev_1?charset=utf8mb4&parseTime=True"
dsn := "root:keji178@tcp(login-test.kingsome.cn:3306)/admindb_dev?charset=utf8mb4&parseTime=True"
db, err = sqlx.Connect("mysql", dsn)
if err != nil {
f5.GetSysLog().Info("Failed to connect to the database err:%v \n", err)

View File

@ -18,6 +18,9 @@ require (
)
require (
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
github.com/aead/chacha20poly1305 v0.0.0-20201124145622-1a5aba2a8b29 // indirect
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect
github.com/bytedance/sonic v1.10.0 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.0 // indirect
@ -28,6 +31,7 @@ require (
github.com/go-playground/validator/v10 v10.15.3 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang-jwt/jwt/v5 v5.0.0 // indirect
github.com/gomodule/redigo v1.8.3 // indirect
github.com/jmoiron/sqlx v1.3.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
@ -36,11 +40,13 @@ require (
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/o1egl/paseto v1.0.0 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
golang.org/x/arch v0.5.0 // indirect
golang.org/x/crypto v0.12.0 // indirect
golang.org/x/crypto v0.13.0 // indirect
golang.org/x/net v0.14.0 // indirect
golang.org/x/sys v0.12.0 // indirect
golang.org/x/text v0.13.0 // indirect

View File

@ -1,3 +1,10 @@
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
github.com/aead/chacha20poly1305 v0.0.0-20170617001512-233f39982aeb/go.mod h1:UzH9IX1MMqOcwhoNOIjmTQeAxrFgzs50j4golQtXXxU=
github.com/aead/chacha20poly1305 v0.0.0-20201124145622-1a5aba2a8b29 h1:1DcvRPZOdbQRg5nAHt2jrc5QbV0AGuhDdfQI6gXjiFE=
github.com/aead/chacha20poly1305 v0.0.0-20201124145622-1a5aba2a8b29/go.mod h1:UzH9IX1MMqOcwhoNOIjmTQeAxrFgzs50j4golQtXXxU=
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 h1:52m0LGchQBBVqJRyYYufQuIbVqRawmubW3OFGqK1ekw=
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635/go.mod h1:lmLxL+FV291OopO93Bwf9fQLQeLyt33VJRUg5VJ30us=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
github.com/bytedance/sonic v1.10.0 h1:qtNZduETEIWJVIyDl01BeNxur2rW9OwTQ/yBqFRkKEk=
@ -30,6 +37,8 @@ github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfC
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE=
github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/gomodule/redigo v1.8.3 h1:HR0kYDX2RJZvAup8CsiJwxB4dTCSC0AaUq6S4SiLwUc=
github.com/gomodule/redigo v1.8.3/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
@ -55,13 +64,19 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/o1egl/paseto v1.0.0 h1:bwpvPu2au176w4IBlhbyUv/S5VPptERIA99Oap5qUd0=
github.com/o1egl/paseto v1.0.0/go.mod h1:5HxsZPmw/3RI2pAwGo1HhOOwSdvBpcuVzO7uDkm+CLU=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@ -78,12 +93,16 @@ github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZ
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.5.0 h1:jpGode6huXQxcskEIpOCvrU+tzo81b6+oFLUYXWtH/Y=
golang.org/x/arch v0.5.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=

View File

@ -0,0 +1,31 @@
package model
import (
"log"
"main/db"
"time"
)
type Session struct {
Id int64 `db:"id"`
Username string `db:"username"`
RefreshToken string `db:"refresh_token"`
UserAgent string `db:"user_agent"`
ClientIp string `db:"client_ip"`
ExpiresAt time.Time `db:"expires_at"`
}
func CreateSession(session *Session) (*Session, error) {
query := "INSERT 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.UserAgent, session.ClientIp, session.ExpiresAt)
if err != nil {
log.Printf("Error creating session: %v", err)
return nil, err
}
_, err = result.LastInsertId()
if err != nil {
log.Printf("Error getting last insert ID: %v", err)
return nil, err
}
return session, nil
}

View File

@ -6,17 +6,16 @@ import (
"main/db"
)
// User 结构体表示用户
type User struct {
AccountId string `db:"account_id"`
Username string `db:"name"`
Level int32 `db:"level"`
Id string `db:"id"`
Username string `db:"username"`
Password string `db:"password"`
}
// CreateUser 创建新用户
func CreateUser(user *User) (int64, error) {
query := "INSERT INTO users (username, email) VALUES (?, ?)"
result, err := db.GetDB().Exec(query, user.Username, user.Level)
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
@ -29,11 +28,10 @@ func CreateUser(user *User) (int64, error) {
return userID, nil
}
// GetUserByID 根据用户ID获取用户信息
func GetUserByID(userID int64) (*User, error) {
query := "SELECT id, username, email FROM users WHERE id = ?"
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, userID)
err := db.GetDB().Get(&user, query, username)
if err != nil {
if err == sql.ErrNoRows {
return nil, nil // 用户不存在
@ -46,8 +44,8 @@ func GetUserByID(userID int64) (*User, error) {
// UpdateUser 更新用户信息
func UpdateUser(user *User) error {
query := "UPDATE users SET username = ?, level = ? WHERE id = ?"
_, err := db.GetDB().Exec(query, user.Username, user.Level, user.AccountId)
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
@ -68,7 +66,7 @@ func DeleteUser(userID int64) error {
// ListUsers 获取所有用户列表
func ListUsers() ([]User, error) {
query := "SELECT account_id, name, level FROM t_user"
query := "SELECT id, username, password FROM t_users"
var users []User
err := db.GetDB().Select(&users, query)
if err != nil {

View File

@ -0,0 +1,54 @@
package token
import (
"fmt"
"github.com/golang-jwt/jwt/v5"
"time"
)
const minSecretKeySize = 32
type JWTMaker struct {
secretKey string
}
func NewJWTMaker(secretKey string) (Maker, error) {
if len(secretKey) < minSecretKeySize {
return nil, fmt.Errorf("invalid key size: must be at least %d characters", minSecretKeySize)
}
return &JWTMaker{secretKey}, nil
}
func (maker *JWTMaker) CreateToken(username string, duration time.Duration) (string, *Payload, error) {
payload, err := NewPayload(username, duration)
if err != nil {
return "", payload, err
}
jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, payload)
token, err := jwtToken.SignedString([]byte(maker.secretKey))
return token, payload, err
}
// VerifyToken checks if the token is valid or not
func (maker *JWTMaker) VerifyToken(token string) (*Payload, error) {
keyFunc := func(token *jwt.Token) (interface{}, error) {
_, ok := token.Method.(*jwt.SigningMethodHMAC)
if !ok {
return nil, ErrInvalidToken
}
return []byte(maker.secretKey), nil
}
jwtToken, err := jwt.ParseWithClaims(token, &Payload{}, keyFunc)
if err != nil {
return nil, ErrInvalidToken
}
payload, ok := jwtToken.Claims.(*Payload)
if !ok {
return nil, ErrInvalidToken
}
return payload, nil
}

View File

@ -0,0 +1,57 @@
package token
import (
"fmt"
"time"
"github.com/aead/chacha20poly1305"
"github.com/o1egl/paseto"
)
// PasetoMaker is a PASETO token maker
type PasetoMaker struct {
paseto *paseto.V2
symmetricKey []byte
}
// NewPasetoMaker creates a new PasetoMaker
func NewPasetoMaker(symmetricKey string) (Maker, error) {
if len(symmetricKey) != chacha20poly1305.KeySize {
return nil, fmt.Errorf("invalid key size: must be exactly %d characters", chacha20poly1305.KeySize)
}
maker := &PasetoMaker{
paseto: paseto.NewV2(),
symmetricKey: []byte(symmetricKey),
}
return maker, nil
}
// CreateToken creates a new token for a specific username and duration
func (maker *PasetoMaker) CreateToken(username string, duration time.Duration) (string, *Payload, error) {
payload, err := NewPayload(username, duration)
if err != nil {
return "", payload, err
}
token, err := maker.paseto.Encrypt(maker.symmetricKey, payload, nil)
return token, payload, err
}
// VerifyToken checks if the token is valid or not
func (maker *PasetoMaker) VerifyToken(token string) (*Payload, error) {
payload := &Payload{}
err := maker.paseto.Decrypt(token, maker.symmetricKey, payload, nil)
if err != nil {
return nil, ErrInvalidToken
}
err = payload.Valid()
if err != nil {
return nil, err
}
return payload, nil
}

View File

@ -3,6 +3,7 @@ package token
import (
"errors"
"f5"
"github.com/golang-jwt/jwt/v5"
"time"
)
@ -18,6 +19,13 @@ type Payload struct {
ExpiredAt time.Time `json:"expired_at"`
}
//type Payload struct {
// ID int64 `json:"id"`
// Username string `json:"username"`
// IssuedAt int64 `json:"issued_at"`
// ExpiredAt int64 `json:"expired_at"`
//}
func NewPayload(username string, duration time.Duration) (*Payload, error) {
tokenID := f5.GetApp().NewUuid()
payload := &Payload{
@ -35,3 +43,33 @@ func (payload *Payload) Valid() error {
}
return nil
}
func (p *Payload) GetExpirationTime() (*jwt.NumericDate, error) {
expirationTime := jwt.NewNumericDate(p.ExpiredAt)
return expirationTime, nil
}
func (p *Payload) GetIssuedAt() (*jwt.NumericDate, error) {
issuedAt := jwt.NewNumericDate(p.IssuedAt)
return issuedAt, nil
//return p.IssuedAt
}
func (p *Payload) GetNotBefore() (*jwt.NumericDate, error) {
now := jwt.NewNumericDate(time.Time{})
return now, nil
//return time.Time{} // 默认返回零值,或根据需求设置合适的值
}
func (p *Payload) GetIssuer() (string, error) {
return "your_issuer", nil // 可根据需求返回合适的签发者Issuer信息
}
func (p *Payload) GetSubject() (string, error) {
return p.Username, nil // 使用用户名作为主题Subject
}
func (p *Payload) GetAudience() (jwt.ClaimStrings, error) {
audience := "your_audience" // 根据需求设置合适的受众Audience信息
return jwt.ClaimStrings{audience}, nil
}