diff --git a/app/controller/admin/index.go b/app/controller/admin/index.go index 3e48299..432b806 100644 --- a/app/controller/admin/index.go +++ b/app/controller/admin/index.go @@ -1,16 +1,42 @@ package admin import ( - "gfast/boot" + "gfast/app/service/user_service" + "gfast/library/response" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/net/ghttp" - "github.com/gogf/gf/util/gconv" + "strings" ) type Index struct{} +//后台首页接口数据 func (c *Index) Index(r *ghttp.Request) { - resp := boot.AdminGfToken.GetTokenData(r) - g.Log().Debug(r.Router.Uri) - r.Response.Write("hello Index-", gconv.Map(resp.Get("data"))["user_nickname"]) + //获取用户信息 + userId := user_service.GetLoginID(r) + //获取用户角色信息 + userMap := user_service.GetAdminInfoById(userId) + if userMap != nil { + delete(userMap, "user_password") + roles, err := user_service.GetAdminRole(userId) + if err == nil { + name := make([]string, len(roles)) + roleIds := make([]int, len(roles)) + for k, v := range roles { + name[k] = v.Name + roleIds[k] = v.Id + } + userMap["roles"] = strings.Join(name, ",") + //获取菜单信息 + user_service.GetAdminMenusByRoleIds(roleIds) + } else { + g.Log().Error(err) + userMap["roles"] = "" + } + } + + result := g.Map{ + "userInfo": userMap, + } + response.SusJson(true, r, "ok", result) } diff --git a/app/model/role_user/role_user_entity.go b/app/model/role_user/role_user_entity.go deleted file mode 100644 index 46c1121..0000000 --- a/app/model/role_user/role_user_entity.go +++ /dev/null @@ -1,57 +0,0 @@ -// ========================================================================== -// This is auto-generated by gf cli tool. You may not really want to edit it. -// ========================================================================== - -package role_user - -import ( - "database/sql" - "github.com/gogf/gf/database/gdb" -) - -// Entity is the golang structure for table qxkj_role_user. -type Entity struct { - Id int `orm:"id,primary" json:"id"` // - RoleId int `orm:"role_id" json:"role_id"` // 角色 id - UserId int `orm:"user_id" json:"user_id"` // 用户id -} - -// QxkjRoleUser is alias of Entity, which some developers say they just want. -type QxkjRoleUser = Entity - -// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers -// the data and where attributes for empty values. -func (r *Entity) OmitEmpty() *arModel { - return Model.Data(r).OmitEmpty() -} - -// Inserts does "INSERT...INTO..." statement for inserting current object into table. -func (r *Entity) Insert() (result sql.Result, err error) { - return Model.Data(r).Insert() -} - -// Replace does "REPLACE...INTO..." statement for inserting current object into table. -// If there's already another same record in the table (it checks using primary key or unique index), -// it deletes it and insert this one. -func (r *Entity) Replace() (result sql.Result, err error) { - return Model.Data(r).Replace() -} - -// Save does "INSERT...INTO..." statement for inserting/updating current object into table. -// It updates the record if there's already another same record in the table -// (it checks using primary key or unique index). -func (r *Entity) Save() (result sql.Result, err error) { - return Model.Data(r).Save() -} - -// Update does "UPDATE...WHERE..." statement for updating current object from table. -// It updates the record if there's already another same record in the table -// (it checks using primary key or unique index). -func (r *Entity) Update() (result sql.Result, err error) { - return Model.Data(r).Where(gdb.GetWhereConditionOfStruct(r)).Update() -} - -// Delete does "DELETE FROM...WHERE..." statement for deleting current object from table. -func (r *Entity) Delete() (result sql.Result, err error) { - return Model.Where(gdb.GetWhereConditionOfStruct(r)).Delete() -} diff --git a/app/model/role_user/role_user_model.go b/app/model/role_user/role_user_model.go deleted file mode 100644 index 7d08e5c..0000000 --- a/app/model/role_user/role_user_model.go +++ /dev/null @@ -1,248 +0,0 @@ -// ========================================================================== -// This is auto-generated by gf cli tool. You may not really want to edit it. -// ========================================================================== - -package role_user - -import ( - "database/sql" - "github.com/gogf/gf/database/gdb" - "github.com/gogf/gf/frame/g" - "time" -) - -// arModel is a active record design model for table qxkj_role_user operations. -type arModel struct { - Model *gdb.Model -} - -var ( - // Table is the table name of qxkj_role_user. - Table = "qxkj_role_user" - // Model is the model object of qxkj_role_user. - Model = &arModel{g.DB("default").Table(Table).Safe()} -) - -// TX sets the transaction for current operation. -func (m *arModel) TX(tx *gdb.TX) *arModel { - return &arModel{m.Model.TX(tx)} -} - -// Master marks the following operation on master node. -func (m *arModel) Master() *arModel { - return &arModel{m.Model.Master()} -} - -// Slave marks the following operation on slave node. -// Note that it makes sense only if there's any slave node configured. -func (m *arModel) Slave() *arModel { - return &arModel{m.Model.Slave()} -} - -// LeftJoin does "LEFT JOIN ... ON ..." statement on the model. -func (m *arModel) LeftJoin(joinTable string, on string) *arModel { - return &arModel{m.Model.LeftJoin(joinTable, on)} -} - -// RightJoin does "RIGHT JOIN ... ON ..." statement on the model. -func (m *arModel) RightJoin(joinTable string, on string) *arModel { - return &arModel{m.Model.RightJoin(joinTable, on)} -} - -// InnerJoin does "INNER JOIN ... ON ..." statement on the model. -func (m *arModel) InnerJoin(joinTable string, on string) *arModel { - return &arModel{m.Model.InnerJoin(joinTable, on)} -} - -// Fields sets the operation fields of the model, multiple fields joined using char ','. -func (m *arModel) Fields(fields string) *arModel { - return &arModel{m.Model.Fields(fields)} -} - -// FieldsEx sets the excluded operation fields of the model, multiple fields joined using char ','. -func (m *arModel) FieldsEx(fields string) *arModel { - return &arModel{m.Model.FieldsEx(fields)} -} - -// Option sets the extra operation option for the model. -func (m *arModel) Option(option int) *arModel { - return &arModel{m.Model.Option(option)} -} - -// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers -// the data and where attributes for empty values. -func (m *arModel) OmitEmpty() *arModel { - return &arModel{m.Model.OmitEmpty()} -} - -// Filter marks filtering the fields which does not exist in the fields of the operated table. -func (m *arModel) Filter() *arModel { - return &arModel{m.Model.Filter()} -} - -// Where sets the condition statement for the model. The parameter can be type of -// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times, -// multiple conditions will be joined into where statement using "AND". -// Eg: -// Where("uid=10000") -// Where("uid", 10000) -// Where("money>? AND name like ?", 99999, "vip_%") -// Where("uid", 1).Where("name", "john") -// Where("status IN (?)", g.Slice{1,2,3}) -// Where("age IN(?,?)", 18, 50) -// Where(User{ Id : 1, UserName : "john"}) -func (m *arModel) Where(where interface{}, args ...interface{}) *arModel { - return &arModel{m.Model.Where(where, args...)} -} - -// And adds "AND" condition to the where statement. -func (m *arModel) And(where interface{}, args ...interface{}) *arModel { - return &arModel{m.Model.And(where, args...)} -} - -// Or adds "OR" condition to the where statement. -func (m *arModel) Or(where interface{}, args ...interface{}) *arModel { - return &arModel{m.Model.Or(where, args...)} -} - -// GroupBy sets the "GROUP BY" statement for the model. -func (m *arModel) GroupBy(groupBy string) *arModel { - return &arModel{m.Model.GroupBy(groupBy)} -} - -// OrderBy sets the "ORDER BY" statement for the model. -func (m *arModel) OrderBy(orderBy string) *arModel { - return &arModel{m.Model.OrderBy(orderBy)} -} - -// Limit sets the "LIMIT" statement for the model. -// The parameter can be either one or two number, if passed two number is passed, -// it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]" -// statement. -func (m *arModel) Limit(limit ...int) *arModel { - return &arModel{m.Model.Limit(limit...)} -} - -// Offset sets the "OFFSET" statement for the model. -// It only makes sense for some databases like SQLServer, PostgreSQL, etc. -func (m *arModel) Offset(offset int) *arModel { - return &arModel{m.Model.Offset(offset)} -} - -// ForPage sets the paging number for the model. -// The parameter is started from 1 for paging. -// Note that, it differs that the Limit function start from 0 for "LIMIT" statement. -func (m *arModel) ForPage(page, limit int) *arModel { - return &arModel{m.Model.ForPage(page, limit)} -} - -// Batch sets the batch operation number for the model. -func (m *arModel) Batch(batch int) *arModel { - return &arModel{m.Model.Batch(batch)} -} - -// Cache sets the cache feature for the model. It caches the result of the sql, which means -// if there's another same sql request, it just reads and returns the result from cache, it -// but not committed and executed into the database. -// -// If the parameter < 0, which means it clear the cache with given . -// If the parameter = 0, which means it never expires. -// If the parameter > 0, which means it expires after . -// -// The optional parameter is used to bind a name to the cache, which means you can later -// control the cache like changing the or clearing the cache with specified . -// -// Note that, the cache feature is disabled if the model is operating on a transaction. -func (m *arModel) Cache(expire time.Duration, name ...string) *arModel { - return &arModel{m.Model.Cache(expire, name...)} -} - -// Data sets the operation data for the model. -// The parameter can be type of string/map/gmap/slice/struct/*struct, etc. -// Eg: -// Data("uid=10000") -// Data("uid", 10000) -// Data(g.Map{"uid": 10000, "name":"john"}) -// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"}) -func (m *arModel) Data(data ...interface{}) *arModel { - return &arModel{m.Model.Data(data...)} -} - -// Insert does "INSERT INTO ..." statement for the model. -func (m *arModel) Insert() (result sql.Result, err error) { - return m.Model.Insert() -} - -// Replace does "REPLACE INTO ..." statement for the model. -func (m *arModel) Replace() (result sql.Result, err error) { - return m.Model.Replace() -} - -// Save does "INSERT INTO ... ON DUPLICATE KEY UPDATE..." statement for the model. -// It updates the record if there's primary or unique index in the saving data, -// or else it inserts a new record into the table. -func (m *arModel) Save() (result sql.Result, err error) { - return m.Model.Save() -} - -// Update does "UPDATE ... " statement for the model. -func (m *arModel) Update() (result sql.Result, err error) { - return m.Model.Update() -} - -// Delete does "DELETE FROM ... " statement for the model. -func (m *arModel) Delete() (result sql.Result, err error) { - return m.Model.Delete() -} - -// Count does "SELECT COUNT(x) FROM ..." statement for the model. -func (m *arModel) Count() (int, error) { - return m.Model.Count() -} - -// All does "SELECT FROM ..." statement for the model. -// It retrieves the records from table and returns the result as []*Entity. -// It returns nil if there's no record retrieved with the given conditions from table. -func (m *arModel) All() ([]*Entity, error) { - all, err := m.Model.All() - if err != nil { - return nil, err - } - var entities []*Entity - if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows { - return nil, err - } - return entities, nil -} - -// One retrieves one record from table and returns the result as *Entity. -// It returns nil if there's no record retrieved with the given conditions from table. -func (m *arModel) One() (*Entity, error) { - one, err := m.Model.One() - if err != nil { - return nil, err - } - var entity *Entity - if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows { - return nil, err - } - return entity, nil -} - -// Value retrieves a specified record value from table and returns the result as interface type. -// It returns nil if there's no record found with the given conditions from table. -func (m *arModel) Value() (gdb.Value, error) { - return m.Model.Value() -} - -// Chunk iterates the table with given size and callback function. -func (m *arModel) Chunk(limit int, callback func(entities []*Entity, err error) bool) { - m.Model.Chunk(limit, func(result gdb.Result, err error) bool { - var entities []*Entity - err = result.Structs(&entities) - if err == sql.ErrNoRows { - return false - } - return callback(entities, err) - }) -} diff --git a/app/service/auth_service/auth_rule.go b/app/service/auth_service/auth_rule.go index 7f16efc..d963f45 100644 --- a/app/service/auth_service/auth_rule.go +++ b/app/service/auth_service/auth_rule.go @@ -173,7 +173,7 @@ func EditRoleRule(iRule interface{}, roleId int64) (err error) { return } //查询当前权限 - gp := enforcer.GetFilteredNamedPolicy("p", 0, fmt.Sprintf("g_%d", roleId)) + gp := enforcer.GetFilteredPolicy(0, fmt.Sprintf("g_%d", roleId)) //删除旧权限 for _, v := range gp { _, e = enforcer.RemovePolicy(v) diff --git a/app/service/user_service/user.go b/app/service/user_service/user.go index 72734ff..303880c 100644 --- a/app/service/user_service/user.go +++ b/app/service/user_service/user.go @@ -1,20 +1,72 @@ package user_service import ( - "database/sql" - "errors" + "fmt" + "gfast/app/model/role" "gfast/app/model/user" + "gfast/app/service/casbin_adapter_service" + "gfast/boot" + "github.com/gogf/gf/frame/g" "github.com/gogf/gf/net/ghttp" + "github.com/gogf/gf/text/gstr" + "github.com/gogf/gf/util/gconv" ) -// 用户登录,成功返回用户信息,否则返回nil -func SignIn(username, password string, session *ghttp.Session) (error, *user.QxkjUser) { - qxkjUser, err := user.Model.Where("user_name=? and user_password=?", username, password).One() - if err != nil && err != sql.ErrNoRows { - return err, nil +//获取登陆用户ID +func GetLoginID(r *ghttp.Request) int64 { + resp := boot.AdminGfToken.GetTokenData(r) + userId := resp.GetInt("data") + return gconv.Int64(userId) +} + +//获取管理员的角色信息 +func GetAdminRole(userId int64) (roles []*role.Entity, err error) { + enforcer, e := casbin_adapter_service.GetEnforcer() + if e != nil { + err = e + return } - if qxkjUser == nil { - return errors.New("账号或密码错误"), nil + //查询关联角色规则 + groupPolicy := enforcer.GetFilteredGroupingPolicy(0, fmt.Sprintf("u_%d", userId)) + if len(groupPolicy) > 0 { + roleIds := make([]int64, len(groupPolicy)) + //得到角色id的切片 + for k, v := range groupPolicy { + roleIds[k] = gconv.Int64(gstr.SubStr(v[1], 2)) + } + //获取角色信息 + roles, err = role.Model.Where("id in(?)", roleIds).All() } - return nil, qxkjUser + return +} + +//根据用户id获取用户信息 +func GetAdminInfoById(id int64) (userMap g.Map) { + //获取用户角色信息 + if id != 0 { + userInfo, err := user.Model.Where("id=?", id).One() + if err != nil { + g.Log().Error(err) + return + } + userMap = gconv.Map(userInfo) + } + return +} + +//获取管理员所属角色菜单 +func GetAdminMenusByRoleIds(roleIds []int) (menus g.Map, err error) { + //获取角色对应的菜单id + enforcer, e := casbin_adapter_service.GetEnforcer() + if e != nil { + err = e + return + } + for _, roleId := range roleIds { + //查询当前权限 + gp := enforcer.GetFilteredPolicy(0, fmt.Sprintf("g_%d", roleId)) + g.Log().Debug(gp) + } + + return } diff --git a/boot/boot.go b/boot/boot.go index 39c28a1..3b03f80 100644 --- a/boot/boot.go +++ b/boot/boot.go @@ -29,6 +29,7 @@ func initAdminGfToken() { LoginBeforeFunc: utils.AdminLogin, LogoutPath: "/sysLogin/logout", AuthPaths: g.SliceStr{"/system/*"}, + AuthAfterFunc: utils.AuthAfterFunc, LogoutBeforeFunc: utils.AdminLoginOut, } AdminGfToken.Start() diff --git a/library/utils/function.go b/library/utils/function.go index 4bea54e..f5748b8 100644 --- a/library/utils/function.go +++ b/library/utils/function.go @@ -1,12 +1,18 @@ package utils import ( - "gfast/app/service/user_service" + "database/sql" + "errors" + "fmt" + "gfast/app/model/user" "gfast/library/response" + "github.com/goflyfox/gtoken/gtoken" "github.com/gogf/gf/crypto/gaes" "github.com/gogf/gf/encoding/gbase64" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/net/ghttp" + "github.com/gogf/gf/os/gtime" + "github.com/gogf/gf/util/gconv" "github.com/gogf/gf/util/grand" "github.com/gogf/gf/util/gvalid" "github.com/mojocn/base64Captcha" @@ -57,18 +63,36 @@ func AdminLogin(r *ghttp.Request) (string, interface{}) { response.JsonExit(r, response.ErrorCode, e.String()) } //判断验证码是否正确 - if !base64Captcha.VerifyCaptchaAndIsClear(data["idKeyC"], data["idValueC"], true) { + /*if !base64Captcha.VerifyCaptchaAndIsClear(data["idKeyC"], data["idValueC"], true) { response.JsonExit(r, response.ErrorCode, "验证码输入错误") - } + }*/ password := EncryptCBC(data["password"], AdminCbcPublicKey) - if err, user := user_service.SignIn(data["username"], password, r.Session); err != nil { + if err, user := signIn(data["username"], password, r); err != nil { response.JsonExit(r, response.ErrorCode, err.Error()) } else { - return data["username"] + password, user + return data["username"] + password, user.Id } return data["username"] + password, nil } +//gtoken验证后返回 +func AuthAfterFunc(r *ghttp.Request, respData gtoken.Resp) { + if r.Method == "OPTIONS" || respData.Success() { + r.Middleware.Next() + } else { + params := r.GetRequestMap() + no := gtime.TimestampMilliStr() + g.Log().Info(fmt.Sprintf("[AUTH_%s][url:%s][params:%s][data:%s]", + no, r.URL.Path, params, respData.Json())) + respData.Msg = "用户信息验证失败" + response := r.Response + options := response.DefaultCORSOptions() + response.CORS(options) + response.WriteJson(respData) + r.ExitAll() + } +} + //后台退出登陆 func AdminLoginOut(r *ghttp.Request) bool { return true @@ -100,3 +124,19 @@ func DecryptCBC(plainText, publicKey string) string { } return gbase64.EncodeToString(b) } + +// 用户登录,成功返回用户信息,否则返回nil +func signIn(username, password string, r *ghttp.Request) (error, *user.QxkjUser) { + qxkjUser, err := user.Model.Where("user_name=? and user_password=?", username, password).One() + if err != nil && err != sql.ErrNoRows { + return err, nil + } + if qxkjUser == nil { + return errors.New("账号或密码错误"), nil + } + //更新登陆时间及ip + qxkjUser.LastLoginTime = gconv.Int(gtime.Timestamp()) + qxkjUser.LastLoginIp = r.GetClientIp() + qxkjUser.Update() + return nil, qxkjUser +}