Add register, login
This commit is contained in:
parent
d00e579458
commit
8d460c8e2e
58
database/admindb.sql
Normal file
58
database/admindb.sql
Normal 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)
|
||||
);
|
@ -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))
|
||||
|
@ -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,
|
||||
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)
|
||||
|
@ -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"`
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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=
|
||||
|
31
server/adminserver/model/session.go
Normal file
31
server/adminserver/model/session.go
Normal 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
|
||||
}
|
@ -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 {
|
||||
|
54
server/adminserver/token/jwt_maker.go
Normal file
54
server/adminserver/token/jwt_maker.go
Normal 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
|
||||
}
|
57
server/adminserver/token/paseto_maker.go
Normal file
57
server/adminserver/token/paseto_maker.go
Normal 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
|
||||
}
|
@ -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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user