From 1262a8dae42dac5d4393452dddd91afa8fa28e32 Mon Sep 17 00:00:00 2001 From: luorijun Date: Mon, 29 Dec 2025 10:18:01 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E8=AE=A4=E8=AF=81=E6=8E=88?= =?UTF-8?q?=E6=9D=83=E6=A8=A1=E5=9D=97=EF=BC=8C=E7=BB=9F=E4=B8=80=E5=88=B0?= =?UTF-8?q?=20auth=20=E5=8C=85=E4=B8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{docker-publish.yml => release.yml} | 4 +- web/auth/account.go | 156 +++++++++ web/auth/{authorize.go => endpoints.go} | 331 +++++++++++++----- web/auth/{authenticate.go => middleware.go} | 69 ---- web/auth/session.go | 4 +- web/handlers/auth.go | 97 ----- web/middlewares.go | 9 + web/routes.go | 6 +- 8 files changed, 407 insertions(+), 269 deletions(-) rename .github/workflows/{docker-publish.yml => release.yml} (97%) create mode 100644 web/auth/account.go rename web/auth/{authorize.go => endpoints.go} (67%) rename web/auth/{authenticate.go => middleware.go} (56%) delete mode 100644 web/handlers/auth.go diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/release.yml similarity index 97% rename from .github/workflows/docker-publish.yml rename to .github/workflows/release.yml index 8ae5517..8e3c98b 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/release.yml @@ -2,7 +2,7 @@ name: Docker on: push: - branches: [ "main" ] + branches: ["v*"] env: REGISTRY: ghcr.io @@ -10,14 +10,12 @@ env: jobs: build: - runs-on: ubuntu-latest permissions: contents: read packages: write steps: - - name: Checkout repository uses: actions/checkout@v4 diff --git a/web/auth/account.go b/web/auth/account.go new file mode 100644 index 0000000..72bfa85 --- /dev/null +++ b/web/auth/account.go @@ -0,0 +1,156 @@ +package auth + +import ( + "context" + "errors" + "log/slog" + "platform/pkg/u" + "platform/web/core" + m "platform/web/models" + q "platform/web/queries" + s "platform/web/services" + + "golang.org/x/crypto/bcrypt" +) + +func authClient(clientId string, clientSecrets ...string) (*m.Client, error) { + + // 获取客户端信息 + client, err := q.Client. + Where( + q.Client.ClientID.Eq(clientId), + q.Client.Status.Eq(1)). + Take() + if err != nil { + return nil, err + } + + // 检查客户端密钥 + if client.Spec == m.ClientSpecWeb || client.Spec == m.ClientSpecAPI { + if len(clientSecrets) == 0 { + return nil, errors.New("客户端密钥错误") + } + clientSecret := clientSecrets[0] + if bcrypt.CompareHashAndPassword([]byte(client.ClientSecret), []byte(clientSecret)) != nil { + return nil, errors.New("客户端密钥错误") + } + } + + // todo 查询客户端关联权限 + + // 组织授权信息(一次性请求) + return client, nil +} + +func authUser(loginType PwdLoginType, username, password string) (user *m.User, err error) { + switch loginType { + case PwdLoginByPhone: + user, err = authUserBySms(q.Q, username, password) + if err != nil { + return nil, err + } + if user == nil { + user = &m.User{ + Phone: username, + Username: u.P(username), + Status: m.UserStatusEnabled, + } + } + case PwdLoginByEmail: + user, err = authUserByEmail(q.Q, username, password) + if err != nil { + return nil, err + } + case PwdLoginByPassword: + user, err = authUserByPassword(q.Q, username, password) + if err != nil { + return nil, err + } + default: + return nil, ErrAuthorizeInvalidRequest + } + + // 账户状态 + if user.Status == m.UserStatusDisabled { + return nil, core.NewBizErr("账号已禁用") + } + + return user, nil +} + +func authUserBySms(tx *q.Query, username, code string) (*m.User, error) { + // 验证验证码 + err := s.Verifier.VerifySms(context.Background(), username, code) + if err != nil { + return nil, core.NewBizErr("短信认证失败:%w", err) + } + + // 查找用户 + return tx.User.Where(tx.User.Phone.Eq(username)).Take() +} + +func authUserByEmail(tx *q.Query, username, code string) (*m.User, error) { + return nil, core.NewServErr("邮箱登录不可用") +} + +func authUserByPassword(tx *q.Query, username, password string) (*m.User, error) { + user, err := tx.User. + Where(tx.User.Phone.Eq(username)). + Or(tx.User.Email.Eq(username)). + Or(tx.User.Username.Eq(username)). + Take() + if err != nil { + slog.Debug("查找用户失败", "error", err) + return nil, core.NewBizErr("用户不存在或密码错误") + } + + // 验证密码 + if user.Password == nil || *user.Password == "" { + slog.Debug("用户未设置密码", "username", username) + return nil, core.NewBizErr("用户不存在或密码错误") + } + if bcrypt.CompareHashAndPassword([]byte(*user.Password), []byte(password)) != nil { + slog.Debug("密码验证失败", "username", username) + return nil, core.NewBizErr("用户不存在或密码错误") + } + + return user, nil +} + +func authAdmin(loginType PwdLoginType, username, password string) (admin *m.Admin, err error) { + switch loginType { + case PwdLoginByPhone, PwdLoginByEmail: + return nil, core.NewServErr("不支持的登录方式:" + string(loginType)) + case PwdLoginByPassword: + admin, err = authAdminByPassword(q.Q, username, password) + if err != nil { + return nil, err + } + default: + return nil, ErrAuthorizeInvalidRequest + } + + // 账户状态 + if admin.Status == m.AdminStatusDisabled { + return nil, core.NewBizErr("账号已禁用") + } + + return admin, nil +} + +func authAdminByPassword(tx *q.Query, username, password string) (*m.Admin, error) { + admin, err := tx.Admin.Where(tx.Admin.Username.Eq(username)).Take() + if err != nil { + return nil, core.NewBizErr("账号不存在或密码错误") + } + + // 验证密码 + if admin.Password == "" { + return nil, core.NewBizErr("账号不存在或密码错误") + } + if bcrypt.CompareHashAndPassword([]byte(admin.Password), []byte(password)) != nil { + return nil, core.NewBizErr("账号不存在或密码错误") + } + + return admin, nil +} diff --git a/web/auth/authorize.go b/web/auth/endpoints.go similarity index 67% rename from web/auth/authorize.go rename to web/auth/endpoints.go index 28e9c37..d8e757d 100644 --- a/web/auth/authorize.go +++ b/web/auth/endpoints.go @@ -6,10 +6,8 @@ import ( "encoding/base64" "encoding/json" "errors" - "log/slog" "platform/pkg/env" "platform/pkg/u" - "platform/web/core" g "platform/web/globals" "platform/web/globals/orm" m "platform/web/models" @@ -22,67 +20,52 @@ import ( "gorm.io/gorm" ) -type GrantType string +// AuthorizeGet 授权端点 +func AuthorizeGet(ctx *fiber.Ctx) error { -const ( - GrantAuthorizationCode = GrantType("authorization_code") // 授权码模式 - GrantClientCredentials = GrantType("client_credentials") // 客户端凭证模式 - GrantRefreshToken = GrantType("refresh_token") // 刷新令牌模式 - GrantPassword = GrantType("password") // 密码模式(私有扩展) -) + // 检查请求 + req := new(AuthorizeGetReq) + if err := g.Validator.ParseQuery(ctx, req); err != nil { + return err + } -type PasswordGrantType string + // 检查客户端 + client, err := authClient(req.ClientID) + if err != nil { + return err + } -const ( - GrantPasswordSecret = PasswordGrantType("password") // 账号密码 - GrantPasswordPhone = PasswordGrantType("phone_code") // 手机验证码 - GrantPasswordEmail = PasswordGrantType("email_code") // 邮箱验证码 -) + if client.RedirectURI == nil || *client.RedirectURI != req.RedirectURI { + return errors.New("客户端重定向URI错误") + } -type TokenReq struct { - GrantType GrantType `json:"grant_type" form:"grant_type"` - ClientID string `json:"client_id" form:"client_id"` - ClientSecret string `json:"client_secret" form:"client_secret"` - Scope string `json:"scope" form:"scope"` - GrantCodeData - GrantClientData - GrantRefreshData - GrantPasswordData + // todo 检查 scope + + // 授权确认页面 + return nil } -type GrantCodeData struct { - Code string `json:"code" form:"code"` - RedirectURI string `json:"redirect_uri" form:"redirect_uri"` - CodeVerifier string `json:"code_verifier" form:"code_verifier"` +type AuthorizeGetReq struct { + ResponseType string `json:"response_type" validate:"eq=code"` + ClientID string `json:"client_id" validate:"required"` + RedirectURI string `json:"redirect_uri" validate:"required"` + Scope string `json:"scope"` + State string `json:"state"` } -type GrantClientData struct { +func AuthorizePost(ctx *fiber.Ctx) error { + + // todo 解析用户授权的范围 + + return nil } -type GrantRefreshData struct { - RefreshToken string `json:"refresh_token" form:"refresh_token"` -} - -type GrantPasswordData struct { - LoginType PasswordGrantType `json:"login_type" form:"login_type"` - Username string `json:"username" form:"username"` - Password string `json:"password" form:"password"` - Remember bool `json:"remember" form:"remember"` -} - -type TokenResp struct { - AccessToken string `json:"access_token"` - RefreshToken string `json:"refresh_token,omitempty"` - ExpiresIn int `json:"expires_in"` - TokenType string `json:"token_type"` - Scope string `json:"scope,omitempty"` -} - -type TokenErrResp struct { - Error string `json:"error"` - Description string `json:"error_description,omitempty"` +type AuthorizePostReq struct { + Accept bool `json:"accept"` + Scope string `json:"scope"` } +// Token 令牌端点 func Token(c *fiber.Ctx) error { now := time.Now() @@ -165,6 +148,75 @@ func Token(c *fiber.Ctx) error { }) } +type TokenReq struct { + GrantType GrantType `json:"grant_type" form:"grant_type"` + ClientID string `json:"client_id" form:"client_id"` + ClientSecret string `json:"client_secret" form:"client_secret"` + Scope string `json:"scope" form:"scope"` + GrantCodeData + GrantClientData + GrantRefreshData + GrantPasswordData +} + +type GrantCodeData struct { + Code string `json:"code" form:"code"` + RedirectURI string `json:"redirect_uri" form:"redirect_uri"` + CodeVerifier string `json:"code_verifier" form:"code_verifier"` +} + +type GrantClientData struct { +} + +type GrantRefreshData struct { + RefreshToken string `json:"refresh_token" form:"refresh_token"` +} + +type GrantPasswordData struct { + LoginType PwdLoginType `json:"login_type" form:"login_type"` + LoginPool PwdLoginPool `json:"login_pool" form:"login_pool"` + Username string `json:"username" form:"username"` + Password string `json:"password" form:"password"` + Remember bool `json:"remember" form:"remember"` +} + +type GrantType string + +const ( + GrantAuthorizationCode = GrantType("authorization_code") // 授权码模式 + GrantClientCredentials = GrantType("client_credentials") // 客户端凭证模式 + GrantRefreshToken = GrantType("refresh_token") // 刷新令牌模式 + GrantPassword = GrantType("password") // 密码模式(私有扩展) +) + +type PwdLoginType string + +const ( + PwdLoginByPassword = PwdLoginType("password") // 账号密码 + PwdLoginByPhone = PwdLoginType("phone_code") // 手机验证码 + PwdLoginByEmail = PwdLoginType("email_code") // 邮箱验证码 +) + +type PwdLoginPool string + +const ( + PwdLoginAsUser = PwdLoginPool("user") // 用户池 + PwdLoginAsAdmin = PwdLoginPool("admin") // 管理员池 +) + +type TokenResp struct { + AccessToken string `json:"access_token"` + RefreshToken string `json:"refresh_token,omitempty"` + ExpiresIn int `json:"expires_in"` + TokenType string `json:"token_type"` + Scope string `json:"scope,omitempty"` +} + +type TokenErrResp struct { + Error string `json:"error"` + Description string `json:"error_description,omitempty"` +} + func authAuthorizationCode(c *fiber.Ctx, auth *AuthCtx, req *TokenReq, now time.Time) (*m.Session, error) { // 检查 code 获取用户授权信息 @@ -226,7 +278,7 @@ func authAuthorizationCode(c *fiber.Ctx, auth *AuthCtx, req *TokenReq, now time. session.RefreshTokenExpires = u.P(now.Add(time.Duration(env.SessionRefreshExpire) * time.Second)) } - err = SaveSession(session) + err = SaveSession(q.Q, session) if err != nil { return nil, err } @@ -249,7 +301,7 @@ func authClientCredential(c *fiber.Ctx, auth *AuthCtx, _ *TokenReq, now time.Tim } // 保存会话 - err := SaveSession(session) + err := SaveSession(q.Q, session) if err != nil { return nil, err } @@ -261,71 +313,85 @@ func authPassword(c *fiber.Ctx, auth *AuthCtx, req *TokenReq, now time.Time) (*m ip, _ := orm.ParseInet(c.IP()) // 可空字段,忽略异常 ua := u.X(c.Get(fiber.HeaderUserAgent)) + // 分池认证 + var err error var user *m.User - err := q.Q.Transaction(func(tx *q.Query) (err error) { - switch req.LoginType { - case GrantPasswordPhone: - user, err = authUserBySms(tx, req.Username, req.Password) - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - return err - } - if user == nil { - user = &m.User{ - Phone: req.Username, - Username: u.P(req.Username), - Status: m.UserStatusEnabled, - } - } - case GrantPasswordEmail: - user, err = authUserByEmail(tx, req.Username, req.Password) - if err != nil { - return err - } - case GrantPasswordSecret: - user, err = authUserByPassword(tx, req.Username, req.Password) - if err != nil { - return err - } - default: - return ErrAuthorizeInvalidRequest - } + var admin *m.Admin - // 账户状态 - if user.Status == m.UserStatusDisabled { - slog.Debug("账户状态异常", "username", req.Username, "status", user.Status) - return core.NewBizErr("账号无法登录") + pool := req.LoginPool + if pool == "" { + pool = PwdLoginAsUser + } + switch pool { + case PwdLoginAsUser: + user, err = authUser(req.LoginType, req.Username, req.Password) + if err != nil { + if req.LoginType != PwdLoginByPhone || !errors.Is(err, gorm.ErrRecordNotFound) { + return nil, err + } + + // 手机号首次登录的自动创建用户 + user = &m.User{ + Phone: req.Username, + Username: u.P(req.Username), + Status: m.UserStatusEnabled, + } } // 更新用户的登录时间 user.LastLogin = u.P(time.Now()) user.LastLoginIP = ip user.LastLoginUA = ua - if err := tx.User.Save(user); err != nil { - return err + + case PwdLoginAsAdmin: + admin, err = authAdmin(req.LoginType, req.Username, req.Password) + if err != nil { + return nil, err } - return nil - }) - if err != nil { - return nil, err + // 更新管理员登录时间 + admin.LastLogin = u.P(time.Now()) + admin.LastLoginIP = ip + admin.LastLoginUA = ua } // 生成会话 session := &m.Session{ IP: ip, UA: ua, - UserID: &user.ID, ClientID: &auth.Client.ID, Scopes: u.X(req.Scope), AccessToken: uuid.NewString(), AccessTokenExpires: now.Add(time.Duration(env.SessionAccessExpire) * time.Second), } + if user != nil { + session.UserID = &user.ID + } + if admin != nil { + session.AdminID = &admin.ID + } if req.Remember { session.RefreshToken = u.P(uuid.NewString()) session.RefreshTokenExpires = u.P(now.Add(time.Duration(env.SessionRefreshExpire) * time.Second)) } - err = SaveSession(session) + // 保存用户更新和会话 + err = q.Q.Transaction(func(tx *q.Query) error { + if err := SaveSession(tx, session); err != nil { + return err + } + if user != nil { + if err := tx.User.Save(user); err != nil { + return err + } + } + if admin != nil { + if err := tx.Admin.Save(admin); err != nil { + return err + } + } + return nil + }) if err != nil { return nil, err } @@ -353,7 +419,7 @@ func authRefreshToken(_ *fiber.Ctx, _ *AuthCtx, req *TokenReq, now time.Time) (* } // 保存令牌 - err = SaveSession(session) + err = SaveSession(q.Q, session) if err != nil { return nil, err } @@ -394,12 +460,85 @@ func sendError(c *fiber.Ctx, err error, description ...string) error { return err } -func Revoke() error { +// Revoke 令牌撤销端点 +func Revoke(ctx *fiber.Ctx) error { + _, err := GetAuthCtx(ctx).PermitUser() + if err != nil { + // 用户未登录 + return nil + } + + // 解析请求参数 + req := new(RevokeReq) + if err := ctx.BodyParser(req); err != nil { + return err + } + + // 删除会话 + err = RemoveSession(ctx.Context(), req.AccessToken, req.RefreshToken) + if err != nil { + return err + } + return nil } -func Introspect() error { - return nil +type RevokeReq struct { + AccessToken string `json:"access_token"` + RefreshToken string `json:"refresh_token"` +} + +// Introspect 令牌检查端点 +func Introspect(ctx *fiber.Ctx) error { + // 验证权限 + authCtx, err := GetAuthCtx(ctx).PermitUser() + if err != nil { + return err + } + + // 获取用户信息 + profile, err := q.User. + Where(q.User.ID.Eq(authCtx.User.ID)). + Omit(q.User.DeletedAt). + Take() + if err != nil { + return err + } + + // 检查用户是否设置了密码 + hasPassword := false + if profile.Password != nil && *profile.Password != "" { + hasPassword = true + profile.Password = nil // 不返回密码 + } + + // 掩码敏感信息 + if profile.Phone != "" { + profile.Phone = maskPhone(profile.Phone) + } + if profile.IDNo != nil && *profile.IDNo != "" { + profile.IDNo = u.P(maskIdNo(*profile.IDNo)) + } + return ctx.JSON(IntrospectResp{*profile, hasPassword}) +} + +type IntrospectResp struct { + m.User + HasPassword bool `json:"has_password"` // 是否设置了密码 +} + +func maskPhone(phone string) string { + if len(phone) < 11 { + return phone + } + return phone[:3] + "****" + phone[7:] +} + +func maskIdNo(idNo string) string { + if len(idNo) < 18 { + return idNo + } + return idNo[:3] + "*********" + idNo[14:] } type CodeContext struct { diff --git a/web/auth/authenticate.go b/web/auth/middleware.go similarity index 56% rename from web/auth/authenticate.go rename to web/auth/middleware.go index 0aa3ef5..1e6cb2e 100644 --- a/web/auth/authenticate.go +++ b/web/auth/middleware.go @@ -6,15 +6,10 @@ import ( "errors" "fmt" "log/slog" - "platform/web/core" - m "platform/web/models" - q "platform/web/queries" - s "platform/web/services" "strings" "time" "github.com/gofiber/fiber/v2" - "golang.org/x/crypto/bcrypt" ) func Authenticate() fiber.Handler { @@ -123,67 +118,3 @@ func authBasic(_ context.Context, token string) (*AuthCtx, error) { Scopes: []string{}, }, nil } - -func authClient(clientId, clientSecret string) (*m.Client, error) { - - // 获取客户端信息 - client, err := q.Client. - Where( - q.Client.ClientID.Eq(clientId), - q.Client.Status.Eq(1)). - Take() - if err != nil { - return nil, err - } - - // 检查客户端密钥 - if client.Spec == m.ClientSpecWeb || client.Spec == m.ClientSpecAPI { - if bcrypt.CompareHashAndPassword([]byte(client.ClientSecret), []byte(clientSecret)) != nil { - return nil, errors.New("客户端密钥错误") - } - } - - // todo 查询客户端关联权限 - - // 组织授权信息(一次性请求) - return client, nil -} - -func authUserBySms(tx *q.Query, username, code string) (*m.User, error) { - // 验证验证码 - err := s.Verifier.VerifySms(context.Background(), username, code) - if err != nil { - return nil, core.NewBizErr("短信认证失败:%w", err) - } - - // 查找用户 - return tx.User.Where(tx.User.Phone.Eq(username)).Take() -} - -func authUserByEmail(tx *q.Query, username, code string) (*m.User, error) { - return nil, core.NewServErr("邮箱登录不可用") -} - -func authUserByPassword(tx *q.Query, username, password string) (*m.User, error) { - user, err := tx.User. - Where(tx.User.Phone.Eq(username)). - Or(tx.User.Email.Eq(username)). - Or(tx.User.Username.Eq(username)). - Take() - if err != nil { - slog.Debug("查找用户失败", "error", err) - return nil, core.NewBizErr("用户不存在或密码错误") - } - - // 验证密码 - if user.Password == nil || *user.Password == "" { - slog.Debug("用户未设置密码", "username", username) - return nil, core.NewBizErr("用户不存在或密码错误") - } - if bcrypt.CompareHashAndPassword([]byte(*user.Password), []byte(password)) != nil { - slog.Debug("密码验证失败", "username", username) - return nil, core.NewBizErr("用户不存在或密码错误") - } - - return user, nil -} diff --git a/web/auth/session.go b/web/auth/session.go index b4aad68..82256ce 100644 --- a/web/auth/session.go +++ b/web/auth/session.go @@ -29,8 +29,8 @@ func FindSessionByRefresh(refreshToken string, now time.Time) (*m.Session, error ).First() } -func SaveSession(session *m.Session) error { - return q.Session.Save(session) +func SaveSession(tx *q.Query, session *m.Session) error { + return tx.Session.Save(session) } func RemoveSession(ctx context.Context, accessToken string, refreshToken string) error { diff --git a/web/handlers/auth.go b/web/handlers/auth.go deleted file mode 100644 index cb710fb..0000000 --- a/web/handlers/auth.go +++ /dev/null @@ -1,97 +0,0 @@ -package handlers - -import ( - "platform/pkg/u" - auth2 "platform/web/auth" - m "platform/web/models" - q "platform/web/queries" - - "github.com/gofiber/fiber/v2" -) - -// region /revoke - -type RevokeReq struct { - AccessToken string `json:"access_token"` - RefreshToken string `json:"refresh_token"` -} - -func Revoke(c *fiber.Ctx) error { - _, err := auth2.GetAuthCtx(c).PermitUser() - if err != nil { - // 用户未登录 - return nil - } - - // 解析请求参数 - req := new(RevokeReq) - if err := c.BodyParser(req); err != nil { - return err - } - - // 删除会话 - err = auth2.RemoveSession(c.Context(), req.AccessToken, req.RefreshToken) - if err != nil { - return err - } - - return nil -} - -// endregion - -// region /profile - -type IntrospectResp struct { - m.User - HasPassword bool `json:"has_password"` // 是否设置了密码 -} - -func Introspect(c *fiber.Ctx) error { - // 验证权限 - authCtx, err := auth2.GetAuthCtx(c).PermitUser() - if err != nil { - return err - } - - // 获取用户信息 - profile, err := q.User. - Where(q.User.ID.Eq(authCtx.User.ID)). - Omit(q.User.DeletedAt). - Take() - if err != nil { - return err - } - - // 检查用户是否设置了密码 - hasPassword := false - if profile.Password != nil && *profile.Password != "" { - hasPassword = true - profile.Password = nil // 不返回密码 - } - - // 掩码敏感信息 - if profile.Phone != "" { - profile.Phone = maskPhone(profile.Phone) - } - if profile.IDNo != nil && *profile.IDNo != "" { - profile.IDNo = u.P(maskIdNo(*profile.IDNo)) - } - return c.JSON(IntrospectResp{*profile, hasPassword}) -} - -func maskPhone(phone string) string { - if len(phone) < 11 { - return phone - } - return phone[:3] + "****" + phone[7:] -} - -func maskIdNo(idNo string) string { - if len(idNo) < 18 { - return idNo - } - return idNo[:3] + "*********" + idNo[14:] -} - -// endregion diff --git a/web/middlewares.go b/web/middlewares.go index 2b4a45d..7b74d07 100644 --- a/web/middlewares.go +++ b/web/middlewares.go @@ -5,6 +5,7 @@ import ( "github.com/gofiber/contrib/otelfiber/v2" "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/cors" "github.com/gofiber/fiber/v2/middleware/logger" "github.com/gofiber/fiber/v2/middleware/recover" "github.com/gofiber/fiber/v2/middleware/requestid" @@ -19,6 +20,14 @@ func ApplyMiddlewares(app *fiber.App) { EnableStackTrace: true, })) + // cors + app.Use(cors.New(cors.Config{ + AllowCredentials: true, + AllowOriginsFunc: func(origin string) bool { + return true + }, + })) + // logger app.Use(logger.New(logger.Config{ Next: func(c *fiber.Ctx) bool { diff --git a/web/routes.go b/web/routes.go index 33271bc..cc99ee6 100644 --- a/web/routes.go +++ b/web/routes.go @@ -13,9 +13,11 @@ func ApplyRouters(app *fiber.App) { // 认证 auth := api.Group("/auth") + auth.Get("/authorize", auth2.AuthorizeGet) + auth.Post("/authorize", auth2.AuthorizePost) auth.Post("/token", auth2.Token) - auth.Post("/revoke", handlers.Revoke) - auth.Post("/introspect", handlers.Introspect) + auth.Post("/revoke", auth2.Revoke) + auth.Post("/introspect", auth2.Introspect) auth.Post("/verify/sms", handlers.SmsCode) // 用户