'init'
This commit is contained in:
61
sc-lktx-backend/internal/common/utils/context.go
Normal file
61
sc-lktx-backend/internal/common/utils/context.go
Normal file
@@ -0,0 +1,61 @@
|
||||
// 从 gin.Context 提取中间件注入的数据 + 分页工具
|
||||
package utils
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// GetUserID 从 Context 获取用户 ID(支持 uint/float64/string 类型转换)
|
||||
func GetUserID(c *gin.Context) uint {
|
||||
userID, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
return 0
|
||||
}
|
||||
switch v := userID.(type) {
|
||||
case uint:
|
||||
return v
|
||||
case float64:
|
||||
return uint(v)
|
||||
case string:
|
||||
id, _ := strconv.ParseUint(v, 10, 64)
|
||||
return uint(id)
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// GetRoleCode 获取主角色编码
|
||||
func GetRoleCode(c *gin.Context) string {
|
||||
roleCode, exists := c.Get("role_code")
|
||||
if !exists {
|
||||
return ""
|
||||
}
|
||||
return roleCode.(string)
|
||||
}
|
||||
|
||||
// HasRole 检查当前用户是否为指定角色
|
||||
func HasRole(c *gin.Context, roleCode string) bool {
|
||||
return GetRoleCode(c) == roleCode
|
||||
}
|
||||
|
||||
// ParsePagination 解析分页参数,默认 page=1, pageSize=10, 最大 1000
|
||||
func ParsePagination(c *gin.Context) (page, pageSize int) {
|
||||
pageStr := c.DefaultQuery("page", "1")
|
||||
pageSizeStr := c.DefaultQuery("page_size", "10")
|
||||
page, _ = strconv.Atoi(pageStr)
|
||||
pageSize, _ = strconv.Atoi(pageSizeStr)
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize < 1 || pageSize > 1000 {
|
||||
pageSize = 10
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetOffset 计算 SQL offset
|
||||
func GetOffset(page, pageSize int) int {
|
||||
return (page - 1) * pageSize
|
||||
}
|
||||
101
sc-lktx-backend/internal/common/utils/jwt.go
Normal file
101
sc-lktx-backend/internal/common/utils/jwt.go
Normal file
@@ -0,0 +1,101 @@
|
||||
// JWT Token 生成与解析 + 业务工具函数
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
// JWTClaims JWT 载荷,包含用户 ID 和角色列表
|
||||
type JWTClaims struct {
|
||||
UserID uint `json:"user_id"`
|
||||
RoleCode string `json:"role_code"` // 角色(visitor/employee/guard)
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
// AdminJWTClaims 管理员 JWT 载荷
|
||||
type AdminJWTClaims struct {
|
||||
AdminID uint `json:"admin_id"`
|
||||
Account string `json:"account"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
// GenerateAdminToken 生成管理员 JWT
|
||||
func GenerateAdminToken(adminID uint, account string, secret string, expireHours int) (string, error) {
|
||||
claims := AdminJWTClaims{
|
||||
AdminID: adminID,
|
||||
Account: account,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(expireHours) * time.Hour)),
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
Issuer: "lktx-admin",
|
||||
},
|
||||
}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
return token.SignedString([]byte(secret))
|
||||
}
|
||||
|
||||
// ParseAdminToken 解析管理员 JWT
|
||||
func ParseAdminToken(tokenString string, secret string) (*AdminJWTClaims, error) {
|
||||
token, err := jwt.ParseWithClaims(tokenString, &AdminJWTClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||||
}
|
||||
return []byte(secret), nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if claims, ok := token.Claims.(*AdminJWTClaims); ok && token.Valid {
|
||||
return claims, nil
|
||||
}
|
||||
return nil, fmt.Errorf("invalid token")
|
||||
}
|
||||
|
||||
// GenerateToken 生成 JWT(单角色,兼容旧版)
|
||||
func GenerateToken(userID uint, roleCode string, secret string, expireHours int) (string, error) {
|
||||
claims := JWTClaims{
|
||||
UserID: userID,
|
||||
RoleCode: roleCode,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(expireHours) * time.Hour)),
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
Issuer: "lktx-mp",
|
||||
},
|
||||
}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
return token.SignedString([]byte(secret))
|
||||
}
|
||||
|
||||
// ParseToken 解析并验证 JWT
|
||||
func ParseToken(tokenString string, secret string) (*JWTClaims, error) {
|
||||
token, err := jwt.ParseWithClaims(tokenString, &JWTClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||||
}
|
||||
return []byte(secret), nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if claims, ok := token.Claims.(*JWTClaims); ok && token.Valid {
|
||||
return claims, nil
|
||||
}
|
||||
return nil, fmt.Errorf("invalid token")
|
||||
}
|
||||
|
||||
// GenerateInviteCode 生成 16 位随机邀请码
|
||||
func GenerateInviteCode() string {
|
||||
b := make([]byte, 8)
|
||||
rand.Read(b)
|
||||
return hex.EncodeToString(b)
|
||||
}
|
||||
|
||||
// GenerateQRCodeContent 生成二维码内容
|
||||
func GenerateQRCodeContent(appointmentID uint) string {
|
||||
return fmt.Sprintf("LKTX:APPT:%d:%d", appointmentID, time.Now().Unix())
|
||||
}
|
||||
22
sc-lktx-backend/internal/common/utils/validator.go
Normal file
22
sc-lktx-backend/internal/common/utils/validator.go
Normal file
@@ -0,0 +1,22 @@
|
||||
// 数据校验工具
|
||||
package utils
|
||||
|
||||
import "regexp"
|
||||
|
||||
// ValidatePhone 验证中国大陆手机号(1 开头 + 3-9 + 9 位数字)
|
||||
func ValidatePhone(phone string) bool {
|
||||
matched, _ := regexp.MatchString(`^1[3-9]\d{9}$`, phone)
|
||||
return matched
|
||||
}
|
||||
|
||||
// ValidateIDNumber 验证 18 位身份证号格式
|
||||
func ValidateIDNumber(idNumber string) bool {
|
||||
matched, _ := regexp.MatchString(`^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[\dXx]$`, idNumber)
|
||||
return matched
|
||||
}
|
||||
|
||||
// ValidateLicensePlate 验证中国大陆车牌号
|
||||
func ValidateLicensePlate(plate string) bool {
|
||||
matched, _ := regexp.MatchString(`^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤川青藏琼宁][A-HJ-NP-Z][A-HJ-NP-Z0-9]{4,5}[A-HJ-NP-Z0-9挂学警港澳]$`, plate)
|
||||
return matched
|
||||
}
|
||||
Reference in New Issue
Block a user