This commit is contained in:
Joe
2026-01-16 15:49:34 +08:00
commit 550d3e1f42
380 changed files with 62024 additions and 0 deletions
+187
View File
@@ -0,0 +1,187 @@
package commands
import (
"errors"
"strconv"
"strings"
"time"
"github.com/goravel/framework/contracts/console"
"github.com/goravel/framework/contracts/console/command"
"github.com/goravel/framework/facades"
"goravel/app/models"
"goravel/app/services"
"goravel/app/utils"
)
// # Admin用户 - 1小时后过期
// go run . artisan token:create 1 --expires=1h
// # 7天后过期
// go run . artisan token:create 1 --expires=7d
// # 使用简写
// go run . artisan token:create 1 -e=1h
// # 指定token名称
// go run . artisan token:create 1 --expires=7d --name=api-token
// # 创建永久token(不设置expires
// go run . artisan token:create 1
type CreateToken struct {
}
// Signature The name and signature of the console command.
func (receiver *CreateToken) Signature() string {
return "token:create"
}
// Description The console command description.
func (receiver *CreateToken) Description() string {
return "为指定管理员创建token(永久或指定过期时间)"
}
// Extend The console command extend.
func (receiver *CreateToken) Extend() command.Extend {
return command.Extend{
Category: "token",
Flags: []command.Flag{
&command.StringFlag{
Name: "expires",
Aliases: []string{"e"},
Usage: "过期时间,格式:1h(1小时)、24h(24小时)、7d(7天)等,不设置则创建永久token",
},
&command.StringFlag{
Name: "name",
Aliases: []string{"n"},
Value: "console-token",
Usage: "token名称",
},
},
}
}
// Handle Execute the console command.
func (receiver *CreateToken) Handle(ctx console.Context) error {
// 获取用户标识(ID或用户名)
userIdentifier := ctx.Argument(0)
if userIdentifier == "" {
return errors.New("请提供用户ID或用户名")
}
// 用户类型固定为 admin
userType := "admin"
// 获取过期时间选项
expiresStr := ctx.Option("expires")
var expiresAt *time.Time
if expiresStr != "" {
// 解析过期时间
duration, err := parseDuration(expiresStr)
if err != nil {
return errors.New("过期时间格式错误,请使用:1h(1小时)、24h(24小时)、7d(7天)等格式")
}
exp := time.Now().Add(duration)
expiresAt = &exp
}
// 如果 expiresStr 为空,expiresAt 为 nil,表示永久token
// 获取token名称
tokenName := ctx.Option("name")
if tokenName == "" {
tokenName = "console-token"
}
// 查询管理员
var admin models.Admin
var err error
// 尝试作为ID解析
if id, parseErr := strconv.ParseUint(userIdentifier, 10, 32); parseErr == nil {
// 作为ID查询
err = facades.Orm().Query().Where("id", uint(id)).First(&admin)
} else {
// 作为用户名查询
err = facades.Orm().Query().Where("username", userIdentifier).First(&admin)
}
if err != nil {
return errors.New("管理员不存在")
}
userID := admin.ID
username := admin.Username
// 创建token
tokenService := services.NewTokenServiceImpl()
// 命令行创建token时,浏览器、IP、操作系统信息为空
plainToken, accessToken, err := tokenService.CreateToken(userType, userID, tokenName, expiresAt, "", "", "", "")
if err != nil {
return errors.New("创建token失败: " + err.Error())
}
// 输出结果
ctx.Info("Token创建成功!")
ctx.Line("")
ctx.Info("用户信息:")
ctx.Line(" 类型: " + userType)
ctx.Line(" ID: " + strconv.FormatUint(uint64(userID), 10))
ctx.Line(" 用户名: " + username)
ctx.Line("")
ctx.Info("Token信息:")
ctx.Line(" 名称: " + accessToken.Name)
if accessToken.ExpiresAt != nil {
ctx.Line(" 过期时间: " + accessToken.ExpiresAt.Format(utils.DateTimeFormat))
} else {
ctx.Line(" 过期时间: 永久有效")
}
ctx.Line(" 创建时间: " + accessToken.CreatedAt.Format(utils.DateTimeFormat))
ctx.Line("")
ctx.Warning("请妥善保管以下token,它只会显示一次:")
ctx.Line("")
ctx.Line(plainToken)
ctx.Line("")
return nil
}
// parseDuration 解析时间字符串,支持 h(小时)、d(天)、m(分钟)等格式
func parseDuration(s string) (time.Duration, error) {
// 移除空格
s = strings.TrimSpace(s)
if len(s) == 0 {
return 0, errors.New("时间字符串为空")
}
// 获取最后一个字符作为单位
unit := s[len(s)-1:]
valueStr := s[:len(s)-1]
// 解析数值
value, err := strconv.ParseFloat(valueStr, 64)
if err != nil {
return 0, err
}
// 根据单位转换为duration
switch unit {
case "m", "M":
// 分钟
return time.Duration(value) * time.Minute, nil
case "h", "H":
// 小时
return time.Duration(value) * time.Hour, nil
case "d", "D":
// 天
return time.Duration(value) * 24 * time.Hour, nil
case "w", "W":
// 周
return time.Duration(value) * 7 * 24 * time.Hour, nil
default:
// 尝试直接解析为duration(如 "1h30m"
return time.ParseDuration(s)
}
}