fix: 时间精度精确到秒 + 同步全部文档到最新状态
时间字段修正: - init.sql: 所有 TIMESTAMP 改为 TIMESTAMP(0),精确到秒 - GORM 模型: 所有时间字段添加 type:timestamp(0) tag - 已有数据库表通过 ALTER TABLE 修正列类型 文档同步(架构设计 + 实施步骤): - system-architecture.md: - auth 模块描述更新为"有状态 JWT Token 管理(Redis 存储)" - 开发环境端口 8080 → 8085 - phase1-foundation-and-auth.md: - Go 版本 1.22+ → 1.23+ - 常量命名更新为驼峰风格(UserStatusActive / RoleUser 等) - Task 4 完整重写:增加 token_store.go、TokenValidator 接口、有状态 JWT - Task 5 端口号 8080 → 8085,测试命令增加登出失效验证 - 依赖版本选择原则说明 Made-with: Cursor
This commit is contained in:
@@ -5,11 +5,11 @@ import "time"
|
|||||||
// Role 角色表模型,对应 auth_roles 表
|
// Role 角色表模型,对应 auth_roles 表
|
||||||
// 系统预置三种角色:user(普通用户)、admin(管理员)、super_admin(超级管理员)
|
// 系统预置三种角色:user(普通用户)、admin(管理员)、super_admin(超级管理员)
|
||||||
type Role struct {
|
type Role struct {
|
||||||
ID int `json:"id" gorm:"primaryKey;autoIncrement"` // 角色唯一标识,自增主键
|
ID int `json:"id" gorm:"primaryKey;autoIncrement"` // 角色唯一标识,自增主键
|
||||||
Code string `json:"code" gorm:"uniqueIndex;size:50;not null"` // 角色代码,全局唯一,如 user/admin/super_admin(对应 constants.RoleCode*)
|
Code string `json:"code" gorm:"uniqueIndex;size:50;not null"` // 角色代码,全局唯一,如 user/admin/super_admin(对应 constants.RoleCode*)
|
||||||
Name string `json:"name" gorm:"size:50;not null"` // 角色中文显示名称,如「普通用户」「管理员」
|
Name string `json:"name" gorm:"size:50;not null"` // 角色中文显示名称,如「普通用户」「管理员」
|
||||||
Description string `json:"description" gorm:"size:200;default:''"` // 角色描述说明,用于后台管理界面展示
|
Description string `json:"description" gorm:"size:200;default:''"` // 角色描述说明,用于后台管理界面展示
|
||||||
CreatedAt time.Time `json:"created_at" gorm:"not null;autoCreateTime"` // 创建时间,由 GORM 自动填充
|
CreatedAt time.Time `json:"created_at" gorm:"not null;autoCreateTime;type:timestamp(0)"` // 创建时间,由 GORM 自动填充,精确到秒
|
||||||
}
|
}
|
||||||
|
|
||||||
// TableName 指定数据库表名
|
// TableName 指定数据库表名
|
||||||
@@ -20,9 +20,9 @@ func (Role) TableName() string {
|
|||||||
// UserRole 用户角色关联表模型,对应 auth_user_roles 表
|
// UserRole 用户角色关联表模型,对应 auth_user_roles 表
|
||||||
// 采用联合主键(user_id + role_id),一个用户可拥有多个角色
|
// 采用联合主键(user_id + role_id),一个用户可拥有多个角色
|
||||||
type UserRole struct {
|
type UserRole struct {
|
||||||
UserID int64 `json:"user_id" gorm:"primaryKey"` // 关联的用户 ID,外键指向 auth_users.id
|
UserID int64 `json:"user_id" gorm:"primaryKey"` // 关联的用户 ID,外键指向 auth_users.id
|
||||||
RoleID int `json:"role_id" gorm:"primaryKey"` // 关联的角色 ID,外键指向 auth_roles.id
|
RoleID int `json:"role_id" gorm:"primaryKey"` // 关联的角色 ID,外键指向 auth_roles.id
|
||||||
CreatedAt time.Time `json:"created_at" gorm:"not null;autoCreateTime"` // 角色分配时间,由 GORM 自动填充
|
CreatedAt time.Time `json:"created_at" gorm:"not null;autoCreateTime;type:timestamp(0)"` // 角色分配时间,由 GORM 自动填充,精确到秒
|
||||||
}
|
}
|
||||||
|
|
||||||
// TableName 指定数据库表名
|
// TableName 指定数据库表名
|
||||||
|
|||||||
@@ -5,19 +5,19 @@ import "time"
|
|||||||
|
|
||||||
// User 用户主表模型,对应 auth_users 表
|
// User 用户主表模型,对应 auth_users 表
|
||||||
type User struct {
|
type User struct {
|
||||||
ID int64 `json:"id" gorm:"primaryKey;autoIncrement"` // 用户唯一标识,自增主键
|
ID int64 `json:"id" gorm:"primaryKey;autoIncrement"` // 用户唯一标识,自增主键
|
||||||
Username string `json:"username" gorm:"uniqueIndex;size:50;not null"` // 登录用户名,全局唯一
|
Username string `json:"username" gorm:"uniqueIndex;size:50;not null"` // 登录用户名,全局唯一
|
||||||
Email string `json:"email" gorm:"uniqueIndex;size:100;not null"` // 邮箱地址,全局唯一,用于登录和找回密码
|
Email string `json:"email" gorm:"uniqueIndex;size:100;not null"` // 邮箱地址,全局唯一,用于登录和找回密码
|
||||||
PasswordHash string `json:"-" gorm:"column:password_hash;size:255;not null"` // bcrypt 加密后的密码哈希,JSON 序列化时隐藏
|
PasswordHash string `json:"-" gorm:"column:password_hash;size:255;not null"` // bcrypt 加密后的密码哈希,JSON 序列化时隐藏
|
||||||
Nickname string `json:"nickname" gorm:"size:50;not null;default:''"` // 用户昵称,用于页面展示,允许重复
|
Nickname string `json:"nickname" gorm:"size:50;not null;default:''"` // 用户昵称,用于页面展示,允许重复
|
||||||
Avatar string `json:"avatar" gorm:"size:500;not null;default:''"` // 头像 URL 地址,为空则使用默认头像
|
Avatar string `json:"avatar" gorm:"size:500;not null;default:''"` // 头像 URL 地址,为空则使用默认头像
|
||||||
Gender int `json:"gender" gorm:"not null;default:0"` // 性别:0=未知, 1=男, 2=女(对应 constants.Gender*)
|
Gender int `json:"gender" gorm:"not null;default:0"` // 性别:0=未知, 1=男, 2=女(对应 constants.Gender*)
|
||||||
Phone *string `json:"phone" gorm:"size:20"` // 手机号,可选字段,指针类型允许 NULL
|
Phone *string `json:"phone" gorm:"size:20"` // 手机号,可选字段,指针类型允许 NULL
|
||||||
Status int `json:"status" gorm:"not null;default:1"` // 账号状态:1=正常, 2=禁用, 3=注销(对应 constants.UserStatus*)
|
Status int `json:"status" gorm:"not null;default:1"` // 账号状态:1=正常, 2=禁用, 3=注销(对应 constants.UserStatus*)
|
||||||
LastLoginAt *time.Time `json:"last_login_at"` // 最后登录时间,首次注册时为 NULL
|
LastLoginAt *time.Time `json:"last_login_at" gorm:"type:timestamp(0)"` // 最后登录时间,首次注册时为 NULL
|
||||||
LastLoginIP *string `json:"last_login_ip" gorm:"column:last_login_ip;size:50"` // 最后登录 IP 地址,用于安全审计
|
LastLoginIP *string `json:"last_login_ip" gorm:"column:last_login_ip;size:50"` // 最后登录 IP 地址,用于安全审计
|
||||||
CreatedAt time.Time `json:"created_at" gorm:"not null;autoCreateTime"` // 账号创建时间,由 GORM 自动填充
|
CreatedAt time.Time `json:"created_at" gorm:"not null;autoCreateTime;type:timestamp(0)"` // 账号创建时间,由 GORM 自动填充,精确到秒
|
||||||
UpdatedAt time.Time `json:"updated_at" gorm:"not null;autoUpdateTime"` // 最后更新时间,由 GORM 自动更新
|
UpdatedAt time.Time `json:"updated_at" gorm:"not null;autoUpdateTime;type:timestamp(0)"` // 最后更新时间,由 GORM 自动更新,精确到秒
|
||||||
}
|
}
|
||||||
|
|
||||||
// TableName 指定数据库表名
|
// TableName 指定数据库表名
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ CREATE TABLE auth_users (
|
|||||||
gender SMALLINT NOT NULL DEFAULT 0,
|
gender SMALLINT NOT NULL DEFAULT 0,
|
||||||
phone VARCHAR(20) DEFAULT NULL,
|
phone VARCHAR(20) DEFAULT NULL,
|
||||||
status SMALLINT NOT NULL DEFAULT 1,
|
status SMALLINT NOT NULL DEFAULT 1,
|
||||||
last_login_at TIMESTAMP DEFAULT NULL,
|
last_login_at TIMESTAMP(0) DEFAULT NULL,
|
||||||
last_login_ip VARCHAR(50) DEFAULT NULL,
|
last_login_ip VARCHAR(50) DEFAULT NULL,
|
||||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
created_at TIMESTAMP(0) NOT NULL DEFAULT NOW(),
|
||||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
updated_at TIMESTAMP(0) NOT NULL DEFAULT NOW()
|
||||||
);
|
);
|
||||||
|
|
||||||
COMMENT ON TABLE auth_users IS '用户主表,存储所有用户信息(普通用户与管理员共用)';
|
COMMENT ON TABLE auth_users IS '用户主表,存储所有用户信息(普通用户与管理员共用)';
|
||||||
@@ -47,7 +47,7 @@ CREATE TABLE auth_roles (
|
|||||||
code VARCHAR(50) UNIQUE NOT NULL,
|
code VARCHAR(50) UNIQUE NOT NULL,
|
||||||
name VARCHAR(50) NOT NULL,
|
name VARCHAR(50) NOT NULL,
|
||||||
description VARCHAR(200) DEFAULT '',
|
description VARCHAR(200) DEFAULT '',
|
||||||
created_at TIMESTAMP NOT NULL DEFAULT NOW()
|
created_at TIMESTAMP(0) NOT NULL DEFAULT NOW()
|
||||||
);
|
);
|
||||||
|
|
||||||
COMMENT ON TABLE auth_roles IS '角色表,定义系统中所有角色类型';
|
COMMENT ON TABLE auth_roles IS '角色表,定义系统中所有角色类型';
|
||||||
@@ -70,7 +70,7 @@ INSERT INTO auth_roles (code, name, description) VALUES
|
|||||||
CREATE TABLE auth_user_roles (
|
CREATE TABLE auth_user_roles (
|
||||||
user_id BIGINT NOT NULL REFERENCES auth_users(id),
|
user_id BIGINT NOT NULL REFERENCES auth_users(id),
|
||||||
role_id INT NOT NULL REFERENCES auth_roles(id),
|
role_id INT NOT NULL REFERENCES auth_roles(id),
|
||||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
created_at TIMESTAMP(0) NOT NULL DEFAULT NOW(),
|
||||||
PRIMARY KEY (user_id, role_id)
|
PRIMARY KEY (user_id, role_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ EchoChat 采用 **「精简单体 + 媒体微服务」** 架构,核心思想
|
|||||||
|
|
||||||
| 模块 | 职责 |
|
| 模块 | 职责 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| auth | 用户注册/登录、JWT Token 管理、RBAC 角色权限(当前粗粒度 3 角色,预留细粒度权限点扩展) |
|
| auth | 用户注册/登录、有状态 JWT Token 管理(Redis 存储)、RBAC 角色权限(当前粗粒度 3 角色,预留细粒度权限点扩展) |
|
||||||
| im | 即时消息收发、会话管理、消息存储 |
|
| im | 即时消息收发、会话管理、消息存储 |
|
||||||
| contact | 好友关系管理、好友分组 |
|
| contact | 好友关系管理、好友分组 |
|
||||||
| meeting | 会议创建/管理、信令转发、mediasoup 资源编排 |
|
| meeting | 会议创建/管理、信令转发、mediasoup 资源编排 |
|
||||||
@@ -236,7 +236,7 @@ mediasoup C++ SFU 的 **"遥控器"**,不懂业务、不懂用户、只懂媒
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
services:
|
services:
|
||||||
go-service: # Go 后端 → :8080
|
go-service: # Go 后端 → :8085
|
||||||
media-server: # mediasoup Node → :3000 + :40000-40100/udp
|
media-server: # mediasoup Node → :3000 + :40000-40100/udp
|
||||||
postgres: # PostgreSQL 17 → :5432
|
postgres: # PostgreSQL 17 → :5432
|
||||||
redis: # Redis 7 → :6379
|
redis: # Redis 7 → :6379
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
**架构:** Go 单体模块化服务 + uniapp 前台 + Vue3 管理端 + PostgreSQL + Redis,Docker Compose 编排。
|
**架构:** Go 单体模块化服务 + uniapp 前台 + Vue3 管理端 + PostgreSQL + Redis,Docker Compose 编排。
|
||||||
|
|
||||||
**技术栈:** Go 1.22+ (Gin + GORM + Wire + zap) / Vue 3.4+ / uniapp 3.0 / Element Plus / PostgreSQL 17 / Redis 7 / Docker Compose
|
**技术栈:** Go 1.23+ (Gin + GORM + Wire + zap) / Vue 3.4+ / uniapp 3.0 / Element Plus / PostgreSQL 17 / Redis 7 / Docker Compose
|
||||||
|
|
||||||
**设计文档:** `docs/plans/2026-02-27-echochat-system-design.md`
|
**设计文档:** `docs/plans/2026-02-27-echochat-system-design.md`
|
||||||
|
|
||||||
@@ -319,7 +319,7 @@ Run: `cd backend/go-service && go mod tidy`
|
|||||||
**Step 10: 运行验证**
|
**Step 10: 运行验证**
|
||||||
|
|
||||||
Run: `cd backend/go-service && go run cmd/server/main.go`
|
Run: `cd backend/go-service && go run cmd/server/main.go`
|
||||||
Expected: 服务启动在 :8080,访问 /health 返回 200
|
Expected: 服务启动在 :8085,访问 /health 返回 200
|
||||||
|
|
||||||
**Step 11: Commit**
|
**Step 11: Commit**
|
||||||
|
|
||||||
@@ -344,18 +344,18 @@ git commit -m "feat(backend): Go 服务骨架(配置、日志、数据库、
|
|||||||
**Step 1: 创建用户状态和角色常量**
|
**Step 1: 创建用户状态和角色常量**
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// app/constants/user_status.go
|
// app/constants/user_status.go — 驼峰命名,符合 Go 社区规范
|
||||||
const (
|
const (
|
||||||
USER_STATUS_ACTIVE = 1 // 正常
|
UserStatusActive = 1 // 正常
|
||||||
USER_STATUS_DISABLED = 2 // 禁用
|
UserStatusDisabled = 2 // 禁用
|
||||||
USER_STATUS_DELETED = 3 // 注销
|
UserStatusDeleted = 3 // 注销
|
||||||
)
|
)
|
||||||
|
|
||||||
// app/constants/role_code.go
|
// app/constants/role_code.go
|
||||||
const (
|
const (
|
||||||
ROLE_USER = "user"
|
RoleUser = "user"
|
||||||
ROLE_ADMIN = "admin"
|
RoleAdmin = "admin"
|
||||||
ROLE_SUPER_ADMIN = "super_admin"
|
RoleSuperAdmin = "super_admin"
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -419,6 +419,7 @@ git commit -m "feat(auth): 用户/角色模型与数据访问层"
|
|||||||
|
|
||||||
**Files:**
|
**Files:**
|
||||||
- Create: `backend/go-service/app/auth/service/auth_service.go`
|
- Create: `backend/go-service/app/auth/service/auth_service.go`
|
||||||
|
- Create: `backend/go-service/app/auth/service/token_store.go`
|
||||||
- Create: `backend/go-service/app/dto/auth_dto.go`
|
- Create: `backend/go-service/app/dto/auth_dto.go`
|
||||||
- Create: `backend/go-service/pkg/utils/jwt.go`
|
- Create: `backend/go-service/pkg/utils/jwt.go`
|
||||||
- Create: `backend/go-service/pkg/utils/password.go`
|
- Create: `backend/go-service/pkg/utils/password.go`
|
||||||
@@ -427,85 +428,87 @@ git commit -m "feat(auth): 用户/角色模型与数据访问层"
|
|||||||
**Step 1: 创建密码工具**
|
**Step 1: 创建密码工具**
|
||||||
|
|
||||||
创建 `pkg/utils/password.go`:
|
创建 `pkg/utils/password.go`:
|
||||||
- `HashPassword(password)` — bcrypt 加密
|
- `HashPassword(password)` — bcrypt 加密(`golang.org/x/crypto/bcrypt`,复用 go.mod 已有的兼容版本)
|
||||||
- `CheckPassword(password, hash)` — 密码校验
|
- `CheckPassword(password, hash)` — 密码校验
|
||||||
|
|
||||||
**Step 2: 创建 JWT 工具**
|
**Step 2: 创建 JWT 工具**
|
||||||
|
|
||||||
创建 `pkg/utils/jwt.go`:
|
创建 `pkg/utils/jwt.go`(使用 `github.com/golang-jwt/jwt/v5@v5.2.1`,兼容 Go 1.23):
|
||||||
- `GenerateToken(userID, username)` — 生成 Access Token
|
- `GenerateToken(cfg, userID, username, roles)` — 生成 Access Token
|
||||||
- `GenerateRefreshToken(userID)` — 生成 Refresh Token
|
- `GenerateRefreshToken(cfg, userID)` — 生成 Refresh Token
|
||||||
- `ParseToken(tokenStr)` — 解析验证 Token
|
- `ParseToken(cfg, tokenStr)` — 解析验证 Token
|
||||||
- Claims 结构体包含 UserID, Username, Roles
|
- Claims 结构体包含 UserID, Username, Roles
|
||||||
|
|
||||||
|
> **依赖版本选择原则:** 优先选择兼容当前 Go 版本的包版本,不盲目拉取最新版,避免触发工具链升级。
|
||||||
|
|
||||||
**Step 3: 创建认证 DTO**
|
**Step 3: 创建认证 DTO**
|
||||||
|
|
||||||
创建 `app/dto/auth_dto.go`:
|
创建 `app/dto/auth_dto.go`:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type RegisterRequest struct {
|
|
||||||
Username string `json:"username" binding:"required,min=3,max=50"`
|
|
||||||
Email string `json:"email" binding:"required,email"`
|
|
||||||
Password string `json:"password" binding:"required,min=6,max=50"`
|
|
||||||
Nickname string `json:"nickname" binding:"max=50"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type LoginRequest struct {
|
|
||||||
Account string `json:"account" binding:"required"` // 邮箱或用户名
|
|
||||||
Password string `json:"password" binding:"required"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type LoginResponse struct {
|
|
||||||
Token string `json:"token"`
|
|
||||||
RefreshToken string `json:"refresh_token"`
|
|
||||||
ExpiresIn int64 `json:"expires_in"`
|
|
||||||
User UserInfo `json:"user"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type UserInfo struct {
|
type UserInfo struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Nickname string `json:"nickname"`
|
Nickname string `json:"nickname"`
|
||||||
Avatar string `json:"avatar"`
|
Avatar string `json:"avatar"`
|
||||||
Roles []string `json:"roles"`
|
Gender int `json:"gender"`
|
||||||
|
Phone string `json:"phone,omitempty"`
|
||||||
|
Roles []string `json:"roles"`
|
||||||
|
CreatedAt string `json:"created_at,omitempty"`
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Step 4: 创建认证服务**
|
**Step 4: 创建 Token Redis 存储管理**
|
||||||
|
|
||||||
|
创建 `app/auth/service/token_store.go`:
|
||||||
|
- 遵循设计方案中的 Redis Key 规范:`echo:auth:token:{user_id}` / `echo:auth:refresh:{user_id}`
|
||||||
|
- `SaveTokens(ctx, userID, accessToken, refreshToken)` — 存入 Redis(覆盖旧 Token,实现单设备登录)
|
||||||
|
- `ValidateAccessToken(ctx, userID, token)` — 校验 Access Token 与 Redis 一致
|
||||||
|
- `ValidateRefreshToken(ctx, userID, token)` — 校验 Refresh Token 与 Redis 一致
|
||||||
|
- `RemoveTokens(ctx, userID)` — 登出时删除 Redis 中的 Token
|
||||||
|
|
||||||
|
**Step 5: 创建认证服务**
|
||||||
|
|
||||||
创建 `app/auth/service/auth_service.go`:
|
创建 `app/auth/service/auth_service.go`:
|
||||||
- `Register(ctx, req)` — 注册逻辑(检查重复、加密密码、创建用户、分配默认角色、生成 Token)
|
- `Register(ctx, req)` — 注册逻辑(检查重复、加密密码、创建用户、分配默认角色、生成 Token + 存 Redis)
|
||||||
- `Login(ctx, req)` — 登录逻辑(查找用户、校验密码、检查状态、更新登录信息、生成 Token)
|
- `Login(ctx, req, clientIP)` — 登录逻辑(查找用户、校验密码、检查状态、更新登录信息、生成 Token + 存 Redis)
|
||||||
- `RefreshToken(ctx, refreshToken)` — 刷新 Token
|
- `AdminLogin(ctx, req, clientIP)` — 管理员登录(额外检查 admin/super_admin 角色)
|
||||||
|
- `RefreshToken(ctx, refreshToken)` — 刷新 Token(校验 Redis + 生成新 Token + 覆盖 Redis)
|
||||||
|
- `Logout(ctx, userID)` — 登出(从 Redis 删除 Token)
|
||||||
|
- `ValidateAccessToken(ctx, userID, token)` — 供中间件调用,校验 Redis
|
||||||
- `GetProfile(ctx, userID)` — 获取用户信息
|
- `GetProfile(ctx, userID)` — 获取用户信息
|
||||||
- `UpdateProfile(ctx, userID, req)` — 更新用户信息
|
- `UpdateProfile(ctx, userID, req)` — 更新用户信息
|
||||||
- `ChangePassword(ctx, userID, req)` — 修改密码
|
- `ChangePassword(ctx, userID, req)` — 修改密码
|
||||||
|
|
||||||
**Step 5: 创建认证中间件**
|
**Step 6: 创建认证中间件**
|
||||||
|
|
||||||
创建 `pkg/middleware/auth.go`:
|
创建 `pkg/middleware/auth.go`:
|
||||||
- `JWTAuth()` — JWT 验证中间件,从 Authorization Header 提取 Token
|
- `TokenValidator` 接口 — 定义 Token 校验契约,由 AuthService 实现(解耦 pkg 与 app 层依赖)
|
||||||
|
- `JWTAuth(cfg, validator)` — 有状态 JWT 验证中间件(解析 Token + 校验 Redis 有效性)
|
||||||
- `RequireRole(roles ...string)` — 角色检查中间件
|
- `RequireRole(roles ...string)` — 角色检查中间件
|
||||||
- 将 UserID 和 Roles 注入 Gin Context
|
- 将 UserID、Username 和 Roles 注入 Gin Context
|
||||||
|
|
||||||
**Step 6: 更新 Wire Provider**
|
**Step 7: 更新 Wire Provider**
|
||||||
|
|
||||||
更新 `app/auth/provider.go`,添加 Service 层 Provider:
|
更新 `app/auth/provider.go`:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
var AuthSet = wire.NewSet(
|
var AuthSet = wire.NewSet(
|
||||||
dao.NewUserDAO,
|
dao.NewUserDAO,
|
||||||
dao.NewRoleDAO,
|
dao.NewRoleDAO,
|
||||||
|
service.NewTokenStore,
|
||||||
service.NewAuthService,
|
service.NewAuthService,
|
||||||
|
controller.NewAuthController,
|
||||||
|
controller.NewAdminAuthController,
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Step 7: Commit**
|
**Step 8: Commit**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git add backend/go-service/
|
git add backend/go-service/
|
||||||
git commit -m "feat(auth): 认证服务层(注册、登录、JWT、密码加密、中间件)"
|
git commit -m "feat(auth): 认证服务层(注册、登录、有状态JWT、密码加密、中间件)"
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -585,21 +588,27 @@ func RegisterRoutes(r *gin.Engine, ctrl *AuthController, adminCtrl *AdminAuthCon
|
|||||||
**Step 5: 运行验证**
|
**Step 5: 运行验证**
|
||||||
|
|
||||||
Run: `cd backend/go-service && go run cmd/server/main.go`
|
Run: `cd backend/go-service && go run cmd/server/main.go`
|
||||||
Expected: 服务启动,可以通过 curl 测试注册和登录接口
|
Expected: 服务启动在 :8085,可以通过 curl 测试注册和登录接口
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 测试注册
|
# 测试注册
|
||||||
curl -X POST http://localhost:8080/api/v1/auth/register \
|
curl -X POST http://localhost:8085/api/v1/auth/register \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{"username":"testuser","email":"test@example.com","password":"123456","nickname":"测试用户"}'
|
-d '{"username":"testuser","email":"test@example.com","password":"123456","nickname":"测试用户"}'
|
||||||
|
|
||||||
# 测试登录
|
# 测试登录
|
||||||
curl -X POST http://localhost:8080/api/v1/auth/login \
|
curl -X POST http://localhost:8085/api/v1/auth/login \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{"account":"testuser","password":"123456"}'
|
-d '{"account":"testuser","password":"123456"}'
|
||||||
|
|
||||||
|
# 测试登出后 Token 立即失效
|
||||||
|
TOKEN=$(curl -s ... | jq -r '.data.token')
|
||||||
|
curl -X POST http://localhost:8085/api/v1/auth/logout -H "Authorization: Bearer $TOKEN"
|
||||||
|
curl http://localhost:8085/api/v1/auth/profile -H "Authorization: Bearer $TOKEN"
|
||||||
|
# 预期返回 401 "认证已失效,请重新登录"
|
||||||
```
|
```
|
||||||
|
|
||||||
Expected: 注册返回 Token,登录返回 Token + 用户信息
|
Expected: 注册返回 Token(同时存入 Redis),登录返回 Token + 用户信息,登出后 Token 立即失效
|
||||||
|
|
||||||
**Step 6: Commit**
|
**Step 6: Commit**
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user