完善登录与鉴权机制
This commit is contained in:
47
web/auth.go
47
web/auth.go
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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-web,1-native,2-browser" json:"spec"` // 安全规范:0-web,1-native,2-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"` // 更新时间
|
||||
|
||||
@@ -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-web,1-native,2-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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -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 定义负载类型
|
||||
|
||||
Reference in New Issue
Block a user