package serve import ( "context" "fmt" "github.com/google/uuid" "github.com/loveuer/nf" "github.com/loveuer/nf/nft/log" "net/http" "time" "uauth/internal/opt" "uauth/internal/serve/handler" "uauth/internal/store/cache" "uauth/internal/tool" "uauth/model" ) func authenticateUser(username, password string) (bool, error) { // 这里你应该实现真实的用户认证逻辑 // 为了简化,我们这里直接硬编码一个用户名和密码 if username == "user" && password == "pass" { return true, nil } return false, fmt.Errorf("invalid username or password") } // 处理登录请求 func handleLogin(c *nf.Ctx) error { username := c.FormValue("username") password := c.FormValue("password") // 认证用户 ok, err := authenticateUser(username, password) if err != nil || !ok { return c.Status(http.StatusUnauthorized).SendString("Unauthorized") } // 用户认证成功,重定向到授权页面 http.Redirect(c.Writer, c.Request, "/authorize?client_id=12345&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fcallback&scope=read%20write", http.StatusFound) return nil } // 处理用户的授权批准 func handleApprove(c *nf.Ctx) error { // 获取表单数据 clientID := c.FormValue("client_id") redirectURI := c.FormValue("redirect_uri") scope := c.FormValue("scope") // 生成授权码 authorizationCode := uuid.New().String()[:8] log.Info("[D] client_id = %s, scope = %s, auth_code = %s", clientID, scope, authorizationCode) // 重定向到回调 URL 并附带授权码 http.Redirect(c.Writer, c.Request, redirectURI+"?code="+authorizationCode, http.StatusFound) return nil } // 令牌请求的处理 func handleToken(c *nf.Ctx) error { var ( err error grantType string code string redirectURI string // 记录 user accessToken string refreshToken string user = new(model.User) ) // 获取请求参数 grantType = c.FormValue("grant_type") code = cache.Prefix + c.FormValue("code") redirectURI = c.FormValue("redirect_uri") // 简单验证 if grantType != "authorization_code" { return c.Status(http.StatusBadRequest).SendString("Unsupported grant type") } if err = cache.Client.GetScan(tool.Timeout(3), code).Scan(&user); err != nil { return c.Status(http.StatusBadRequest).SendString("Invalid authorization code") } defer func() { // 清除已使用的授权码 cache.Client.Del(tool.Timeout(3), code) _ = redirectURI }() // 生成访问令牌 if accessToken, refreshToken, err = generateAccessToken(user); err != nil { return c.Status(http.StatusInternalServerError).SendString(err.Error()) } c.Writer.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") // 返回访问令牌 return c.JSON(map[string]string{ "access_token": accessToken, "refresh_token": refreshToken, "token_type": "bearer", "expires_in": "3600", // 访问令牌有效期(秒) }) } func generateAccessToken(user *model.User) (accessToken string, refreshToken string, err error) { if accessToken, err = user.JwtEncode(); err != nil { return } refreshToken = uuid.New().String()[:8] if err = cache.Client.SetEx(tool.Timeout(3), cache.Prefix+"refresh_token", refreshToken, 24*time.Hour); err != nil { return } if err = cache.Client.SetEx(tool.Timeout(3), cache.Prefix+"access_token", accessToken, time.Hour); err != nil { return } return } func Run(ctx context.Context) error { app := nf.New() api := app.Group(opt.Cfg.Svc.Prefix) // 设置路由 api.Post("/client/registry", handler.ClientRegistry) api.Get("/login", handler.LoginPage) api.Post("/login", handler.LoginAction) api.Get("/authorize", handler.Authorize) api.Post("/approve", handleApprove) api.Post("/token", handleToken) // 启动 HTTP 服务器 log.Info("Starting server on: %s", opt.Cfg.Svc.Address) go func() { <-ctx.Done() _ = app.Shutdown(tool.Timeout(2)) }() return app.Run(opt.Cfg.Svc.Address) }