基础信息展示
This commit is contained in:
parent
034260391d
commit
bf5e5cae87
@ -1,4 +1,5 @@
|
|||||||
import type { tokenData } from '@/apis/model'
|
import type { tokenData, ApiUser } from '@/apis/model'
|
||||||
|
import { apiWrapGet } from '@/apis/utils'
|
||||||
|
|
||||||
export async function login(username: string, password: string) {
|
export async function login(username: string, password: string) {
|
||||||
const v = await fetch(import.meta.env.VITE_APIADDR + "/api/yggdrasil/authserver/authenticate", {
|
const v = await fetch(import.meta.env.VITE_APIADDR + "/api/yggdrasil/authserver/authenticate", {
|
||||||
@ -25,9 +26,16 @@ export async function register(email: string, username: string, password: string
|
|||||||
"CaptchaToken": captchaToken
|
"CaptchaToken": captchaToken
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
const data = await v.json()
|
return await apiWrapGet(v)
|
||||||
if (!v.ok) {
|
|
||||||
throw data.msg
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function userInfo(token: string) {
|
||||||
|
if (token == "") return
|
||||||
|
const v = await fetch(import.meta.env.VITE_APIADDR + "/api/v1/user", {
|
||||||
|
headers: {
|
||||||
|
"Authorization": "Bearer " + token
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return await apiWrapGet<ApiUser>(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -19,3 +19,10 @@ interface captcha {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type ApiCaptcha = Api<captcha>
|
export type ApiCaptcha = Api<captcha>
|
||||||
|
|
||||||
|
interface user {
|
||||||
|
uid: string
|
||||||
|
uuid: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ApiUser = Api<user>
|
||||||
|
7
frontend/src/apis/utils.ts
Normal file
7
frontend/src/apis/utils.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export async function apiWrapGet<T>(v: Response) {
|
||||||
|
const data = await v.json()
|
||||||
|
if (!v.ok) {
|
||||||
|
throw data.msg
|
||||||
|
}
|
||||||
|
return data as T
|
||||||
|
}
|
@ -20,7 +20,7 @@ const CaptchaWidget = forwardRef<refType, prop>(({ onSuccess }, ref) => {
|
|||||||
const Turnstileref = useRef<TurnstileInstance>(null)
|
const Turnstileref = useRef<TurnstileInstance>(null)
|
||||||
const [key, setKey] = useState(1)
|
const [key, setKey] = useState(1)
|
||||||
const { data, error, loading } = useRequest(() => fetch(import.meta.env.VITE_APIADDR + '/api/v1/captcha').then(v => v.json() as Promise<ApiCaptcha>), {
|
const { data, error, loading } = useRequest(() => fetch(import.meta.env.VITE_APIADDR + '/api/v1/captcha').then(v => v.json() as Promise<ApiCaptcha>), {
|
||||||
loadingDelay: 500
|
loadingDelay: 200
|
||||||
})
|
})
|
||||||
|
|
||||||
useImperativeHandle(ref, () => {
|
useImperativeHandle(ref, () => {
|
||||||
|
@ -1,15 +1,28 @@
|
|||||||
import { token, username } from "@/store/store"
|
import { token, username } from "@/store/store"
|
||||||
|
import { useRequest } from "ahooks"
|
||||||
import { useAtomValue } from "jotai"
|
import { useAtomValue } from "jotai"
|
||||||
|
import { userInfo } from '@/apis/apis'
|
||||||
|
|
||||||
export default function User() {
|
export default function User() {
|
||||||
const nowToken = useAtomValue(token)
|
const nowToken = useAtomValue(token)
|
||||||
const nowUsername = useAtomValue(username)
|
const nowUsername = useAtomValue(username)
|
||||||
|
|
||||||
|
const { data, error } = useRequest(() => userInfo(nowToken), {
|
||||||
|
refreshDeps: [nowToken],
|
||||||
|
cacheKey: "/api/v1/user/reg",
|
||||||
|
cacheTime: 10000
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<p>你好: {nowUsername}</p>
|
<p>你好: {nowUsername}</p>
|
||||||
<p>token: {nowToken} </p>
|
<p>token: {nowToken} </p>
|
||||||
|
{error && String(error)}
|
||||||
|
{!error && <>
|
||||||
|
<p>uid: {data?.data.uid}</p>
|
||||||
|
<p>uuid: {data?.data.uuid}</p>
|
||||||
|
</>}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
@ -1,10 +1,19 @@
|
|||||||
package handle
|
package handle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"net/netip"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/samber/lo"
|
||||||
"github.com/xmdhs/authlib-skin/config"
|
"github.com/xmdhs/authlib-skin/config"
|
||||||
|
"github.com/xmdhs/authlib-skin/model"
|
||||||
"github.com/xmdhs/authlib-skin/service"
|
"github.com/xmdhs/authlib-skin/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -23,3 +32,34 @@ func NewHandel(webService *service.WebService, validate *validator.Validate, con
|
|||||||
logger: logger,
|
logger: logger,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func encodeJson[T any](w io.Writer, m model.API[T]) {
|
||||||
|
json.NewEncoder(w).Encode(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handel) getTokenbyAuthorization(ctx context.Context, w http.ResponseWriter, r *http.Request) string {
|
||||||
|
auth := r.Header.Get("Authorization")
|
||||||
|
if auth == "" {
|
||||||
|
h.logger.DebugContext(ctx, "缺少 Authorization")
|
||||||
|
handleError(ctx, w, "缺少 Authorization", model.ErrAuth, 401)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
al := strings.Split(auth, " ")
|
||||||
|
if len(al) != 2 || al[0] != "Bearer" {
|
||||||
|
h.logger.DebugContext(ctx, "Authorization 格式错误")
|
||||||
|
handleError(ctx, w, "Authorization 格式错误", model.ErrAuth, 401)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return al[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPrefix(ip string) (string, error) {
|
||||||
|
ipa, err := netip.ParseAddr(ip)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("getPrefix: %w", err)
|
||||||
|
}
|
||||||
|
if ipa.Is6() {
|
||||||
|
return lo.Must1(ipa.Prefix(48)).String(), nil
|
||||||
|
}
|
||||||
|
return lo.Must1(ipa.Prefix(24)).String(), nil
|
||||||
|
}
|
||||||
|
@ -1,16 +1,13 @@
|
|||||||
package handle
|
package handle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/netip"
|
|
||||||
|
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
"github.com/samber/lo"
|
|
||||||
"github.com/xmdhs/authlib-skin/model"
|
"github.com/xmdhs/authlib-skin/model"
|
||||||
"github.com/xmdhs/authlib-skin/service"
|
"github.com/xmdhs/authlib-skin/service"
|
||||||
|
utilsService "github.com/xmdhs/authlib-skin/service/utils"
|
||||||
"github.com/xmdhs/authlib-skin/utils"
|
"github.com/xmdhs/authlib-skin/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -53,22 +50,34 @@ func (h *Handel) Reg() httprouter.Handle {
|
|||||||
handleError(ctx, w, err.Error(), model.ErrService, 500)
|
handleError(ctx, w, err.Error(), model.ErrService, 500)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
json.NewEncoder(w).Encode(model.API[any]{
|
encodeJson(w, model.API[any]{
|
||||||
Code: 0,
|
Code: 0,
|
||||||
Data: nil,
|
|
||||||
Msg: "",
|
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPrefix(ip string) (string, error) {
|
func (h *Handel) UserInfo() httprouter.Handle {
|
||||||
ipa, err := netip.ParseAddr(ip)
|
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||||
if err != nil {
|
ctx := r.Context()
|
||||||
return "", fmt.Errorf("getPrefix: %w", err)
|
token := h.getTokenbyAuthorization(ctx, w, r)
|
||||||
|
if token == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := h.webService.Info(ctx, token)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, utilsService.ErrTokenInvalid) {
|
||||||
|
h.logger.DebugContext(ctx, "token 无效")
|
||||||
|
handleError(ctx, w, "token 无效", model.ErrAuth, 401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h.logger.InfoContext(ctx, err.Error())
|
||||||
|
handleError(ctx, w, err.Error(), model.ErrUnknown, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
encodeJson(w, model.API[model.UserInfo]{
|
||||||
|
Code: 0,
|
||||||
|
Data: u,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
if ipa.Is6() {
|
|
||||||
return lo.Must1(ipa.Prefix(48)).String(), nil
|
|
||||||
}
|
|
||||||
return lo.Must1(ipa.Prefix(24)).String(), nil
|
|
||||||
}
|
}
|
||||||
|
@ -9,4 +9,5 @@ const (
|
|||||||
ErrService
|
ErrService
|
||||||
ErrExistUser
|
ErrExistUser
|
||||||
ErrRegLimit
|
ErrRegLimit
|
||||||
|
ErrAuth
|
||||||
)
|
)
|
||||||
|
@ -29,3 +29,8 @@ type Captcha struct {
|
|||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
SiteKey string `json:"siteKey"`
|
SiteKey string `json:"siteKey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UserInfo struct {
|
||||||
|
UID int `json:"uid"`
|
||||||
|
UUID string `json:"uuid"`
|
||||||
|
}
|
||||||
|
@ -11,6 +11,10 @@ import (
|
|||||||
|
|
||||||
func NewRoute(yggService *yggdrasil.Yggdrasil, handel *handle.Handel) (*httprouter.Router, error) {
|
func NewRoute(yggService *yggdrasil.Yggdrasil, handel *handle.Handel) (*httprouter.Router, error) {
|
||||||
r := httprouter.New()
|
r := httprouter.New()
|
||||||
|
r.HandleOPTIONS = true
|
||||||
|
r.GlobalOPTIONS = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(204)
|
||||||
|
})
|
||||||
err := newYggdrasil(r, *yggService)
|
err := newYggdrasil(r, *yggService)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("NewRoute: %w", err)
|
return nil, fmt.Errorf("NewRoute: %w", err)
|
||||||
@ -19,17 +23,6 @@ func NewRoute(yggService *yggdrasil.Yggdrasil, handel *handle.Handel) (*httprout
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("NewRoute: %w", err)
|
return nil, fmt.Errorf("NewRoute: %w", err)
|
||||||
}
|
}
|
||||||
r.GlobalOPTIONS = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if r.Header.Get("Access-Control-Request-Method") != "" {
|
|
||||||
// Set CORS headers
|
|
||||||
header := w.Header()
|
|
||||||
header.Set("Access-Control-Allow-Methods", header.Get("Allow"))
|
|
||||||
header.Set("Access-Control-Allow-Origin", "*")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adjust status code to 204
|
|
||||||
w.WriteHeader(http.StatusNoContent)
|
|
||||||
})
|
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,5 +54,6 @@ func newYggdrasil(r *httprouter.Router, handelY yggdrasil.Yggdrasil) error {
|
|||||||
func newSkinApi(r *httprouter.Router, handel *handle.Handel) error {
|
func newSkinApi(r *httprouter.Router, handel *handle.Handel) error {
|
||||||
r.PUT("/api/v1/user/reg", handel.Reg())
|
r.PUT("/api/v1/user/reg", handel.Reg())
|
||||||
r.GET("/api/v1/captcha", handel.GetCaptcha())
|
r.GET("/api/v1/captcha", handel.GetCaptcha())
|
||||||
|
r.GET("/api/v1/user", handel.UserInfo())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -33,9 +33,22 @@ func NewServer(c config.Config, sl *slog.Logger, route *httprouter.Router) (*htt
|
|||||||
if c.Debug && sl.Enabled(ctx, slog.LevelDebug) {
|
if c.Debug && sl.Enabled(ctx, slog.LevelDebug) {
|
||||||
sl.DebugContext(ctx, r.Method)
|
sl.DebugContext(ctx, r.Method)
|
||||||
}
|
}
|
||||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
cors(route).ServeHTTP(w, r)
|
||||||
route.ServeHTTP(w, r)
|
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
return s, func() { s.Close() }
|
return s, func() { s.Close() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cors(h http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
header := w.Header()
|
||||||
|
if r.Header.Get("Access-Control-Request-Method") != "" {
|
||||||
|
header.Set("Access-Control-Allow-Methods", r.Header.Get("Access-Control-Request-Method"))
|
||||||
|
}
|
||||||
|
header.Set("Access-Control-Allow-Origin", "*")
|
||||||
|
header.Set("Access-Control-Allow-Headers", "*")
|
||||||
|
header.Set("Access-Control-Allow-Private-Network", "true")
|
||||||
|
header.Set("Access-Control-Max-Age", "3600")
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -52,7 +52,7 @@ func InitializeRoute(ctx context.Context, c config.Config) (*http.Server, func()
|
|||||||
}
|
}
|
||||||
yggdrasil3 := yggdrasil2.NewYggdrasil(logger, validate, yggdrasilYggdrasil, c, pubRsaKey)
|
yggdrasil3 := yggdrasil2.NewYggdrasil(logger, validate, yggdrasilYggdrasil, c, pubRsaKey)
|
||||||
httpClient := ProvideHttpClient()
|
httpClient := ProvideHttpClient()
|
||||||
webService := service.NewWebService(c, client, httpClient)
|
webService := service.NewWebService(c, client, httpClient, cache, privateKey)
|
||||||
handel := handle.NewHandel(webService, validate, c, logger)
|
handel := handle.NewHandel(webService, validate, c, logger)
|
||||||
router, err := route.NewRoute(yggdrasil3, handel)
|
router, err := route.NewRoute(yggdrasil3, handel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -12,6 +12,8 @@ import (
|
|||||||
"github.com/xmdhs/authlib-skin/db/ent/user"
|
"github.com/xmdhs/authlib-skin/db/ent/user"
|
||||||
"github.com/xmdhs/authlib-skin/db/ent/userprofile"
|
"github.com/xmdhs/authlib-skin/db/ent/userprofile"
|
||||||
"github.com/xmdhs/authlib-skin/model"
|
"github.com/xmdhs/authlib-skin/model"
|
||||||
|
"github.com/xmdhs/authlib-skin/model/yggdrasil"
|
||||||
|
utilsService "github.com/xmdhs/authlib-skin/service/utils"
|
||||||
"github.com/xmdhs/authlib-skin/utils"
|
"github.com/xmdhs/authlib-skin/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -88,3 +90,14 @@ func (w *WebService) Reg(ctx context.Context, u model.User, ipPrefix, ip string)
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *WebService) Info(ctx context.Context, token string) (model.UserInfo, error) {
|
||||||
|
t, err := utilsService.Auth(ctx, yggdrasil.ValidateToken{AccessToken: token}, w.client, w.cache, &w.prikey.PublicKey, false)
|
||||||
|
if err != nil {
|
||||||
|
return model.UserInfo{}, fmt.Errorf("Info: %w", err)
|
||||||
|
}
|
||||||
|
return model.UserInfo{
|
||||||
|
UID: t.UID,
|
||||||
|
UUID: t.Subject,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/rsa"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/xmdhs/authlib-skin/config"
|
"github.com/xmdhs/authlib-skin/config"
|
||||||
|
"github.com/xmdhs/authlib-skin/db/cache"
|
||||||
"github.com/xmdhs/authlib-skin/db/ent"
|
"github.com/xmdhs/authlib-skin/db/ent"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -11,12 +13,16 @@ type WebService struct {
|
|||||||
config config.Config
|
config config.Config
|
||||||
client *ent.Client
|
client *ent.Client
|
||||||
httpClient *http.Client
|
httpClient *http.Client
|
||||||
|
cache cache.Cache
|
||||||
|
prikey *rsa.PrivateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWebService(c config.Config, e *ent.Client, hc *http.Client) *WebService {
|
func NewWebService(c config.Config, e *ent.Client, hc *http.Client, cache cache.Cache, prikey *rsa.PrivateKey) *WebService {
|
||||||
return &WebService{
|
return &WebService{
|
||||||
config: c,
|
config: c,
|
||||||
client: e,
|
client: e,
|
||||||
httpClient: hc,
|
httpClient: hc,
|
||||||
|
cache: cache,
|
||||||
|
prikey: prikey,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user