Add oauth2 like auth service
All checks were successful
Build Backend (NixCN CMS) TeamCity build finished
Build Frontend (NixCN CMS) TeamCity build finished

Signed-off-by: Asai Neko <sugar@sne.moe>
This commit is contained in:
2026-01-02 15:57:42 +08:00
parent 62da1e096e
commit a98ab26fa4
12 changed files with 292 additions and 83 deletions

View File

@@ -1,15 +1,12 @@
package auth
import (
"nixcn-cms/data"
"nixcn-cms/internal/cryptography"
"net/url"
"nixcn-cms/pkgs/authcode"
"nixcn-cms/pkgs/email"
"nixcn-cms/pkgs/turnstile"
"github.com/google/uuid"
log "github.com/sirupsen/logrus"
"gorm.io/gorm"
"github.com/gin-gonic/gin"
"github.com/spf13/viper"
@@ -43,15 +40,23 @@ func Magic(c *gin.Context) {
c.JSON(500, gin.H{"status": "code gen failed"})
}
uri := viper.GetString("server.external_url") +
"/api/v1/auth/redirect?" +
"code=" + code +
"&redirect_uri=" + req.RedirectUri +
"&state=" + req.State
externalUrl := viper.GetString("server.external_url")
url, err := url.Parse(externalUrl)
if err != nil {
c.JSON(500, gin.H{"status": "invalid external url"})
}
debugMode := viper.GetString("server.debug_mode")
if debugMode == "true" {
log.Info("Magic link for " + req.Email + " : " + uri)
url.Path = "/api/v1/auth/redirect"
query := url.Query()
query.Set("code", code)
query.Set("redirect_uri", req.RedirectUri)
query.Set("state", req.State)
url.RawQuery = query.Encode()
debugMode := viper.GetBool("server.debug_mode")
if debugMode {
c.JSON(200, gin.H{"status": "magiclink sent", "uri": url.String()})
return
} else {
// Send email using resend
resend, err := email.NewResendClient()
@@ -63,61 +68,9 @@ func Magic(c *gin.Context) {
resend.Send(
req.Email,
"NixCN CMS Email Verify",
"<p>Click the link below to verify your email. This link will expire in 10 minutes.</p><a href="+uri+">"+uri+"</a>",
"<p>Click the link below to verify your email. This link will expire in 10 minutes.</p><a href="+url.String()+">"+url.String()+"</a>",
)
}
c.JSON(200, gin.H{"status": "magic link sent"})
}
func VerifyMagicLink(c *gin.Context) {
// Get token from url
magicToken := c.Query("token")
if magicToken == "" {
c.JSON(400, gin.H{"error": "missing token"})
return
}
// Verify email token
email, ok := authcode.VerifyAuthCode(magicToken)
if !ok {
c.JSON(401, gin.H{"error": "invalid or expired token"})
return
}
// Verify if user exists
userData := new(data.User)
user, err := userData.GetByEmail(email)
if err != nil {
if err == gorm.ErrRecordNotFound {
// Create user
user.UUID = uuid.New()
user.UserId = uuid.New()
user.Email = email
user.PermissionLevel = 10
if err := user.Create(); err != nil {
c.JSON(500, gin.H{"status": "internal server error"})
return
}
} else {
c.JSON(500, gin.H{"status": "internal server error"})
return
}
}
// Generate jwt
JwtTool := cryptography.Token{
Application: viper.GetString("server.application"),
}
accessToken, refreshToken, err := JwtTool.IssueTokens(user.UserId)
if err != nil {
c.JSON(500, gin.H{"status": "error generating tokens"})
return
}
c.JSON(200, gin.H{
"access_token": accessToken,
"refresh_token": refreshToken,
})
}