commit eb1744bd0dd73d33aedfaa8e3628c5cdb403b0b5 Author: loveuer Date: Wed Oct 23 17:46:15 2024 +0800 wip: 刚刚开始, 探索阶段 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ebf869b --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea +.vscode +.DS_Store \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..d4965db --- /dev/null +++ b/go.mod @@ -0,0 +1,19 @@ +module uauth + +go 1.20 + +require ( + github.com/google/uuid v1.6.0 + github.com/gorilla/mux v1.8.1 + github.com/loveuer/nf v0.2.11 + github.com/spf13/cobra v1.8.1 +) + +require ( + github.com/fatih/color v1.17.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/spf13/pflag v1.0.5 // indirect + golang.org/x/sys v0.20.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e289871 --- /dev/null +++ b/go.sum @@ -0,0 +1,27 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/loveuer/nf v0.2.11 h1:W775exDO8eNAHT45WDhXekMYCuWahOW9t1aVmGh3u1o= +github.com/loveuer/nf v0.2.11/go.mod h1:M6reF17/kJBis30H4DxR5hrtgo/oJL4AV4cBe4HzJLw= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/httptest/uauth/auth req.bru b/httptest/uauth/auth req.bru new file mode 100644 index 0000000..6ca096c --- /dev/null +++ b/httptest/uauth/auth req.bru @@ -0,0 +1,18 @@ +meta { + name: auth req + type: http + seq: 2 +} + +get { + url: http://127.0.0.1:8080/authorize?client_id=12345&response_type=code&redirect_uri=http://localhost:8080/callback&scopde=balaba + body: none + auth: none +} + +params:query { + client_id: 12345 + response_type: code + redirect_uri: http://localhost:8080/callback + scopde: balaba +} diff --git a/httptest/uauth/bruno.json b/httptest/uauth/bruno.json new file mode 100644 index 0000000..c46c40c --- /dev/null +++ b/httptest/uauth/bruno.json @@ -0,0 +1,9 @@ +{ + "version": "1", + "name": "uauth", + "type": "collection", + "ignore": [ + "node_modules", + ".git" + ] +} \ No newline at end of file diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go new file mode 100644 index 0000000..9314c39 --- /dev/null +++ b/internal/cmd/cmd.go @@ -0,0 +1,30 @@ +package cmd + +import ( + "github.com/loveuer/nf/nft/log" + "github.com/spf13/cobra" + "uauth/internal/opt" +) + +var ( + Command = &cobra.Command{ + Use: "uauth", + Short: "uauth: oauth v2 server", + Example: "", + PersistentPreRun: func(cmd *cobra.Command, args []string) { + if opt.Cfg.Debug { + log.SetLogLevel(log.LogLevelDebug) + } + }, + } +) + +func init() { + Command.PersistentFlags().BoolVar(&opt.Cfg.Debug, "debug", false, "debug mode") + + initServe() + + Command.AddCommand( + initServe(), + ) +} diff --git a/internal/cmd/serve.go b/internal/cmd/serve.go new file mode 100644 index 0000000..f15a012 --- /dev/null +++ b/internal/cmd/serve.go @@ -0,0 +1,11 @@ +package cmd + +import "github.com/spf13/cobra" + +func initServe() *cobra.Command { + serve := &cobra.Command{ + Use: "serve", + } + + return serve +} diff --git a/internal/opt/config.go b/internal/opt/config.go new file mode 100644 index 0000000..abb24f1 --- /dev/null +++ b/internal/opt/config.go @@ -0,0 +1,9 @@ +package opt + +type config struct { + Debug bool `json:"debug"` +} + +var ( + Cfg = config{} +) diff --git a/main.go b/main.go new file mode 100644 index 0000000..81bf409 --- /dev/null +++ b/main.go @@ -0,0 +1,100 @@ +package main + +import ( + "fmt" + "github.com/google/uuid" + "github.com/loveuer/nf" + "log" + "net/http" +) + +// 假设这是你的用户认证函数 +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 handleAuthorize(c *nf.Ctx) error { + // 解析查询参数 + clientID := c.Query("client_id") + responseType := c.Query("response_type") + redirectURI := c.Query("redirect_uri") + scope := c.Query("scope") + + // 检查客户端 ID 和其他参数 + // 在实际应用中,你需要检查这些参数是否合法 + if clientID != "12345" || responseType != "code" || redirectURI != "http://localhost:8080/callback" { + return c.Status(http.StatusBadRequest).SendString("Invalid request") + } + + // 显示授权页面给用户 + _, err := c.Write([]byte(` + + Authorization + +

Do you want to authorize this application?

+
+ + + + +
+ + + `)) + + return err +} + +// 处理用户的授权批准 +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.Printf("[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 main() { + app := nf.New() + + // 设置路由 + app.Get("/login", handleLogin) + app.Get("/authorize", handleAuthorize) + app.Post("/approve", handleApprove) + + // 启动 HTTP 服务器 + log.Println("Starting server on :8080") + log.Fatal(app.Run(":8080")) +} diff --git a/model/user.go b/model/user.go new file mode 100644 index 0000000..7537c61 --- /dev/null +++ b/model/user.go @@ -0,0 +1,23 @@ +package model + +type Status int64 + +type User struct { + Id uint64 `json:"id" gorm:"primaryKey;column:id"` + CreatedAt int64 `json:"created_at" gorm:"column:created_at;autoCreateTime:milli"` + UpdatedAt int64 `json:"updated_at" gorm:"column:updated_at;autoUpdateTime:milli"` + DeletedAt int64 `json:"deleted_at" gorm:"index;column:deleted_at;default:0"` + + Username string `json:"username" gorm:"column:username;type:varchar(64);unique"` + Password string `json:"-" gorm:"column:password;type:varchar(256)"` + + Status Status `json:"status" gorm:"column:status;default:0"` + + Nickname string `json:"nickname" gorm:"column:nickname;type:varchar(64)"` + Comment string `json:"comment" gorm:"column:comment"` + + CreatedById uint64 `json:"created_by_id" gorm:"column:created_by_id"` + CreatedByName string `json:"created_by_name" gorm:"column:created_by_name;type:varchar(64)"` + + LoginAt int64 `json:"login_at" gorm:"-"` +}