PHP到AI+Go程序员转型:目录更新与token系统完善
上一期我们探讨了优化细节与网络请求封装的方法,本期继续推进——重点介绍目录结构更新和token系统的完善。在此之前,先分享一个有意思的小插曲。 对AI的小考验 在动手完善token系统之前,我特意给AI出了一道题:token作为管理员身份令牌,计划使用UUID v7生成值,那么入库时还有必要加密吗?
上一期我们探讨了优化细节与网络请求封装的方法,本期继续推进——重点介绍目录结构更新和token系统的完善。在此之前,先分享一个有意思的小插曲。
对AI的小考验
在动手完善token系统之前,我特意给AI出了一道题:token作为管理员身份令牌,计划使用UUID v7生成值,那么入库时还有必要加密吗?
AI的回答很干脆:没必要。它搬出一套理论——UUID v7结构是48位时间戳加74位随机数,每秒能生成2^74个不重复值,暴力枚举128位UUID在计算上不现实。还列举了一堆“哈希的代价”、“真正该加哈希的场景”之类的说辞。
这有点不太对劲。加密最大的意义从来不是防暴力枚举,而是防拖库。token一旦泄露,黑客就能直接登录后台;但如果我们加了加密,黑客必须同时拿到程序源码和token密文才能渗透进来。怎么能省掉这道安全屏障?
所以最终拍板:token入库必须走SHA256加密。
目录结构更新
当前数据库初始化函数放在internal/database/database.go里。接下来要陆续加入token(多驱动设计)、captcha、upload(也是多驱动设计)等模块。按照原来的计划,目录结构会变成这样:
├── internal/
│ ├── handler/
│ ├── model/
│ ├── repository/
│ ├── router/
│ ├── database/
│ ├── captcha/
│ ├── upload/
│ ├── response/
│ ├── middleware/
│ └── service/
问题来了——database、token、captcha、upload这些模块偏向底层基础设施,跟handler、model这些业务层放在一起,确实有些违和。所以决定加一层infra目录,专门存放基础设施。调整后的结构如下:
├── internal/
│ ├── infra/
│ │ ├── token/
│ │ │ ├── driver
│ │ │ │ ├── database.go
│ │ │ │ └── redis.go
│ │ │ └─── token.go
│ │ ├── captcha/
│ │ └── upload/
│ ├── handler/
│ ├── model/
│ ├── repository/
│ ├── router/
│ ├── response/
│ ├── middleware/
│ └── service/
把database、token、captcha、upload这类底层模块移入infra。至于router和response——router是业务入口,response算是业务出口,都是可移可不移的类型,最终选择留在原地不动。
另外,配置解析逻辑(config/config.go文件,不是yaml配置文件)也跟着移入了infra目录,最终路径是internal/infra/config/config.go。这种操作在AI时代就是一句话的事儿,基本不会翻车,最多全项目搜一下/config确认就行。不过config/*.yaml文件不用动——运行时配置放在项目根目录的/config下,是社区标准的做法。
完善token系统
token系统的规划如下:
- 在
internal/model/common.go建立Token模型,字段包括token、type(字符串)、user_id、创建时间、过期时间,每个字段带中文注释 - 在
internal/infra/token/token.go建立token管理接口和结构体,采用多驱动模式。所有驱动放在internal/infra/token/driver目录下,一个驱动一个文件。目前只实现database一种驱动 - 增加
token.driver配置项,默认值database。token.go读取驱动配置并返回对应的驱动实例 - 驱动需要实现
Create、Get、Delete、Clear(删除指定会员指定类型的所有token)四个方法。管理器结构体额外实现Check方法——通过Get读取token信息后检查是否过期 - token入库前走SHA256加密
目前还没引入额外的全局秘钥(后续可能会考虑),也没用“SHA256索引+bcrypt校验”双字段方案。不过配合验权接口的节流逻辑,即便token的SHA256泄露了,抗爆破能力依然够用。
把这些规划交给Claude Code(cc),最终生成的核心代码如下:
# config/config.yaml 增加 token 驱动配置,目前只实现了 database 驱动
# 未来可以增加 redis 等驱动,得益于 AI 的帮助,加驱动基本上只需要一句话
token:
driver: database
// internal/model/common.go 文件,用于存放 captcha、area 等公共模型
// Token 令牌模型,用于存储各类用户令牌
type Token struct {
Token string `gorm:"comment:令牌;type:varchar(64);primaryKey" json:"-"`
Type string `gorm:"comment:令牌类型;type:varchar(32);not null" json:"type"`
UserID uint `gorm:"comment:用户ID;not null;index" json:"user_id"`
CreatedAt time.Time `gorm:"comment:创建时间" json:"created_at"`
ExpiredAt time.Time `gorm:"comment:过期时间;not null;index" json:"expired_at"`
}
// internal/infra/token/token.go 文件,用于存放 token 管理接口和结构体
package token
import (
"context"
"crypto/sha256"
"fmt"
"sync"
"time"
"ai-go-mall/internal/infra/config"
"ai-go-mall/internal/infra/token/driver"
"ai-go-mall/internal/model"
)
// Driver 令牌存储驱动接口
type Driver interface {
Create(ctx context.Context, token *model.Token) error
Get(ctx context.Context, token string) (*model.Token, error)
Delete(ctx context.Context, token string) error
Clear(ctx context.Context, userID uint, tokenType string) error
}
// Manager 令牌管理器
type Manager struct {
driver Driver
}
// NewManager 创建令牌管理器
func NewManager(driver Driver) *Manager {
return &Manager{driver: driver}
}
// Create 创建令牌,入库前自动对 Token 做 SHA256
func (m *Manager) Create(ctx context.Context, token *model.Token) error {
token.Token = sha256Hex(token.Token)
return m.driver.Create(ctx, token)
}
// Get 获取令牌信息
func (m *Manager) Get(ctx context.Context, token string) (*model.Token, error) {
return m.driver.Get(ctx, sha256Hex(token))
}
// Check 检查令牌是否存在且未过期
func (m *Manager) Check(ctx context.Context, token string) bool {
t, err := m.Get(ctx, token)
if err != nil || t == nil {
return false
}
return time.Now().Before(t.ExpiredAt)
}
// Delete 删除令牌
func (m *Manager) Delete(ctx context.Context, token string) error {
return m.driver.Delete(ctx, sha256Hex(token))
}
// Clear 清除指定用户指定类型的所有令牌
func (m *Manager) Clear(ctx context.Context, userID uint, tokenType string) error {
return m.driver.Clear(ctx, userID, tokenType)
}
// sha256Hex 返回 raw 的 SHA256 十六进制字符串
func sha256Hex(raw string) string {
sum := sha256.Sum256([]byte(raw))
return fmt.Sprintf("%x", sum)
}
// ==================== 全局单例 ====================
var (
instance *Manager
once sync.Once
)
// Instance 返回全局令牌管理器实例,首次调用时根据配置自动初始化
func Instance() *Manager {
once.Do(func() {
instance = NewManager(newDriver(config.Get().Token.Driver))
})
return instance
}
// newDriver 根据配置创建存储驱动
func newDriver(name string) Driver {
switch name {
default:
return driver.NewDatabase()
}
}
// internal/infra/token/driver/database.go 文件,token 数据库驱动
package driver
import (
"context"
"errors"
"ai-go-mall/internal/infra/database"
"ai-go-mall/internal/model"
"gorm.io/gorm"
)
// Database 基于关系型数据库的令牌驱动
type Database struct{}
// NewDatabase 创建数据库令牌驱动
func NewDatabase() *Database {
return &Database{}
}
// Create 创建令牌
func (d *Database) Create(ctx context.Context, t *model.Token) error {
return gorm.G[model.Token](database.DB()).Create(ctx, t)
}
// Get 获取令牌信息
func (d *Database) Get(ctx context.Context, token string) (*model.Token, error) {
t, err := gorm.G[model.Token](database.DB()).
Where("token = ?", token).
First(ctx)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &t, nil
}
// Delete 删除令牌
func (d *Database) Delete(ctx context.Context, token string) error {
_, err := gorm.G[model.Token](database.DB()).Where("token = ?", token).Delete(ctx)
return err
}
// Clear 清除指定用户指定类型的所有令牌
func (d *Database) Clear(ctx context.Context, userID uint, tokenType string) error {
_, err := gorm.G[model.Token](database.DB()).
Where("user_id = ? AND type = ?", userID, tokenType).
Delete(ctx)
return err
}
一段小总结:目录结构本次调整幅度不算大,主要是为后续多个基础设施模块铺平了道路。token系统的核心逻辑已经跑通,尤其是SHA256加密入库和Check过期检查,这两个点是后续所有鉴权流程的基础。下一期会聊中间件整合和验权接口的联调,感兴趣的朋友可以先思考一下:token管理器已经配好了,验权中间件该怎么做才能既安全又不显得笨重?
你是一名 AI 行业编辑,请围绕下面这条热点输出一份资讯解读:
热点:PHP到AI+Go程序员转型:目录更新与token系统完善要求:
1. 先用一句话解释这条热点在讲什么
2. 再总结它为什么重要
3. 说明会影响哪些 AI 产品或内容方向
4. 最后给出 3 个适合资讯站使用的标题
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
相关热点要在MyEclipse中让Java实体类自动对应数据库表结构,同时又想避免编写繁杂的XML映射文件,启用注解映射是必经之路。这个需求听起来简单,但实际操作中稍不注意就容易踩坑——比如生成的POJO缺少@Entity、@Table等关键注解,或者驱动版本不兼容导致连接失败。下面将几个核心步骤逐一拆解,
讯飞听见在区分多人发言方面,其实并不神秘。其核心依赖声纹识别、说话人管理以及智能上下文建模三项技术的协同工作,而非简单依靠音量大小或停顿长短进行切割。只要正确设置并规范录入声纹,即便面对三人以上的轮流发言、语速较快甚至偶尔重叠的情况,系统也能稳定地将每句话准确标注到对应发言人,帮助用户高效整理会议记
在背景噪音较大的环境下,语音转写的准确率往往会明显下降。尽管讯飞听见并没有提供所谓的“一键降噪”按钮——你无法通过单一开关自动清除所有干扰——但它的应对策略是前置优化 + 模型适配 + 后期校正,并非依赖后期滤波一种方式,而是从录音源头、识别模型与人工干预三个环节协同发力,以实现更可靠的转写效果。
Gamma AI的演示文稿编辑能力远不止生成初稿这么基础。如果你已经用它搭建好幻灯片框架,却希望在不重写整页的前提下快速调整某页文案语气、更换图表类型,或让某个节点支持点击跳转——这些操作都可以在侧边栏的AI设计助手中实时完成,无需退出编辑模式或切换其他工具。下面直接拆解具体操作流程。 先交代一个前
- 日榜
- 周榜
- 月榜
热点快看
