github.com/infraboard/keyauth@v0.8.1/client/interceptor/http.go (about) 1 package interceptor 2 3 import ( 4 "context" 5 "fmt" 6 "net/http" 7 "sync" 8 9 "github.com/gin-gonic/gin" 10 "github.com/infraboard/mcube/exception" 11 "github.com/infraboard/mcube/http/response" 12 "github.com/infraboard/mcube/logger" 13 "github.com/infraboard/mcube/logger/zap" 14 httpb "github.com/infraboard/mcube/pb/http" 15 "github.com/rs/xid" 16 17 "github.com/infraboard/keyauth/apps/micro" 18 "github.com/infraboard/keyauth/apps/permission" 19 "github.com/infraboard/keyauth/apps/token" 20 "github.com/infraboard/keyauth/apps/user/types" 21 "github.com/infraboard/keyauth/client" 22 "github.com/infraboard/keyauth/common/header" 23 ) 24 25 type PermissionCheckMode int 26 27 const ( 28 // PRBAC_MODE 基于策略的权限校验 29 PRBAC_MODE PermissionCheckMode = 1 30 // ACL_MODE 基于用户类型的权限校验 31 ACL_MODE = 2 32 ) 33 34 // NewInternalAuther 内部使用的auther 35 func NewHTTPAuther(c *client.Client) *HTTPAuther { 36 return &HTTPAuther{ 37 keyauth: c, 38 l: zap.L().Named("Http Interceptor"), 39 mode: PRBAC_MODE, 40 allows: []string{}, 41 } 42 } 43 44 // internal todo 45 type HTTPAuther struct { 46 l logger.Logger 47 keyauth *client.Client 48 mode PermissionCheckMode 49 svr *micro.Micro 50 lock sync.Mutex 51 allows []string 52 } 53 54 func (a *HTTPAuther) SetPermissionCheckMode(m PermissionCheckMode) { 55 a.mode = m 56 } 57 58 func (a *HTTPAuther) SetAllows(allows ...fmt.Stringer) { 59 for _, v := range allows { 60 a.allows = append(a.allows, v.String()) 61 } 62 } 63 64 func (a *HTTPAuther) Auth(r *http.Request, entry httpb.Entry) ( 65 authInfo interface{}, err error) { 66 var tk *token.Token 67 68 // 从请求中获取access token 69 acessToken := r.Header.Get(header.OAuthTokenHeader) 70 71 if entry.AuthEnable { 72 // 校验身份 73 tk, err = a.ValidateIdentity(r.Context(), acessToken) 74 if err != nil { 75 return nil, err 76 } 77 78 // namesapce检查 79 if entry.RequiredNamespace && tk.NamespaceId == "" { 80 return nil, exception.NewBadRequest("namespace required!") 81 } 82 83 // 权限检查 84 if entry.PermissionEnable { 85 err = a.CheckPermission(r.Context(), tk, entry) 86 if err != nil { 87 return nil, err 88 } 89 } 90 } 91 92 // 设置RequestID 93 if r.Header.Get(header.RequestIdHeader) == "" { 94 r.Header.Set(header.RequestIdHeader, xid.New().String()) 95 } 96 97 return tk, nil 98 } 99 100 // Gin Auth Middleware 101 func (a *HTTPAuther) GinAuthHandlerFunc() gin.HandlerFunc { 102 return func(c *gin.Context) { 103 // 从请求中获取access token 104 acessToken := c.GetHeader(header.OAuthTokenHeader) 105 106 // 校验身份 107 tk, err := a.ValidateIdentity(c.Request.Context(), acessToken) 108 if err != nil { 109 response.Failed(c.Writer, err) 110 return 111 } 112 c.Set("token", tk) 113 c.Next() 114 } 115 } 116 117 // Gin Perm Middleware 118 func (a *HTTPAuther) PermHandlerFunc() gin.HandlerFunc { 119 return func(c *gin.Context) { 120 obj := c.MustGet("token") 121 122 tk, ok := obj.(*token.Token) 123 if !ok { 124 response.Failed(c.Writer, fmt.Errorf("auth middleware first")) 125 return 126 } 127 128 e := httpb.Entry{ 129 Method: c.Request.Method, 130 Path: c.FullPath(), 131 Allow: a.allows, 132 } 133 134 // 权限检查 135 err := a.CheckPermission(c.Request.Context(), tk, e) 136 if err != nil { 137 response.Failed(c.Writer, err) 138 return 139 } 140 c.Next() 141 } 142 } 143 144 func (a *HTTPAuther) ValidateIdentity(ctx context.Context, accessToken string) (*token.Token, error) { 145 a.l.Debug("start token identity check ...") 146 147 if accessToken == "" { 148 return nil, exception.NewBadRequest("token required") 149 } 150 151 req := token.NewValidateTokenRequest() 152 req.AccessToken = accessToken 153 tk, err := a.keyauth.Token().ValidateToken(ctx, req) 154 if err != nil { 155 return nil, err 156 } 157 158 a.l.Debugf("token check ok, username: %s", tk.Account) 159 return tk, nil 160 } 161 162 func (a *HTTPAuther) CheckPermission(ctx context.Context, tk *token.Token, e httpb.Entry) error { 163 if tk == nil { 164 return exception.NewUnauthorized("validate permission need token") 165 } 166 167 // 如果是超级管理员不做权限校验, 直接放行 168 if tk.UserType.IsIn(types.UserType_SUPPER) { 169 a.l.Debugf("[%s] supper admin skip permission check!", tk.Account) 170 return nil 171 } 172 173 switch a.mode { 174 case ACL_MODE: 175 return a.ValidatePermissionByACL(ctx, tk, e) 176 case PRBAC_MODE: 177 return a.ValidatePermissionByPRBAC(ctx, tk, e) 178 default: 179 return fmt.Errorf("only support acl and prbac") 180 } 181 } 182 183 func (a *HTTPAuther) ValidatePermissionByACL(ctx context.Context, tk *token.Token, e httpb.Entry) error { 184 // 检查是否是允许的类型 185 if len(e.Allow) > 0 { 186 a.l.Debugf("[%s] start check permission to keyauth ...", tk.Account) 187 if !e.IsAllow(tk.UserType) { 188 return exception.NewPermissionDeny("no permission, allow: %s, but current: %s", e.Allow, tk.UserType) 189 } 190 a.l.Debugf("[%s] permission check passed", tk.Account) 191 } 192 193 return nil 194 } 195 196 func (a *HTTPAuther) ValidatePermissionByPRBAC(ctx context.Context, tk *token.Token, e httpb.Entry) error { 197 svr, err := a.GetClientService(ctx) 198 if err != nil { 199 return err 200 } 201 202 req := permission.NewCheckPermissionRequest() 203 req.Account = tk.Account 204 req.NamespaceId = tk.NamespaceId 205 req.ServiceId = svr.Id 206 req.Path = e.UniquePath() 207 _, err = a.keyauth.Permission().CheckPermission(ctx, req) 208 if err != nil { 209 return exception.NewPermissionDeny(err.Error()) 210 } 211 a.l.Debugf("[%s] permission check passed", tk.Account) 212 return nil 213 } 214 215 func (a *HTTPAuther) GetClientService(ctx context.Context) (*micro.Micro, error) { 216 if a.svr != nil { 217 return a.svr, nil 218 } 219 a.lock.Lock() 220 defer a.lock.Unlock() 221 222 req := micro.NewDescribeServiceRequestWithClientID(a.keyauth.GetClientID()) 223 ins, err := a.keyauth.Micro().DescribeService(ctx, req) 224 if err != nil { 225 return nil, err 226 } 227 a.svr = ins 228 return ins, nil 229 } 230 231 // SetLogger todo 232 func (a *HTTPAuther) SetLogger(l logger.Logger) { 233 a.l = l 234 }