wip: 继续 oauth

This commit is contained in:
loveuer
2024-10-25 18:18:11 +08:00
parent a17b9bb16b
commit 4822fbc092
8 changed files with 270 additions and 87 deletions

34
internal/client/client.go Normal file
View File

@ -0,0 +1,34 @@
package client
import (
"context"
"github.com/google/uuid"
"golang.org/x/oauth2"
"golang.org/x/oauth2/authhandler"
)
var (
State = uuid.New().String()[:8]
)
func Run(ctx context.Context) error {
oauth2.NewClient(ctx, authhandler.TokenSource(
ctx,
&oauth2.Config{
ClientID: "",
ClientSecret: "",
Endpoint: oauth2.Endpoint{
AuthURL: "",
DeviceAuthURL: "",
TokenURL: "",
AuthStyle: 0,
},
RedirectURL: "",
Scopes: nil,
},
State,
func(authCodeURL string) (code string, state string, err error) {
},
))
}

View File

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"
>
<title>Client Login</title>
<style>
body {
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
}
</style>
</head>
<body>
<div>
<h3>这里是 xx 产品登录页面</h3>
<form>
<fieldset>
<label>
Username
<input
name="username"
placeholder="username"
autocomplete="given-name"
/>
</label>
<label>
Password
<input
type="password"
name="password"
placeholder="password"
autocomplete="password"
/>
</label>
</fieldset>
<input
type="submit"
value="登录"
/>
<a href="http://localhost:8080/api/oauth/v2/login?client_id=test&client_secret=test&scope=test1,test2&redirect_uri=http://localhost:9119/api/login/callback">使用 Pro 账号登录</a>
</form>
</div>
</body>
</html>

View File

@ -0,0 +1,39 @@
package handler
import (
"github.com/loveuer/nf"
"net/http"
)
func Authorize(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(`
<html>
<head><title>Authorization</title></head>
<body>
<h1>Do you want to authorize this application?</h1>
<form action="/approve" method="post">
<input type="hidden" name="client_id" value="` + clientID + `"/>
<input type="hidden" name="redirect_uri" value="` + redirectURI + `"/>
<input type="hidden" name="scope" value="` + scope + `"/>
<button type="submit">Yes, I authorize</button>
</form>
</body>
</html>
`))
return err
}

View File

@ -0,0 +1,77 @@
package handler
import (
_ "embed"
"github.com/loveuer/nf"
"github.com/loveuer/nf/nft/resp"
"net/http"
"net/url"
)
var (
//go:embed serve_login.html
page string
)
func LoginPage(c *nf.Ctx) error {
type Req struct {
ClientID string `query:"client_id"`
ClientSecret string `query:"client_secret"`
Scope string `query:"scope"`
RedirectURI string `query:"redirect_uri"`
}
var (
err error
req = new(Req)
)
if err = c.QueryParser(req); err != nil {
return resp.Resp400(c, err.Error())
}
if req.ClientID == "" || req.ClientSecret == "" || req.RedirectURI == "" {
return resp.Resp400(c, req)
}
// todo: 验证 client id, client secret, scoop
// todo: 如果用户是已登录状态,则直接带上信息返回到 authorize 页面
return c.RenderHTML("login", page, map[string]interface{}{
"client_id": req.ClientID,
"client_secret": req.ClientSecret,
"redirect_uri": req.RedirectURI,
"scope": req.Scope,
})
}
func LoginAction(c *nf.Ctx) error {
type Req struct {
Username string `form:"username"`
Password string `form:"password"`
ClientId string `form:"client_id"`
ClientSecret string `form:"client_secret"`
RedirectURI string `form:"redirect_uri"`
Scope string `form:"scope"`
}
var (
err error
req = new(Req)
)
if err = c.BodyParser(req); err != nil {
return resp.Resp400(c, err.Error())
}
// todo: 验证用户登录是否成功,等等
queries := make(url.Values)
queries.Add("client_id", req.ClientId)
queries.Add("client_secret", req.ClientSecret)
queries.Add("redirect_uri", req.RedirectURI)
queries.Add("scope", req.Scope)
return c.Redirect("/api/oauth/v2/authorize?"+queries.Encode(), http.StatusFound)
}

View File

@ -0,0 +1,55 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.jade.min.css"
>
<title>Server Login</title>
<style>
body {
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
}
</style>
</head>
<body>
<div>
<h3>欢迎来到 Pro</h3>
<form action="/api/oauth/v2/login" method="POST">
<fieldset>
<label>
Username
<input
name="username"
placeholder="username"
autocomplete="given-name"
/>
</label>
<label>
Password
<input
type="password"
name="password"
placeholder="password"
autocomplete="password"
/>
</label>
<input type="hidden" name="client_id" value="{{ .client_id }}"/>
<input type="hidden" name="client_secret" value="{{ .client_secret }}"/>
<input type="hidden" name="redirect_uri" value="{{ .redirect_uri }}"/>
<input type="hidden" name="scope" value="{{ .scope }}"/>
</fieldset>
<input
type="submit"
value="登录"
/>
</form>
</div>
</body>
</html>

View File

@ -9,6 +9,7 @@ import (
"net/http"
"time"
"uauth/internal/opt"
"uauth/internal/serve/handler"
"uauth/internal/store/cache"
"uauth/internal/tool"
"uauth/model"
@ -41,39 +42,6 @@ func handleLogin(c *nf.Ctx) error {
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(`
<html>
<head><title>Authorization</title></head>
<body>
<h1>Do you want to authorize this application?</h1>
<form action="/approve" method="post">
<input type="hidden" name="client_id" value="` + clientID + `"/>
<input type="hidden" name="redirect_uri" value="` + redirectURI + `"/>
<input type="hidden" name="scope" value="` + scope + `"/>
<button type="submit">Yes, I authorize</button>
</form>
</body>
</html>
`))
return err
}
// 处理用户的授权批准
func handleApprove(c *nf.Ctx) error {
// 获取表单数据
@ -164,8 +132,9 @@ func Run(ctx context.Context) error {
api := app.Group(opt.Cfg.Svc.Prefix)
// 设置路由
api.Get("/login", handleLogin)
api.Get("/authorize", handleAuthorize)
api.Get("/login", handler.LoginPage)
api.Post("/login", handler.LoginAction)
api.Get("/authorize", handler.Authorize)
api.Post("/approve", handleApprove)
api.Post("/token", handleToken)