| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- package permlib
- import (
- "context"
- "encoding/json"
- "fmt"
- "net/http"
- "strings"
- )
- func (e *Engine) authMiddleware(next http.HandlerFunc) http.HandlerFunc {
- return func(w http.ResponseWriter, req *http.Request) {
- authHeader := req.Header.Get("Authorization")
- if authHeader == "" {
- e.cfg.Callbacks.OnError(w, req, 401, 401, "未登录")
- return
- }
- tokenStr := strings.TrimPrefix(authHeader, "Bearer ")
- if tokenStr == authHeader {
- e.cfg.Callbacks.OnError(w, req, 401, 401, "token格式错误")
- return
- }
- info, err := e.verifyAndGetUser(req.Context(), tokenStr)
- if err != nil {
- e.cfg.Callbacks.OnError(w, req, 401, 401, "token无效或已过期")
- return
- }
- apiCode := e.resolvePermCode(req)
- if apiCode != "" && !containsPerm(info.Perms, apiCode) {
- e.cfg.Callbacks.OnError(w, req, 403, 403, fmt.Sprintf("无权访问: %s", apiCode))
- return
- }
- user := &UserInfo{
- UserId: info.UserId,
- Username: info.Username,
- ProductCode: info.ProductCode,
- MemberType: info.MemberType,
- Perms: info.Perms,
- }
- ctx := withUser(req.Context(), user)
- req, rejected := e.filterRequest(req, info.Perms)
- if rejected {
- e.cfg.Callbacks.OnError(w, req, 403, 403, "包含无权写入的字段")
- return
- }
- dataCode := e.resolveDataCode(req, apiCode)
- hasDataPerm := dataCode == "" || containsPerm(info.Perms, dataCode)
- var wrappedNext http.HandlerFunc
- if e.hasRespFilter(req) {
- wrappedNext = func(w http.ResponseWriter, req *http.Request) {
- rw := newFilterResponseWriter(w, req, info.Perms, e)
- next(rw, req)
- rw.flush()
- }
- } else {
- wrappedNext = next
- }
- e.cfg.Callbacks.OnSuccess(w, req.WithContext(ctx), wrappedNext, user, hasDataPerm)
- }
- }
- func (e *Engine) resolvePermCode(req *http.Request) string {
- key := req.Method + " " + req.URL.Path
- if decl, ok := e.routePerms[key]; ok {
- return decl.PermCode
- }
- return ""
- }
- func (e *Engine) resolveDataCode(req *http.Request, apiCode string) string {
- key := req.Method + " " + req.URL.Path
- if decl, ok := e.routePerms[key]; ok {
- return decl.DataCode
- }
- if apiCode != "" {
- return apiToDataCode(apiCode)
- }
- return ""
- }
- func (e *Engine) hasRespFilter(req *http.Request) bool {
- key := req.Method + " " + req.URL.Path
- if fm, ok := e.fieldPerms[key]; ok {
- return len(fm.Response) > 0
- }
- return false
- }
- func (e *Engine) filterRequest(req *http.Request, perms []string) (*http.Request, bool) {
- key := req.Method + " " + req.URL.Path
- if fm, ok := e.fieldPerms[key]; ok && len(fm.Request) > 0 {
- return filterRequestByMap(req, fm.Request, perms, e.cfg.FieldWriteMode)
- }
- return req, false
- }
- func (e *Engine) verifyAndGetUser(ctx context.Context, token string) (*cachedUser, error) {
- if u, ok := e.cache.get(token); ok {
- return u, nil
- }
- v, err, _ := e.cache.sf.Do(token, func() (interface{}, error) {
- resp, err := e.client.verifyToken(ctx, token)
- if err != nil {
- return nil, err
- }
- if !resp.Valid {
- return nil, fmt.Errorf("token验证失败")
- }
- u := &cachedUser{
- UserId: resp.UserId,
- Username: resp.Username,
- ProductCode: resp.ProductCode,
- MemberType: resp.MemberType,
- Perms: resp.Perms,
- }
- e.cache.set(token, u)
- return u, nil
- })
- if err != nil {
- return nil, err
- }
- return v.(*cachedUser), nil
- }
- func containsPerm(perms []string, code string) bool {
- for _, p := range perms {
- if p == code {
- return true
- }
- }
- return false
- }
- func filterRequestByMap(req *http.Request, fieldMap map[string]string, perms []string, mode FieldWriteMode) (*http.Request, bool) {
- if req.Body == nil {
- return req, false
- }
- body, err := readBody(req)
- if err != nil || len(body) == 0 {
- return req, false
- }
- var obj map[string]json.RawMessage
- if err := json.Unmarshal(body, &obj); err != nil {
- restoreBody(req, body)
- return req, false
- }
- permSet := toPermSet(perms)
- for jsonField, permCode := range fieldMap {
- if _, has := obj[jsonField]; has && !permSet[permCode] {
- if mode == FieldWriteReject {
- restoreBody(req, body)
- return req, true
- }
- delete(obj, jsonField)
- }
- }
- filtered, _ := json.Marshal(obj)
- restoreBody(req, filtered)
- req.ContentLength = int64(len(filtered))
- return req, false
- }
|