diff --git a/devcloud/mcenter/apps/token/README.md b/devcloud/mcenter/apps/token/README.md index 2f9dbcf..ee07544 100644 --- a/devcloud/mcenter/apps/token/README.md +++ b/devcloud/mcenter/apps/token/README.md @@ -33,3 +33,28 @@ type Service interface { } ``` + +## 接口的实现 + +```go +func TestIssueToken(t *testing.T) { + req := token.NewIssueTokenRequest() + req.IssueByPassword("admin", "123456") + req.Source = token.SOURCE_WEB + set, err := svc.IssueToken(ctx, req) + if err != nil { + t.Fatal(err) + } + t.Log(set) +} + +func TestQueryToken(t *testing.T) { + req := token.NewQueryTokenRequest() + set, err := svc.QueryToken(ctx, req) + if err != nil { + t.Fatal(err) + } + t.Log(set) +} +``` + diff --git a/devcloud/mcenter/apps/token/api/api.go b/devcloud/mcenter/apps/token/api/api.go index fc32e97..79aaa8e 100644 --- a/devcloud/mcenter/apps/token/api/api.go +++ b/devcloud/mcenter/apps/token/api/api.go @@ -11,27 +11,27 @@ import ( ) func init() { - ioc.Api().Registry(&TokenRestulApiHandler{}) + ioc.Api().Registry(&TokenRestfulApiHandler{}) } -type TokenRestulApiHandler struct { +type TokenRestfulApiHandler struct { ioc.ObjectImpl // 依赖控制器 svc token.Service } -func (h *TokenRestulApiHandler) Name() string { +func (h *TokenRestfulApiHandler) Name() string { return token.APP_NAME } //go:embed docs/login.md var loginApiDocNotes string -func (h *TokenRestulApiHandler) Init() error { +func (h *TokenRestfulApiHandler) Init() error { h.svc = token.GetService() - tags := []string{"用户登录"} + tags := []string{"登录管理"} ws := gorestful.ObjectRouter(h) ws.Route(ws.POST("").To(h.Login). Doc("颁发令牌(登录)"). diff --git a/devcloud/mcenter/apps/token/api/token.go b/devcloud/mcenter/apps/token/api/token.go index 0dc60aa..f53415e 100644 --- a/devcloud/mcenter/apps/token/api/token.go +++ b/devcloud/mcenter/apps/token/api/token.go @@ -10,7 +10,7 @@ import ( "github.com/infraboard/mcube/v2/ioc/config/application" ) -func (h *TokenRestulApiHandler) Login(r *restful.Request, w *restful.Response) { +func (h *TokenRestfulApiHandler) Login(r *restful.Request, w *restful.Response) { // 1. 获取用户的请求参数, 参数在Body里面 req := token.NewIssueTokenRequest() @@ -78,7 +78,7 @@ func (h *TokenRestulApiHandler) Login(r *restful.Request, w *restful.Response) { // } // Logout HandleFunc -func (h *TokenRestulApiHandler) Logout(r *restful.Request, w *restful.Response) { +func (h *TokenRestfulApiHandler) Logout(r *restful.Request, w *restful.Response) { req := token.NewRevolkTokenRequest( token.GetAccessTokenFromHTTP(r.Request), token.GetRefreshTokenFromHTTP(r.Request), @@ -106,7 +106,7 @@ func (h *TokenRestulApiHandler) Logout(r *restful.Request, w *restful.Response) response.Success(w, tk) } -func (h *TokenRestulApiHandler) ValiateToken(r *restful.Request, w *restful.Response) { +func (h *TokenRestfulApiHandler) ValiateToken(r *restful.Request, w *restful.Response) { // 1. 获取用户的请求参数, 参数在Body里面 req := token.NewValiateTokenRequest("") err := r.ReadEntity(req) diff --git a/devcloud/mcenter/apps/token/model.go b/devcloud/mcenter/apps/token/model.go index ccef9f5..b6330a6 100644 --- a/devcloud/mcenter/apps/token/model.go +++ b/devcloud/mcenter/apps/token/model.go @@ -22,6 +22,7 @@ func GetAccessTokenFromHTTP(r *http.Request) string { if err != nil { return "" } + // ?token=xxxx tk, _ = url.QueryUnescape(cookie.Value) } else { // 处理 带格式: Bearer diff --git a/devcloud/mcenter/apps/user/README.md b/devcloud/mcenter/apps/user/README.md index a9ca452..5b0aabe 100644 --- a/devcloud/mcenter/apps/user/README.md +++ b/devcloud/mcenter/apps/user/README.md @@ -65,3 +65,27 @@ func (u *User) CheckPassword(password string) error { return bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password)) } ``` + +### 接口设计 + +```go +ws.Route(ws.GET("").To(h.QueryUser). + Doc("用户列表查询"). + Metadata(restfulspec.KeyOpenAPITags, tags). + Param(restful.QueryParameter("page_size", "分页大小").DataType("integer")). + Param(restful.QueryParameter("page_number", "页码").DataType("integer")). + Writes(Set{}). + Returns(200, "OK", Set{})) +``` + +其中 user字段里面的 +```json +{ +"password": "$2a$10$GoEjC.vFlgJ..BCvaMu6YurdVgyx4p6S4LFRXiqXESiVY4lokL496" +} +// 需要脱敏: "*" +{ +"password": "****" +} +``` + diff --git a/devcloud/mcenter/apps/user/api/api.go b/devcloud/mcenter/apps/user/api/api.go index 778f64e..5b4b35a 100644 --- a/devcloud/mcenter/apps/user/api/api.go +++ b/devcloud/mcenter/apps/user/api/api.go @@ -1 +1,48 @@ package api + +import ( + "122.51.31.227/go-course/go18/devcloud/mcenter/apps/user" + "github.com/infraboard/mcube/v2/ioc" + "github.com/infraboard/mcube/v2/ioc/config/gorestful" + + restfulspec "github.com/emicklei/go-restful-openapi/v2" + "github.com/emicklei/go-restful/v3" +) + +func init() { + ioc.Api().Registry(&UserRestfulApiHandler{}) +} + +type UserRestfulApiHandler struct { + ioc.ObjectImpl + + // 依赖控制器 + svc user.Service +} + +func (h *UserRestfulApiHandler) Name() string { + return "users" +} + +func (h *UserRestfulApiHandler) Init() error { + h.svc = user.GetService() + + tags := []string{"用户登录"} + ws := gorestful.ObjectRouter(h) + ws.Route(ws.GET("").To(h.QueryUser). + Doc("用户列表查询"). + Metadata(restfulspec.KeyOpenAPITags, tags). + Param(restful.QueryParameter("page_size", "分页大小").DataType("integer")). + Param(restful.QueryParameter("page_number", "页码").DataType("integer")). + Writes(Set{}). + Returns(200, "OK", Set{})) + + return nil +} + +// *types.Set[*User] +// 返回的泛型, API Doc这个工具 不支持泛型 +type Set struct { + Total int64 `json:"total"` + Items []user.User `json:"items"` +} diff --git a/devcloud/mcenter/apps/user/api/user.go b/devcloud/mcenter/apps/user/api/user.go new file mode 100644 index 0000000..a8aa811 --- /dev/null +++ b/devcloud/mcenter/apps/user/api/user.go @@ -0,0 +1,40 @@ +package api + +import ( + "122.51.31.227/go-course/go18/devcloud/mcenter/apps/user" + "github.com/emicklei/go-restful/v3" + "github.com/gin-gonic/gin/binding" + "github.com/infraboard/mcube/v2/http/restful/response" +) + +func (h *UserRestfulApiHandler) QueryUser(r *restful.Request, w *restful.Response) { + // 获取用户通过API传入的参数 + req := user.NewQueryUserRequest() + + // r.QueryParameter("page_size") + // r.QueryParameter("page_number") + // url bind, url parameter <---> obj form:"page_size" form:"page_number" + // url? + // gin bind 的具体实现:非简单结构: json user_ids = [] user_id=1&user_id=2 + if err := binding.Query.Bind(r.Request, req); err != nil { + response.Failed(w, err) + return + } + + set, err := h.svc.QueryUser(r.Request.Context(), req) + if err != nil { + response.Failed(w, err) + return + } + + // 专门做脱敏处理 + // for user.password = "" json: omitempty + // 每个接口 都需要定制化的写这些逻辑 + // 为对象实现一个脱名方法: Densence, 断言这个对象实现了这个方法 + // 定义一个接口,断言这个对象 满足这个接口, 这个能解决80%的问题 + // 对象嵌套, 你需要自己 去调用嵌套对象的 Densence + + // 能不能直接通过JSON标签 这样方式来完成脱敏: must:"3,4" (181*****4777) + // 不能每次都调用吧,因此这个脱敏逻辑 放到 Rsep函数内进行处理 + response.Success(w, set) +} diff --git a/devcloud/mcenter/apps/user/design.drawio b/devcloud/mcenter/apps/user/design.drawio new file mode 100644 index 0000000..1cdf92e --- /dev/null +++ b/devcloud/mcenter/apps/user/design.drawio @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/devcloud/mcenter/apps/user/interface.go b/devcloud/mcenter/apps/user/interface.go index 4159aa4..6944a8a 100644 --- a/devcloud/mcenter/apps/user/interface.go +++ b/devcloud/mcenter/apps/user/interface.go @@ -33,13 +33,13 @@ type Service interface { func NewQueryUserRequest() *QueryUserRequest { return &QueryUserRequest{ - PageRequest: request.NewDefaultPageRequest(), + PageRequest: *request.NewDefaultPageRequest(), UserIds: []uint64{}, } } type QueryUserRequest struct { - *request.PageRequest + request.PageRequest UserIds []uint64 `form:"user" json:"user"` } diff --git a/devcloud/mcenter/apps/user/model.go b/devcloud/mcenter/apps/user/model.go index 219f979..7017b5d 100644 --- a/devcloud/mcenter/apps/user/model.go +++ b/devcloud/mcenter/apps/user/model.go @@ -65,7 +65,7 @@ type CreateUserRequest struct { // 用户名 UserName string `json:"user_name" gorm:"column:user_name;type:varchar(100);not null;uniqueIndex" description:"用户名"` // 密码(Hash过后的) - Password string `json:"password" gorm:"column:password;type:varchar(200);not null" description:"用户密码"` + Password string `json:"password,omitempty" gorm:"column:password;type:varchar(200);not null" description:"用户密码" mask:",3,4"` // 用户描述 Description string `json:"description" gorm:"column:description;type:varchar(200);not null" description:"用户描述"` // 用户类型