github.com/kotovmak/go-admin@v1.1.1/modules/auth/middleware.go (about) 1 // Copyright 2019 GoAdmin Core Team. All rights reserved. 2 // Use of this source code is governed by a Apache-2.0 style 3 // license that can be found in the LICENSE file. 4 5 package auth 6 7 import ( 8 "net/http" 9 "net/url" 10 11 "github.com/kotovmak/go-admin/context" 12 "github.com/kotovmak/go-admin/modules/config" 13 "github.com/kotovmak/go-admin/modules/constant" 14 "github.com/kotovmak/go-admin/modules/db" 15 "github.com/kotovmak/go-admin/modules/errors" 16 "github.com/kotovmak/go-admin/modules/language" 17 "github.com/kotovmak/go-admin/modules/logger" 18 "github.com/kotovmak/go-admin/modules/page" 19 "github.com/kotovmak/go-admin/plugins/admin/models" 20 template2 "github.com/kotovmak/go-admin/template" 21 "github.com/kotovmak/go-admin/template/types" 22 ) 23 24 // Invoker contains the callback functions which are used 25 // in the route middleware. 26 type Invoker struct { 27 prefix string 28 authFailCallback MiddlewareCallback 29 permissionDenyCallback MiddlewareCallback 30 conn db.Connection 31 } 32 33 // Middleware is the default auth middleware of plugins. 34 func Middleware(conn db.Connection) context.Handler { 35 return DefaultInvoker(conn).Middleware() 36 } 37 38 // DefaultInvoker return a default Invoker. 39 func DefaultInvoker(conn db.Connection) *Invoker { 40 return &Invoker{ 41 prefix: config.Prefix(), 42 authFailCallback: func(ctx *context.Context) { 43 if ctx.Request.URL.Path == config.GetLoginUrl() { 44 return 45 } 46 if ctx.Request.URL.Path == "/logout" { 47 ctx.Write(302, map[string]string{ 48 "Location": config.GetLoginUrl(), 49 }, ``) 50 return 51 } 52 param := "" 53 if ref := ctx.Referer(); ref != "" { 54 param = "?ref=" + url.QueryEscape(ref) 55 } 56 57 u := config.GetLoginUrl() + param 58 _, err := ctx.Request.Cookie(DefaultCookieKey) 59 referer := ctx.Referer() 60 61 if (ctx.Headers(constant.PjaxHeader) == "" && ctx.Method() != "GET") || 62 err != nil || 63 referer == "" { 64 ctx.Write(302, map[string]string{ 65 "Location": u, 66 }, ``) 67 } else { 68 msg := language.Get("login overdue, please login again") 69 ctx.HTML(http.StatusOK, `<script> 70 if (typeof(swal) === "function") { 71 swal({ 72 type: "info", 73 title: "`+language.Get("login info")+`", 74 text: "`+msg+`", 75 showCancelButton: false, 76 confirmButtonColor: "#3c8dbc", 77 confirmButtonText: '`+language.Get("got it")+`', 78 }) 79 setTimeout(function(){ location.href = "`+u+`"; }, 3000); 80 } else { 81 alert("`+msg+`") 82 location.href = "`+u+`" 83 } 84 </script>`) 85 } 86 }, 87 permissionDenyCallback: func(ctx *context.Context) { 88 if ctx.Headers(constant.PjaxHeader) == "" && ctx.Method() != "GET" { 89 ctx.JSON(http.StatusForbidden, map[string]interface{}{ 90 "code": http.StatusForbidden, 91 "msg": language.Get(errors.PermissionDenied), 92 }) 93 } else { 94 page.SetPageContent(ctx, Auth(ctx), func(ctx interface{}) (types.Panel, error) { 95 return template2.WarningPanel(errors.PermissionDenied, template2.NoPermission403Page), nil 96 }, conn) 97 } 98 }, 99 conn: conn, 100 } 101 } 102 103 // SetPrefix return the default Invoker with the given prefix. 104 func SetPrefix(prefix string, conn db.Connection) *Invoker { 105 i := DefaultInvoker(conn) 106 i.prefix = prefix 107 return i 108 } 109 110 // SetAuthFailCallback set the authFailCallback of Invoker. 111 func (invoker *Invoker) SetAuthFailCallback(callback MiddlewareCallback) *Invoker { 112 invoker.authFailCallback = callback 113 return invoker 114 } 115 116 // SetPermissionDenyCallback set the permissionDenyCallback of Invoker. 117 func (invoker *Invoker) SetPermissionDenyCallback(callback MiddlewareCallback) *Invoker { 118 invoker.permissionDenyCallback = callback 119 return invoker 120 } 121 122 // MiddlewareCallback is type of callback function. 123 type MiddlewareCallback func(ctx *context.Context) 124 125 // Middleware get the auth middleware from Invoker. 126 func (invoker *Invoker) Middleware() context.Handler { 127 return func(ctx *context.Context) { 128 user, authOk, permissionOk := Filter(ctx, invoker.conn) 129 130 if authOk && permissionOk { 131 ctx.SetUserValue("user", user) 132 ctx.Next() 133 return 134 } 135 136 if !authOk { 137 invoker.authFailCallback(ctx) 138 ctx.Abort() 139 return 140 } 141 142 if !permissionOk { 143 ctx.SetUserValue("user", user) 144 invoker.permissionDenyCallback(ctx) 145 ctx.Abort() 146 return 147 } 148 } 149 } 150 151 // Filter retrieve the user model from Context and check the permission 152 // at the same time. 153 func Filter(ctx *context.Context, conn db.Connection) (models.UserModel, bool, bool) { 154 var ( 155 id float64 156 ok bool 157 158 user = models.User() 159 ses, err = InitSession(ctx, conn) 160 ) 161 162 if err != nil { 163 logger.Error("retrieve auth user failed", err) 164 return user, false, false 165 } 166 167 if id, ok = ses.Get("user_id").(float64); !ok { 168 return user, false, false 169 } 170 171 user, ok = GetCurUserByID(int64(id), conn) 172 173 if !ok { 174 return user, false, false 175 } 176 177 return user, true, CheckPermissions(user, ctx.Request.URL.String(), ctx.Method(), ctx.PostForm()) 178 } 179 180 const defaultUserIDSesKey = "user_id" 181 182 // GetUserID return the user id from the session. 183 func GetUserID(sesKey string, conn db.Connection) int64 { 184 id, err := GetSessionByKey(sesKey, defaultUserIDSesKey, conn) 185 if err != nil { 186 logger.Error("retrieve auth user failed", err) 187 return -1 188 } 189 if idFloat64, ok := id.(float64); ok { 190 return int64(idFloat64) 191 } 192 return -1 193 } 194 195 // GetCurUser return the user model. 196 func GetCurUser(sesKey string, conn db.Connection) (user models.UserModel, ok bool) { 197 198 if sesKey == "" { 199 ok = false 200 return 201 } 202 203 id := GetUserID(sesKey, conn) 204 if id == -1 { 205 ok = false 206 return 207 } 208 return GetCurUserByID(id, conn) 209 } 210 211 // GetCurUserByID return the user model of given user id. 212 func GetCurUserByID(id int64, conn db.Connection) (user models.UserModel, ok bool) { 213 214 user = models.User().SetConn(conn).Find(id) 215 216 if user.IsEmpty() { 217 ok = false 218 return 219 } 220 221 if user.Avatar == "" || config.GetStore().Prefix == "" { 222 user.Avatar = "" 223 } else { 224 user.Avatar = config.GetStore().URL(user.Avatar) 225 } 226 227 user = user.WithRoles().WithPermissions().WithMenus() 228 229 ok = user.HasMenu() 230 231 return 232 } 233 234 // CheckPermissions check the permission of the user. 235 func CheckPermissions(user models.UserModel, path, method string, param url.Values) bool { 236 return user.CheckPermissionByUrlMethod(path, method, param) 237 }