修正部分API授权

This commit is contained in:
GeekMaster
2025-08-31 10:52:25 +08:00
parent 9254b8fafe
commit 52313fc7f6
16 changed files with 90 additions and 90 deletions

View File

@@ -48,12 +48,12 @@ func (h *ChatAppHandler) RegisterRoutes() {
// Save 创建或者更新某个角色
func (h *ChatAppHandler) Save(c *gin.Context) {
var data vo.ChatRole
var data vo.ChatApp
if err := c.ShouldBindJSON(&data); err != nil {
resp.ERROR(c, types.InvalidArgs)
return
}
var role model.ChatRole
var role model.ChatApp
err := utils.CopyObject(data, &role)
if err != nil {
resp.ERROR(c, types.InvalidArgs)
@@ -81,8 +81,8 @@ func (h *ChatAppHandler) Save(c *gin.Context) {
}
func (h *ChatAppHandler) List(c *gin.Context) {
var items []model.ChatRole
var roles = make([]vo.ChatRole, 0)
var items []model.ChatApp
var roles = make([]vo.ChatApp, 0)
res := h.DB.Order("sort_num ASC").Find(&items)
if res.Error != nil {
resp.ERROR(c, "No data found")
@@ -123,7 +123,7 @@ func (h *ChatAppHandler) List(c *gin.Context) {
}
for _, v := range items {
var role vo.ChatRole
var role vo.ChatApp
err := utils.CopyObject(v, &role)
if err == nil {
role.Id = v.Id
@@ -151,7 +151,7 @@ func (h *ChatAppHandler) Sort(c *gin.Context) {
}
for index, id := range data.Ids {
err := h.DB.Model(&model.ChatRole{}).Where("id = ?", id).Update("sort_num", data.Sorts[index]).Error
err := h.DB.Model(&model.ChatApp{}).Where("id = ?", id).Update("sort_num", data.Sorts[index]).Error
if err != nil {
resp.ERROR(c, err.Error())
return
@@ -173,7 +173,7 @@ func (h *ChatAppHandler) Set(c *gin.Context) {
return
}
err := h.DB.Model(&model.ChatRole{}).Where("id = ?", data.Id).Update(data.Filed, data.Value).Error
err := h.DB.Model(&model.ChatApp{}).Where("id = ?", data.Id).Update(data.Filed, data.Value).Error
if err != nil {
resp.ERROR(c, err.Error())
return
@@ -188,7 +188,7 @@ func (h *ChatAppHandler) Remove(c *gin.Context) {
resp.ERROR(c, types.InvalidArgs)
return
}
res := h.DB.Where("id", id).Delete(&model.ChatRole{})
res := h.DB.Where("id", id).Delete(&model.ChatApp{})
if res.Error != nil {
resp.ERROR(c, "删除失败!")
return

View File

@@ -45,15 +45,15 @@ func (h *ChatHandler) RegisterRoutes() {
}
type chatItemVo struct {
Username string `json:"username"`
UserId uint `json:"user_id"`
ChatId string `json:"chat_id"`
Title string `json:"title"`
Role vo.ChatRole `json:"role"`
Model string `json:"model"`
Token int `json:"token"`
CreatedAt int64 `json:"created_at"`
MsgNum int `json:"msg_num"` // 消息数量
Username string `json:"username"`
UserId uint `json:"user_id"`
ChatId string `json:"chat_id"`
Title string `json:"title"`
Role vo.ChatApp `json:"role"`
Model string `json:"model"`
Token int `json:"token"`
CreatedAt int64 `json:"created_at"`
MsgNum int `json:"msg_num"` // 消息数量
}
func (h *ChatHandler) List(c *gin.Context) {
@@ -103,7 +103,7 @@ func (h *ChatHandler) List(c *gin.Context) {
}
var messages []model.ChatMessage
var users []model.User
var roles []model.ChatRole
var roles []model.ChatApp
h.DB.Where("chat_id IN ?", chatIds).Find(&messages)
h.DB.Where("id IN ?", userIds).Find(&users)
h.DB.Where("id IN ?", roleIds).Find(&roles)
@@ -111,7 +111,7 @@ func (h *ChatHandler) List(c *gin.Context) {
tokenMap := make(map[string]int)
userMap := make(map[uint]string)
msgMap := make(map[string]int)
roleMap := make(map[uint]vo.ChatRole)
roleMap := make(map[uint]vo.ChatApp)
for _, msg := range messages {
tokenMap[msg.ChatId] += msg.Tokens
msgMap[msg.ChatId] += 1
@@ -120,7 +120,7 @@ func (h *ChatHandler) List(c *gin.Context) {
userMap[user.Id] = user.Username
}
for _, r := range roles {
var roleVo vo.ChatRole
var roleVo vo.ChatApp
err := utils.CopyObject(r, &roleVo)
if err != nil {
continue

View File

@@ -20,31 +20,31 @@ import (
"gorm.io/gorm"
)
type ChatRoleHandler struct {
type ChatAppHandler struct {
BaseHandler
}
func NewChatRoleHandler(app *core.AppServer, db *gorm.DB) *ChatRoleHandler {
return &ChatRoleHandler{BaseHandler: BaseHandler{App: app, DB: db}}
func NewChatAppHandler(app *core.AppServer, db *gorm.DB) *ChatAppHandler {
return &ChatAppHandler{BaseHandler: BaseHandler{App: app, DB: db}}
}
// RegisterRoutes 注册路由
func (h *ChatRoleHandler) RegisterRoutes() {
func (h *ChatAppHandler) RegisterRoutes() {
group := h.App.Engine.Group("/api/app/")
group.GET("list", h.List)
// 需要用户授权的接口
group.Use(middleware.UserAuthMiddleware(h.App.Config.Session.SecretKey, h.App.Redis))
{
group.GET("list", h.List)
group.GET("list/user", h.ListByUser)
group.POST("update", h.UpdateRole)
group.POST("update", h.UpdateApp)
}
}
// List 获取用户聊天应用列表
func (h *ChatRoleHandler) List(c *gin.Context) {
func (h *ChatAppHandler) List(c *gin.Context) {
tid := h.GetInt(c, "tid", 0)
var roles []model.ChatRole
var roles []model.ChatApp
session := h.DB.Where("enable", true)
if tid > 0 {
session = session.Where("tid", tid)
@@ -55,9 +55,9 @@ func (h *ChatRoleHandler) List(c *gin.Context) {
return
}
var roleVos = make([]vo.ChatRole, 0)
var roleVos = make([]vo.ChatApp, 0)
for _, r := range roles {
var v vo.ChatRole
var v vo.ChatApp
err := utils.CopyObject(r, &v)
if err == nil {
v.Id = r.Id
@@ -68,10 +68,10 @@ func (h *ChatRoleHandler) List(c *gin.Context) {
}
// ListByUser 获取用户添加的角色列表
func (h *ChatRoleHandler) ListByUser(c *gin.Context) {
func (h *ChatAppHandler) ListByUser(c *gin.Context) {
id := h.GetInt(c, "id", 0)
userId := h.GetLoginUserId(c)
var roles []model.ChatRole
var roles []model.ChatApp
session := h.DB.Where("enable", true)
// 如果用户没登录,则获取所有角色
if userId > 0 {
@@ -100,9 +100,9 @@ func (h *ChatRoleHandler) ListByUser(c *gin.Context) {
return
}
var roleVos = make([]vo.ChatRole, 0)
var roleVos = make([]vo.ChatApp, 0)
for _, r := range roles {
var v vo.ChatRole
var v vo.ChatApp
err := utils.CopyObject(r, &v)
if err == nil {
v.Id = r.Id
@@ -112,8 +112,8 @@ func (h *ChatRoleHandler) ListByUser(c *gin.Context) {
resp.SUCCESS(c, roleVos)
}
// UpdateRole 更新用户聊天角色
func (h *ChatRoleHandler) UpdateRole(c *gin.Context) {
// UpdateApp 更新用户聊天应用
func (h *ChatAppHandler) UpdateApp(c *gin.Context) {
user, err := h.GetLoginUser(c)
if err != nil {
resp.NotAuth(c)

View File

@@ -2,7 +2,6 @@ package handler
import (
"geekai/core"
"geekai/core/middleware"
"geekai/store/model"
"geekai/store/vo"
"geekai/utils"
@@ -23,12 +22,7 @@ func NewChatAppTypeHandler(app *core.AppServer, db *gorm.DB) *ChatAppTypeHandler
// RegisterRoutes 注册路由
func (h *ChatAppTypeHandler) RegisterRoutes() {
group := h.App.Engine.Group("/api/app/type/")
// 需要用户授权的接口
group.Use(middleware.UserAuthMiddleware(h.App.Config.Session.SecretKey, h.App.Redis))
{
group.GET("list", h.List)
}
group.GET("list", h.List)
}
// List 获取App类型列表

View File

@@ -55,7 +55,7 @@ type ChatInput struct {
Stream bool `json:"stream"`
Files []vo.File `json:"files"`
ChatModel model.ChatModel `json:"chat_model,omitempty"`
ChatRole model.ChatRole `json:"chat_role,omitempty"`
ChatRole model.ChatApp `json:"chat_role,omitempty"`
LastMsgId uint `json:"last_msg_id,omitempty"` // 最后的消息ID用于重新生成答案的时候过滤上下文
}
@@ -136,7 +136,7 @@ func (h *ChatHandler) Chat(c *gin.Context) {
}
// 验证聊天角色
var chatRole model.ChatRole
var chatRole model.ChatApp
err := h.DB.First(&chatRole, input.RoleId).Error
if err != nil || !chatRole.Enable {
pushMessage(c, ChatEventError, "当前聊天角色不存在或者未启用,请更换角色之后再发起对话!")

View File

@@ -42,9 +42,9 @@ func (h *ChatHandler) List(c *gin.Context) {
modelValues = append(modelValues, chat.Model)
}
var roles []model.ChatRole
var roles []model.ChatApp
var models []model.ChatModel
roleMap := make(map[uint]model.ChatRole)
roleMap := make(map[uint]model.ChatApp)
modelMap := make(map[string]model.ChatModel)
h.DB.Where("id IN ?", roleIds).Find(&roles)
h.DB.Where("value IN ?", modelValues).Find(&models)
@@ -205,7 +205,7 @@ func (h *ChatHandler) Detail(c *gin.Context) {
}
// 填充角色名称
var role model.ChatRole
var role model.ChatApp
res = h.DB.Where("id", chatItem.RoleId).First(&role)
if res.Error != nil {
resp.ERROR(c, "Role not found")

View File

@@ -127,7 +127,7 @@ func main() {
}),
// 创建控制器
fx.Provide(handler.NewChatRoleHandler),
fx.Provide(handler.NewChatAppHandler),
fx.Provide(handler.NewUserHandler),
fx.Provide(handler.NewChatHandler),
fx.Provide(handler.NewNetHandler),
@@ -242,7 +242,7 @@ func main() {
fx.Provide(service.NewUserService),
// 注册路由
fx.Invoke(func(s *core.AppServer, h *handler.ChatRoleHandler) {
fx.Invoke(func(s *core.AppServer, h *handler.ChatAppHandler) {
h.RegisterRoutes()
}),
fx.Invoke(func(s *core.AppServer, h *handler.UserHandler) {

View File

@@ -110,6 +110,11 @@ func (s *LicenseService) SyncLicense() {
s.license.IsActive = false
} else {
s.license = license
// 保存 License 到数据库
err = s.db.Model(&model.Config{}).Where("name = ?", types.ConfigKeyLicense).UpdateColumn("value", utils.JsonEncode(s.license)).Error
if err != nil {
logger.Errorf("保存 License 到数据库失败: %v", err)
}
}
urls, err := s.fetchUrlWhiteList()
@@ -184,6 +189,11 @@ func (s *LicenseService) GetLicense() *types.License {
return s.license
}
func (s *LicenseService) SetLicense(licenseKey string) {
s.license.Key = licenseKey
}
// IsValidApiURL 判断是否合法的中转 URL
func (s *LicenseService) IsValidApiURL(uri string) error {
// 获得许可授权的直接放行

View File

@@ -28,18 +28,20 @@ const (
// MigrationService 配置迁移服务
type MigrationService struct {
db *gorm.DB
redisClient *redis.Client
appConfig *types.AppConfig
levelDB *store.LevelDB
db *gorm.DB
redisClient *redis.Client
appConfig *types.AppConfig
levelDB *store.LevelDB
licenseService *LicenseService
}
func NewMigrationService(db *gorm.DB, redisClient *redis.Client, appConfig *types.AppConfig, levelDB *store.LevelDB) *MigrationService {
func NewMigrationService(db *gorm.DB, redisClient *redis.Client, appConfig *types.AppConfig, levelDB *store.LevelDB, licenseService *LicenseService) *MigrationService {
return &MigrationService{
db: db,
redisClient: redisClient,
appConfig: appConfig,
levelDB: levelDB,
db: db,
redisClient: redisClient,
appConfig: appConfig,
levelDB: levelDB,
licenseService: licenseService,
}
}
@@ -71,6 +73,7 @@ func (s *MigrationService) MigrateLicense() {
logger.Errorf("迁移 License 失败: %v", err)
return
}
s.licenseService.SetLicense(license.Key)
logger.Info("迁移 License 完成")
s.redisClient.Set(context.Background(), key, "1", 0)
}

View File

@@ -4,7 +4,7 @@ import (
"time"
)
type ChatRole struct {
type ChatApp struct {
Id uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
Name string `gorm:"column:name;type:varchar(30);not null;comment:角色名称" json:"name"`
Tid uint `gorm:"column:tid;type:int(11);not null;comment:分类ID" json:"tid"`
@@ -19,6 +19,6 @@ type ChatRole struct {
UpdatedAt time.Time `gorm:"column:updated_at;type:datetime;not null" json:"updated_at"`
}
func (m *ChatRole) TableName() string {
func (m *ChatApp) TableName() string {
return "chatgpt_chat_roles"
}

View File

@@ -2,7 +2,7 @@ package vo
import "geekai/core/types"
type ChatRole struct {
type ChatApp struct {
BaseVo
Key string `json:"key"` // 角色唯一标识
Tid uint `json:"tid"`

View File

@@ -46,7 +46,6 @@ const calcSpan = () => {
span.value = 1
return
}
console.log(cols)
while (cols > 1) {
if (24 % cols === 0) {
span.value = 24 / cols

View File

@@ -90,13 +90,19 @@
<div class="qr-code-container">
<div class="qr-code-wrapper w-[200px] h-[200px] mx-auto" v-loading="qrcodeLoading">
<img :src="wechatLoginQRCode" class="qr-frame" v-if="wechatLoginQRCode" />
<div
v-else
class="w-[200px] h-[200px] flex justify-center items-center text-green-600"
>
<i class="iconfont icon-wechat !text-3xl"></i>
</div>
<!-- 二维码过期蒙版 -->
<div v-if="qrcodeExpired" class="qr-expired-mask">
<div class="expired-content">
<i class="iconfont icon-refresh-ccw expired-icon"></i>
<p class="expired-text">二维码已过期</p>
<button
@click="getWechatLoginURL"
@click="getWxLoginURL"
class="bg-gray-200 text-gray-600 px-2.5 py-1 rounded-md hover:bg-gray-300"
>
<i class="iconfont icon-refresh text-lg"></i>
@@ -443,7 +449,7 @@ onMounted(() => {
// 监听登录标签页切换
watch(loginActiveName, (newValue) => {
if (newValue === 'wechat') {
getWechatLoginURL()
getWxLoginURL()
} else {
// 其他登录方式,清除定时器
if (pollingTimer.value) {
@@ -458,7 +464,7 @@ watch(loginActiveName, (newValue) => {
const handleTabClick = (tab) => {
// CustomTabs组件传递的是tab对象包含paneName属性
if (tab.paneName === 'wechat') {
getWechatLoginURL()
getWxLoginURL()
} else {
// 其他登录方式,清除定时器
if (pollingTimer.value) {
@@ -479,7 +485,7 @@ const submit = (verifyData) => {
}
// 获取微信登录 URL
const getWechatLoginURL = () => {
const getWxLoginURL = () => {
wechatLoginQRCode.value = ''
qrcodeLoading.value = true
qrcodeExpired.value = false

View File

@@ -110,7 +110,7 @@
<el-select
v-model="roleId"
filterable
placeholder="角色"
placeholder="应用"
@change="_newChat"
class="role-select"
style="width: 150px"
@@ -306,7 +306,7 @@
</div>
<div class="flex-between">
<div class="flex little-btns">
<span class="tool-item-btn" @click="realtimeChat">
<!-- <span class="tool-item-btn" @click="realtimeChat">
<el-tooltip
class="box-item"
effect="dark"
@@ -316,7 +316,7 @@
>
<i class="iconfont icon-mic-bold"></i>
</el-tooltip>
</span>
</span> -->
<span class="tool-item-btn">
<el-tooltip class="box-item" effect="dark" content="上传附件">
@@ -662,7 +662,7 @@ const initData = async () => {
// 获取角色列表
const roleRes = await httpGet('/api/app/list')
roles.value = roleRes.data
if (roles.value.length > 0) {
if (roles.value.length > 0 && !roleId.value) {
roleId.value = roles.value[0].id
}

View File

@@ -9,7 +9,7 @@
<div class="user-avatar" v-if="isLogin" @click="router.push('profile')">
<van-image :src="userAvatar" round width="40" height="40" />
</div>
<div class="login-btn" v-else @click="router.push('login')">
<div class="login-btn" v-else @click="router.push('/login')">
<van-button size="small" type="primary" round>登录</van-button>
</div>
</div>

View File

@@ -3,7 +3,7 @@
<div class="profile-header">
<div class="header-bg"></div>
<div class="header-content">
<div class="user-info" v-if="isLogin">
<div class="user-info">
<div class="avatar-container">
<van-image :src="fileList[0].url" round width="80" height="80" />
</div>
@@ -15,20 +15,12 @@
</div>
</div>
</div>
<div class="login-prompt" v-else>
<button
class="py-3 px-5 bg-gradient-to-r from-green-400 to-blue-400 text-white rounded-xl disabled:from-gray-400 disabled:to-gray-400 disabled:cursor-not-allowed hover:from-green-500 hover:to-blue-500 transition-all duration-200 flex items-center justify-center space-x-2"
@click="router.push('/login')"
>
立即登录
</button>
</div>
</div>
</div>
<div class="profile-content">
<!-- 快捷操作 -->
<div class="quick-actions" v-if="isLogin">
<div class="quick-actions">
<h3 class="section-title">快捷操作</h3>
<van-row :gutter="12">
<van-col :span="8">
@@ -59,7 +51,7 @@
</div>
<!-- 我的服务 -->
<div class="menu-section" v-if="isLogin">
<div class="menu-section">
<h3 class="section-title">我的服务</h3>
<van-cell-group>
<van-cell title="绑定邮箱" is-link @click="showBindEmailDialog = true">
@@ -91,7 +83,7 @@
</div>
<!-- 退出登录 -->
<div class="logout-section" v-if="isLogin">
<div class="logout-section">
<van-button size="large" block type="danger" plain @click="showLogoutConfirm = true">
退出登录
</van-button>
@@ -206,7 +198,6 @@ import { checkSession, getSystemInfo } from '@/store/cache'
import { removeUserToken } from '@/store/session'
import { useSharedStore } from '@/store/sharedata'
import { httpGet, httpPost } from '@/utils/http'
import { showLoginDialog } from '@/utils/libs'
import { showFailToast, showLoadingToast, showSuccessToast } from 'vant'
import { computed, onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
@@ -229,7 +220,6 @@ const fileList = ref([
])
const router = useRouter()
const isLogin = ref(false)
const showSettings = ref(false)
const showPasswordDialog = ref(false)
const showBindEmailDialog = ref(false)
@@ -272,7 +262,6 @@ onMounted(() => {
checkSession()
.then((user) => {
isLogin.value = true
form.value = { ...form.value, ...user }
fileList.value[0].url = user.avatar || '/images/avatar/default.jpg'
@@ -280,7 +269,7 @@ onMounted(() => {
fetchUserProfile()
})
.catch(() => {
isLogin.value = false
router.push('/login')
})
})
@@ -356,9 +345,8 @@ const logout = function () {
.then(() => {
removeUserToken()
store.setIsLogin(false)
isLogin.value = false
showSuccessToast('退出登录成功')
showLogoutConfirm.value = false
router.push('/login')
// 清除用户数据
form.value = {