| |
| |
| |
|
|
| package auth |
|
|
| import ( |
| "net/http" |
| "net/url" |
|
|
| "github.com/GoAdminGroup/go-admin/context" |
| "github.com/GoAdminGroup/go-admin/modules/config" |
| "github.com/GoAdminGroup/go-admin/modules/constant" |
| "github.com/GoAdminGroup/go-admin/modules/db" |
| "github.com/GoAdminGroup/go-admin/modules/errors" |
| "github.com/GoAdminGroup/go-admin/modules/language" |
| "github.com/GoAdminGroup/go-admin/modules/logger" |
| "github.com/GoAdminGroup/go-admin/modules/page" |
| "github.com/GoAdminGroup/go-admin/plugins/admin/models" |
| template2 "github.com/GoAdminGroup/go-admin/template" |
| "github.com/GoAdminGroup/go-admin/template/types" |
| ) |
|
|
| |
| |
| type Invoker struct { |
| prefix string |
| authFailCallback MiddlewareCallback |
| permissionDenyCallback MiddlewareCallback |
| conn db.Connection |
| } |
|
|
| |
| func Middleware(conn db.Connection) context.Handler { |
| return DefaultInvoker(conn).Middleware() |
| } |
|
|
| |
| func DefaultInvoker(conn db.Connection) *Invoker { |
| return &Invoker{ |
| prefix: config.Prefix(), |
| authFailCallback: func(ctx *context.Context) { |
| if ctx.Request.URL.Path == config.Url(config.GetLoginUrl()) { |
| return |
| } |
| if ctx.Request.URL.Path == config.Url("/logout") { |
| ctx.Write(302, map[string]string{ |
| "Location": config.Url(config.GetLoginUrl()), |
| }, ``) |
| return |
| } |
| param := "" |
| if ref := ctx.Referer(); ref != "" { |
| param = "?ref=" + url.QueryEscape(ref) |
| } |
|
|
| u := config.Url(config.GetLoginUrl() + param) |
| _, err := ctx.Request.Cookie(DefaultCookieKey) |
| referer := ctx.Referer() |
|
|
| if (ctx.Headers(constant.PjaxHeader) == "" && ctx.Method() != "GET") || |
| err != nil || |
| referer == "" { |
| ctx.Write(302, map[string]string{ |
| "Location": u, |
| }, ``) |
| } else { |
| msg := language.Get("login overdue, please login again") |
| ctx.HTML(http.StatusOK, `<script> |
| if (typeof(swal) === "function") { |
| swal({ |
| type: "info", |
| title: "`+language.Get("login info")+`", |
| text: "`+msg+`", |
| showCancelButton: false, |
| confirmButtonColor: "#3c8dbc", |
| confirmButtonText: '`+language.Get("got it")+`', |
| }) |
| setTimeout(function(){ location.href = "`+u+`"; }, 3000); |
| } else { |
| alert("`+msg+`") |
| location.href = "`+u+`" |
| } |
| </script>`) |
| } |
| }, |
| permissionDenyCallback: func(rawCtx *context.Context) { |
| if rawCtx.Headers(constant.PjaxHeader) == "" && rawCtx.Method() != "GET" { |
| rawCtx.JSON(http.StatusForbidden, map[string]interface{}{ |
| "code": http.StatusForbidden, |
| "msg": language.Get(errors.PermissionDenied), |
| }) |
| } else { |
| page.SetPageContent(rawCtx, Auth(rawCtx), func(ctx interface{}) (types.Panel, error) { |
| return template2.WarningPanel(rawCtx, errors.PermissionDenied, template2.NoPermission403Page), nil |
| }, conn) |
| } |
| }, |
| conn: conn, |
| } |
| } |
|
|
| |
| func SetPrefix(prefix string, conn db.Connection) *Invoker { |
| i := DefaultInvoker(conn) |
| i.prefix = prefix |
| return i |
| } |
|
|
| |
| func (invoker *Invoker) SetAuthFailCallback(callback MiddlewareCallback) *Invoker { |
| invoker.authFailCallback = callback |
| return invoker |
| } |
|
|
| |
| func (invoker *Invoker) SetPermissionDenyCallback(callback MiddlewareCallback) *Invoker { |
| invoker.permissionDenyCallback = callback |
| return invoker |
| } |
|
|
| |
| type MiddlewareCallback func(ctx *context.Context) |
|
|
| |
| func (invoker *Invoker) Middleware() context.Handler { |
| return func(ctx *context.Context) { |
| user, authOk, permissionOk := Filter(ctx, invoker.conn) |
|
|
| if authOk && permissionOk { |
| ctx.SetUserValue("user", user) |
| ctx.Next() |
| return |
| } |
|
|
| if !authOk { |
| invoker.authFailCallback(ctx) |
| ctx.Abort() |
| return |
| } |
|
|
| if !permissionOk { |
| ctx.SetUserValue("user", user) |
| invoker.permissionDenyCallback(ctx) |
| ctx.Abort() |
| return |
| } |
| } |
| } |
|
|
| |
| |
| func Filter(ctx *context.Context, conn db.Connection) (models.UserModel, bool, bool) { |
| var ( |
| id float64 |
| ok bool |
|
|
| user = models.User() |
| ses, err = InitSession(ctx, conn) |
| ) |
|
|
| if err != nil { |
| logger.ErrorCtx(ctx, "retrieve auth user failed %+v", err) |
| return user, false, false |
| } |
|
|
| if id, ok = ses.Get("user_id").(float64); !ok { |
| return user, false, false |
| } |
|
|
| user, ok = GetCurUserByID(int64(id), conn) |
|
|
| if !ok { |
| return user, false, false |
| } |
|
|
| return user, true, CheckPermissions(user, ctx.Request.URL.String(), ctx.Method(), ctx.PostForm()) |
| } |
|
|
| const defaultUserIDSesKey = "user_id" |
|
|
| |
| func GetUserID(sesKey string, conn db.Connection) int64 { |
| id, err := GetSessionByKey(sesKey, defaultUserIDSesKey, conn) |
| if err != nil { |
| logger.Error("retrieve auth user failed", err) |
| return -1 |
| } |
| if idFloat64, ok := id.(float64); ok { |
| return int64(idFloat64) |
| } |
| return -1 |
| } |
|
|
| |
| func GetCurUser(sesKey string, conn db.Connection) (user models.UserModel, ok bool) { |
|
|
| if sesKey == "" { |
| ok = false |
| return |
| } |
|
|
| id := GetUserID(sesKey, conn) |
| if id == -1 { |
| ok = false |
| return |
| } |
| return GetCurUserByID(id, conn) |
| } |
|
|
| |
| func GetCurUserByID(id int64, conn db.Connection) (user models.UserModel, ok bool) { |
|
|
| user = models.User().SetConn(conn).Find(id) |
|
|
| if user.IsEmpty() { |
| ok = false |
| return |
| } |
|
|
| if user.Avatar == "" || config.GetStore().Prefix == "" { |
| user.Avatar = "" |
| } else { |
| user.Avatar = config.GetStore().URL(user.Avatar) |
| } |
|
|
| user = user.WithRoles().WithPermissions().WithMenus() |
|
|
| ok = user.HasMenu() |
|
|
| return |
| } |
|
|
| |
| func CheckPermissions(user models.UserModel, path, method string, param url.Values) bool { |
| return user.CheckPermissionByUrlMethod(path, method, param) |
| } |
|
|