You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
OneAuth/api/token/create.go

139 lines
3.9 KiB
Go

//
// post.go
// Copyright (C) 2025 veypi <i@veypi.com>
// 2025-05-09 17:26
// Distributed under terms of the MIT license.
//
package token
import (
"net/http"
"time"
"github.com/golang-jwt/jwt/v5"
6 months ago
"github.com/veypi/OneAuth/cfg"
"github.com/veypi/OneAuth/libs/auth"
"github.com/veypi/OneAuth/models"
"github.com/veypi/OneBD/rest"
"github.com/veypi/utils/logv"
)
type postOpts struct {
// 两种获取token方式一种用refreshtoken换取apptoken(应用登录)一种用密码加密code换refreshtoken (oa登录)
Refresh *string `json:"refresh" parse:"json"`
Typ *string `json:"typ" parse:"json"`
AppID *string `json:"app_id" gorm:"index;type:varchar(32)" parse:"json"`
ExpiredAt *time.Time `json:"expired_at" parse:"json"`
OverPerm *string `json:"over_perm" parse:"json"`
Device *string `json:"device" parse:"json"`
}
var _ = Router.Post("/", tokenPost)
// for user login app
func tokenPost(x *rest.X) (any, error) {
opts := &postOpts{}
err := x.Parse(opts)
if err != nil {
return nil, err
}
aid := cfg.Config.ID
if opts.AppID != nil && *opts.AppID != "" {
aid = *opts.AppID
}
data := &models.Token{}
claim := &auth.Claims{}
claim.IssuedAt = jwt.NewNumericDate(time.Now())
claim.Issuer = cfg.Config.ID
if opts.Refresh != nil {
typ := "app"
if opts.Typ != nil {
typ = *opts.Typ
}
// for other app redirect
refresh, err := auth.ParseJwt(*opts.Refresh)
if err != nil {
return nil, err
}
if refresh.ID == "" {
return nil, rest.ErrNotAuthorized
}
err = cfg.DB().Where("id = ?", refresh.ID).First(data).Error
if err != nil {
return nil, err
}
claim.AID = aid
claim.UID = refresh.UID
claim.Name = refresh.Name
claim.Icon = refresh.Icon
claim.ExpiresAt = jwt.NewNumericDate(time.Now().Add(time.Minute * 10))
if typ == "app" {
if refresh.AID == aid {
// refresh token
acList := make(auth.Access, 0, 10)
logv.AssertError(cfg.DB().Table("accesses a").
Select("a.name, a.t_id, a.level").
Joins("INNER JOIN user_roles ur ON ur.role_id = a.role_id AND ur.user_id = ? AND a.app_id = ?", refresh.UID, aid).
Scan(&acList).Error)
claim.Access = acList
if aid == cfg.Config.ID {
return auth.GenJwt(claim)
}
app := &models.App{}
err = cfg.DB().Where("id = ?", aid).First(app).Error
if err != nil {
return nil, err
}
return auth.GenJwtWithKey(claim, app.Key)
} else if refresh.ID == cfg.Config.ID {
// oa应用生成其他应用的refresh token
newToken := &models.Token{}
newToken.UserID = refresh.UID
newToken.AppID = aid
newToken.ExpiredAt = time.Now().Add(time.Hour * 24)
if opts.OverPerm != nil {
newToken.OverPerm = *opts.OverPerm
}
if opts.Device != nil {
newToken.Device = *opts.Device
}
newToken.Ip = x.GetRemoteIp()
logv.AssertError(cfg.DB().Create(newToken).Error)
// gen other app token
claim.ID = newToken.ID
claim.ExpiresAt = jwt.NewNumericDate(newToken.ExpiredAt)
return auth.GenJwt(claim)
} else {
return nil, rest.ErrNotPermitted
}
} else if typ == "ufs" {
claim.AID = refresh.AID
claim.UID = refresh.UID
claim.Name = refresh.Name
claim.Icon = refresh.Icon
claim.ExpiresAt = jwt.NewNumericDate(time.Now().Add(time.Minute * 10))
claim.Access = auth.Access{
{Name: "fs", TID: "/", Level: auth.Do},
}
token := logv.AssertFuncErr(auth.GenJwt(claim))
cookie := &http.Cookie{
Name: "fstoken", // Cookie 的名称
Value: token, // Cookie 的值
Path: "/fs/u/", // Cookie 的路径,通常是根路径
MaxAge: 600, // Cookie 的最大年龄,单位是秒
HttpOnly: true, // 是否仅限 HTTP(S) 访问
Secure: false, // 是否通过安全连接传输 Cookie
}
http.SetCookie(x, cookie)
return token, nil
} else {
return nil, rest.ErrArgInvalid
}
} else {
return nil, rest.ErrArgInvalid
}
}