完善登录与鉴权机制

This commit is contained in:
2025-03-28 15:01:30 +08:00
parent e61f0bef32
commit edec734b71
11 changed files with 132 additions and 108 deletions

View File

@@ -56,3 +56,50 @@ func PermitUser(permissions ...string) fiber.Handler {
return c.Next()
}
}
func PermitDevice(permissions ...string) fiber.Handler {
return func(c *fiber.Ctx) error {
// 获取令牌
var header = c.Get("Authorization")
var token = strings.TrimPrefix(header, "Bearer ")
if token == "" {
return c.Status(fiber.StatusUnauthorized).JSON(common.ErrResp{
Error: true,
Message: "没有权限",
})
}
// 验证令牌
auth, err := services.Session.Find(c.Context(), token)
if err != nil {
return c.Status(fiber.StatusUnauthorized).JSON(common.ErrResp{
Error: true,
Message: "没有权限",
})
}
// 检查权限
switch auth.Payload.Type {
case services.PayloadAdmin:
// 管理员不需要权限检查
case services.PayloadClientPublic, services.PayloadClientConfidential:
if len(permissions) > 0 && !auth.AnyPermission(permissions...) {
return c.Status(fiber.StatusForbidden).JSON(common.ErrResp{
Error: true,
Message: "拒绝访问",
})
}
default:
return c.Status(fiber.StatusForbidden).JSON(common.ErrResp{
Error: true,
Message: "拒绝访问",
})
}
// 将认证信息存储在上下文中
c.Locals("auth", auth)
c.Locals("access_token", token) // 存储原始令牌,便于后续操作
return c.Next()
}
}

View File

@@ -1,52 +0,0 @@
package handlers
import (
"platform/web/models"
q "platform/web/queries"
"time"
"github.com/gofiber/fiber/v2"
"golang.org/x/crypto/bcrypt"
)
type CreateClientReq struct {
ClientID string `query:"client_id"`
ClientSecret string `query:"client_secret"`
}
func CreateClient(c *fiber.Ctx) error {
// 验证请求参数
req := new(CreateClientReq)
if err := c.QueryParser(req); err != nil {
return err
}
if req.ClientID == "" {
return fiber.NewError(fiber.StatusBadRequest, "client_id不能为空")
}
if req.ClientSecret == "" {
return fiber.NewError(fiber.StatusBadRequest, "client_secret不能为空")
}
// 创建客户端
hashedSecret, err := bcrypt.GenerateFromPassword([]byte(req.ClientSecret), bcrypt.DefaultCost)
if err != nil {
return err
}
client := &models.Client{
ClientID: req.ClientID,
ClientSecret: string(hashedSecret),
Name: "默认客户端 - " + time.Now().String(),
Spec: 0,
GrantCode: true,
GrantClient: true,
GrantRefresh: true,
Version: 0,
}
err = q.Client.Create(client)
if err != nil {
return err
}
return c.JSON(client)
}

View File

@@ -18,8 +18,9 @@ type LoginReq struct {
}
type LoginResp struct {
Token string `json:"token"`
Expires int64 `json:"expires"`
Token string `json:"token"`
Expires int64 `json:"expires"`
Auth services.AuthContext `json:"auth"`
}
func Login(c *fiber.Ctx) error {
@@ -65,6 +66,7 @@ func loginByPhone(c *fiber.Ctx, req *LoginReq) error {
if user == nil {
user = &models.User{
Phone: req.Username,
Name: req.Username,
}
}
@@ -87,8 +89,10 @@ func loginByPhone(c *fiber.Ctx, req *LoginReq) error {
"user": {},
},
Payload: services.Payload{
Type: services.PayloadUser,
Id: user.ID,
Id: user.ID,
Type: services.PayloadUser,
Name: user.Name,
Avatar: user.Avatar,
},
}
duration := time.Hour * 24
@@ -103,5 +107,6 @@ func loginByPhone(c *fiber.Ctx, req *LoginReq) error {
return c.JSON(LoginResp{
Token: token.AccessToken,
Expires: token.AccessTokenExpires.Unix(),
Auth: auth,
})
}

View File

@@ -23,7 +23,7 @@ type Client struct {
GrantRefresh bool `gorm:"column:grant_refresh;not null;comment:允许刷新令牌授予" json:"grant_refresh"` // 允许刷新令牌授予
Spec int32 `gorm:"column:spec;not null;comment:安全规范0-web1-native2-browser" json:"spec"` // 安全规范0-web1-native2-browser
Name string `gorm:"column:name;not null;comment:名称" json:"name"` // 名称
Version int32 `gorm:"column:version;not null;comment:版本" json:"version"` // 版本
Icon string `gorm:"column:icon;comment:图标URL" json:"icon"` // 图标URL
Status int32 `gorm:"column:status;not null;default:1;comment:状态1-正常0-禁用" json:"status"` // 状态1-正常0-禁用
CreatedAt time.Time `gorm:"column:created_at;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间
UpdatedAt time.Time `gorm:"column:updated_at;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间

View File

@@ -36,7 +36,7 @@ func newClient(db *gorm.DB, opts ...gen.DOOption) client {
_client.GrantRefresh = field.NewBool(tableName, "grant_refresh")
_client.Spec = field.NewInt32(tableName, "spec")
_client.Name = field.NewString(tableName, "name")
_client.Version = field.NewInt32(tableName, "version")
_client.Icon = field.NewString(tableName, "icon")
_client.Status = field.NewInt32(tableName, "status")
_client.CreatedAt = field.NewTime(tableName, "created_at")
_client.UpdatedAt = field.NewTime(tableName, "updated_at")
@@ -60,7 +60,7 @@ type client struct {
GrantRefresh field.Bool // 允许刷新令牌授予
Spec field.Int32 // 安全规范0-web1-native2-browser
Name field.String // 名称
Version field.Int32 // 版本
Icon field.String // 图标URL
Status field.Int32 // 状态1-正常0-禁用
CreatedAt field.Time // 创建时间
UpdatedAt field.Time // 更新时间
@@ -90,7 +90,7 @@ func (c *client) updateTableName(table string) *client {
c.GrantRefresh = field.NewBool(table, "grant_refresh")
c.Spec = field.NewInt32(table, "spec")
c.Name = field.NewString(table, "name")
c.Version = field.NewInt32(table, "version")
c.Icon = field.NewString(table, "icon")
c.Status = field.NewInt32(table, "status")
c.CreatedAt = field.NewTime(table, "created_at")
c.UpdatedAt = field.NewTime(table, "updated_at")
@@ -121,7 +121,7 @@ func (c *client) fillFieldMap() {
c.fieldMap["grant_refresh"] = c.GrantRefresh
c.fieldMap["spec"] = c.Spec
c.fieldMap["name"] = c.Name
c.fieldMap["version"] = c.Version
c.fieldMap["icon"] = c.Icon
c.fieldMap["status"] = c.Status
c.fieldMap["created_at"] = c.CreatedAt
c.fieldMap["updated_at"] = c.UpdatedAt

View File

@@ -11,14 +11,10 @@ func ApplyRouters(app *fiber.App) {
// 认证
auth := api.Group("/auth")
auth.Post("/verify/sms", PermitUser(), handlers.SmsCode)
auth.Post("/login/sms", PermitUser(), handlers.Login)
auth.Post("/verify/sms", PermitDevice(), handlers.SmsCode)
auth.Post("/login/sms", PermitDevice(), handlers.Login)
auth.Post("/token", handlers.Token)
// 客户端
client := api.Group("/client")
client.Get("/test/create", handlers.CreateClient)
// 通道
channel := api.Group("/channel", PermitUser())
channel.Post("/create", handlers.CreateChannel)

View File

@@ -59,8 +59,9 @@ func (s *authService) OauthClientCredentials(ctx context.Context, client *models
auth := AuthContext{
Permissions: permissions,
Payload: Payload{
Type: clientType,
Id: client.ID,
Type: clientType,
Name: client.Name,
},
}

View File

@@ -238,15 +238,17 @@ func mergeConfig(defaultCfg SessionConfig, customCfg SessionConfig) SessionConfi
// AuthContext 定义认证信息
type AuthContext struct {
Payload Payload
Permissions map[string]struct{}
Metadata map[string]interface{}
Payload Payload `json:"payload"`
Permissions map[string]struct{} `json:"permissions,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
}
// Payload 定义负载信息
type Payload struct {
Type PayloadType
Id int32
Id int32 `json:"id,omitempty"`
Type PayloadType `json:"type,omitempty"`
Name string `json:"name,omitempty"`
Avatar string `json:"avatar,omitempty"`
}
// PayloadType 定义负载类型