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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

//
// 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"
"github.com/veypi/OneAuth/cfg"
"github.com/veypi/OneAuth/libs/auth"
"github.com/veypi/OneAuth/models"
"github.com/vyes/vigo"
"github.com/vyes/vigo/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 *vigo.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, vigo.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(cfg.Config.TokenExpire))
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, vigo.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(cfg.Config.TokenExpire))
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, vigo.ErrArgInvalid
}
} else {
return nil, vigo.ErrArgInvalid
}
}