167 lines
4.2 KiB
Go
167 lines
4.2 KiB
Go
package permission
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/emicklei/go-restful/v3"
|
|
"github.com/infraboard/mcube/v2/exception"
|
|
"github.com/infraboard/mcube/v2/http/restful/response"
|
|
"github.com/infraboard/mcube/v2/ioc"
|
|
"github.com/infraboard/mcube/v2/ioc/config/application"
|
|
"github.com/infraboard/mcube/v2/ioc/config/gorestful"
|
|
"github.com/infraboard/mcube/v2/ioc/config/log"
|
|
"github.com/infraboard/modules/iam/apps/endpoint"
|
|
"github.com/infraboard/modules/iam/apps/policy"
|
|
"github.com/infraboard/modules/iam/apps/token"
|
|
"github.com/rs/zerolog"
|
|
"resty.dev/v3"
|
|
)
|
|
|
|
func Auth(v bool) (string, bool) {
|
|
return endpoint.META_REQUIRED_AUTH_KEY, v
|
|
}
|
|
|
|
func Permission(v bool) (string, bool) {
|
|
return endpoint.META_REQUIRED_PERM_KEY, v
|
|
}
|
|
|
|
func Required(roles ...string) (string, []string) {
|
|
return endpoint.META_REQUIRED_ROLE_KEY, roles
|
|
}
|
|
|
|
func init() {
|
|
ioc.Config().Registry(&Checker{})
|
|
}
|
|
|
|
func GetPermissionChecker() *Checker {
|
|
return ioc.Config().Get("permission_checker").(*Checker)
|
|
}
|
|
|
|
type Checker struct {
|
|
ioc.ObjectImpl
|
|
log *zerolog.Logger
|
|
}
|
|
|
|
func (c *Checker) Name() string {
|
|
return "permission_checker"
|
|
}
|
|
|
|
func (c *Checker) Priority() int {
|
|
return gorestful.Priority() - 1
|
|
}
|
|
|
|
func (c *Checker) Init() error {
|
|
c.log = log.Sub(c.Name())
|
|
|
|
// 注册认证中间件
|
|
gorestful.RootRouter().Filter(c.Check)
|
|
return nil
|
|
}
|
|
|
|
func (c *Checker) Check(r *restful.Request, w *restful.Response, next *restful.FilterChain) {
|
|
route := endpoint.NewEntryFromRestRouteReader(r.SelectedRoute())
|
|
if route.RequiredAuth {
|
|
// 校验身份
|
|
tk, err := c.CheckToken(r)
|
|
if err != nil {
|
|
response.Failed(w, err)
|
|
return
|
|
}
|
|
|
|
// 校验权限
|
|
if err := c.CheckPolicy(r, tk, route); err != nil {
|
|
response.Failed(w, err)
|
|
return
|
|
}
|
|
}
|
|
|
|
next.ProcessFilter(r, w)
|
|
}
|
|
|
|
func (c *Checker) CheckToken(r *restful.Request) (*token.Token, error) {
|
|
v := token.GetAccessTokenFromHTTP(r.Request)
|
|
if v == "" {
|
|
return nil, exception.NewUnauthorized("请先登录")
|
|
}
|
|
|
|
tk, err := c.ValiateToken(r.Request.Context(), token.NewValiateTokenRequest(v))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ctx := context.WithValue(r.Request.Context(), token.CTX_TOKEN_KEY, tk)
|
|
r.Request = r.Request.WithContext(ctx)
|
|
return tk, nil
|
|
}
|
|
|
|
// http://127.0.0.1:8020/api/mcenter/v1/token/validate
|
|
func (c *Checker) ValiateToken(ctx context.Context, in *token.ValiateTokenRequest) (*token.Token, error) {
|
|
tk := token.NewToken()
|
|
resp, err := resty.New().
|
|
SetBaseURL(application.Get().InternalAddress).
|
|
SetAuthToken(application.Get().InternalToken).
|
|
R().
|
|
WithContext(ctx).
|
|
SetContentType("application/json").
|
|
SetBody(in).
|
|
SetResult(tk).
|
|
Post("/api/mcenter/v1/token/validate")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if resp.StatusCode()/100 != 2 {
|
|
return nil, exception.NewUnauthorized("[%d] token校验异常: %s", resp.StatusCode(), resp.String())
|
|
}
|
|
if tk.NamespaceId == 0 {
|
|
tk.NamespaceId = 1
|
|
}
|
|
return tk, nil
|
|
}
|
|
|
|
func (c *Checker) CheckPolicy(r *restful.Request, tk *token.Token, route *endpoint.RouteEntry) error {
|
|
if tk.IsAdmin {
|
|
return nil
|
|
}
|
|
|
|
// API权限校验
|
|
if route.RequiredPerm {
|
|
permReq := policy.NewValidateEndpointPermissionRequest()
|
|
permReq.UserId = tk.UserId
|
|
permReq.NamespaceId = tk.NamespaceId
|
|
permReq.Service = application.Get().AppName
|
|
permReq.Method = route.Method
|
|
permReq.Path = route.Path
|
|
resp, err := c.ValidateEndpointPermission(r.Request.Context(), permReq)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !resp.HasPermission {
|
|
return exception.NewPermissionDeny("无权限")
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// 查询策略列表
|
|
// /api/mcenter/v1/permission/check
|
|
func (c *Checker) ValidateEndpointPermission(ctx context.Context, in *policy.ValidateEndpointPermissionRequest) (*policy.ValidateEndpointPermissionResponse, error) {
|
|
ins := policy.NewValidateEndpointPermissionResponse(*in)
|
|
resp, err := resty.New().
|
|
SetBaseURL(application.Get().InternalAddress).
|
|
SetAuthToken(application.Get().InternalToken).
|
|
SetDebug(true).
|
|
R().
|
|
WithContext(ctx).
|
|
SetBody(in).
|
|
SetResult(ins).
|
|
Post("/api/mcenter/v1/permission/check")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if resp.StatusCode()/100 != 2 {
|
|
return nil, exception.NewPermissionDeny("[%d] token鉴权异常: %s", resp.StatusCode(), resp.String())
|
|
}
|
|
return ins, nil
|
|
}
|