package bo import ( "crypto/md5" "errors" "fmt" "log" "regexp" "scd_check_tools/global" "scd_check_tools/logger" "scd_check_tools/models/enum" "scd_check_tools/tools" "strconv" "strings" "sync" "time" "github.com/astaxie/beego/orm" _ "github.com/astaxie/beego/orm" ) type T_data_usersession struct { Sessionid string `orm:"pk"` Userid int Lastdt int64 } type T_data_role_func struct { Id int `orm:"pk"` Roleid int Funccodeid int } func init() { orm.RegisterModel(new(T_data_usersession)) orm.RegisterModel(new(T_data_role_func)) } var tokenSync sync.RWMutex //缓存token对应的用户信息 var CacheUserByToken = sync.Map{} //登录信息记录 var LoginInfo = sync.Map{} //保存角色-功能 func SaveRoleFunc(roleid int, funclist []string, userinfo map[string]interface{}) error { o := orm.NewOrm() sql := "delete from t_data_role_func where roleid=?" _, err := o.Raw(sql, roleid).Exec() if err != nil { log.Println(err) return err } for _, item := range funclist { intitem, _ := strconv.Atoi(item) obj := T_data_role_func{Roleid: roleid, Funccodeid: intitem} _, err = o.Insert(&obj) if err != nil { log.Println(err) } } dblog := new(SystemLog) dblog.SetUserInfo(userinfo) dblog.Audittype = enum.AuditType_admin_system_userrole dblog.Logtype = enum.LogType_bind dblog.Eventtype = enum.OptEventType_Bus dblog.Eventlevel = enum.OptEventLevel_Hight if err != nil { dblog.Description = fmt.Sprintf("角色%d权限分配失败:%s", roleid, err.Error()) dblog.Fail2() return err } dblog.Description = fmt.Sprintf("角色%d权限分配成功", roleid) dblog.Success2() return nil } func GetRoleFunc(roleid int) (data []orm.Params, err error) { o := orm.NewOrm() lst := []orm.Params{} sql := "select a.*,b.code,b.name,b.parentcode from t_data_role_func a,global_const_code b where a.funccodeid=b.id and a.roleid=?" _, err = o.Raw(sql, roleid).Values(&lst) return lst, err } func GetUserFunc(userid int) (data interface{}, err error) { o := orm.NewOrm() lst := []orm.Params{} checkSuperSql := "select 1 from t_data_user where id=? and role=(select id from global_const_code where code='role_superadmin')" _, err = o.Raw(checkSuperSql, userid).Values(&lst) if len(lst) > 0 { //超级管理员,返回所有功能菜单 para := orm.Params{"code": "all"} return []orm.Params{para}, nil } sql := "select b.code,b.name,case when substr(b.code,1,8)='pl_menu_' then (select code from global_const_code where parentcode=b.code and name='url') else '' end url from t_data_role_func a,global_const_code b,t_data_user c where a.roleid=c.role and a.funccodeid=b.id and c.id=?" _, err = o.Raw(sql, userid).Values(&lst) return lst, err } func GetSessionInfo(sessionid string) (userinfo T_data_usersession, err error) { o := orm.NewOrm() obj := T_data_usersession{Sessionid: sessionid} err = o.Read(&obj) if err != nil { return T_data_usersession{}, err } userinfo.Sessionid = obj.Sessionid userinfo.Userid = obj.Userid userinfo.Lastdt = obj.Lastdt return obj, nil } func RemoveSession(sessionid string) error { if sessionid == "" { return nil } o := orm.NewOrm() obj := T_data_usersession{Sessionid: sessionid} _, err := o.Delete(&obj) global.GoCahce.Delete(sessionid) global.GoCahce.Delete(sessionid + "_userinfo") global.GoCahce.Delete(sessionid + "_apis") return err } //session续期。超时10分钟则自动过期,需要重新登录认证 func UpdateSession(sessionid string) error { if _, has := global.GoCahce.Get(sessionid); has { return nil } uinfo, err := GetSessionInfo(sessionid) if err != nil { return err } lastdt := uinfo.Lastdt //fmt.Println(uinfo) //fmt.Println(time.Now().Unix()) if global.SessionTimeout > 0 { if (time.Now().Unix() - lastdt) > int64(global.SessionTimeout) { return errors.New("session超时") } } global.GoCahce.Set(sessionid, uinfo, 30*time.Second) uid := uinfo.Userid return SetSession(sessionid, strconv.Itoa(uid)) } func SetSession(sessionid string, userid string) error { o := orm.NewOrm() uid, _ := strconv.Atoi(userid) obj := T_data_usersession{Sessionid: sessionid, Userid: uid, Lastdt: time.Now().Unix()} u, er := GetSessionInfo(sessionid) if er != nil && er != orm.ErrNoRows { return er } if u.Sessionid != "" { _, er = o.Update(&obj) } else { //清空该用户原来的token oldtokens := []orm.Params{} o.Raw("select sessionid from t_data_usersession where userid=?", userid).Values(&oldtokens) if len(oldtokens) > 0 { for _, row := range oldtokens { key := tools.IsEmpty(row["sessionid"]) + "_apis" global.GoCahce.Delete(key) global.GoCahce.Delete(tools.IsEmpty(row["sessionid"]) + "_userinfo") } o.Raw("delete from t_data_usersession where userid=?", userid).Exec() } _, er = o.Insert(&obj) if er != nil { logger.Logger.Error(er) } else { //加载该token的接口权限 go func(token, userid string) { useridint, _ := strconv.Atoi(userid) funcs, _ := GetUserFunc(useridint) if funcs != nil { fl := funcs.([]orm.Params) funcmap := map[string]bool{} for _, r := range fl { funcmap[tools.IsEmpty(r["code"])] = true } global.GoCahce.Set(token+"_apis", funcmap, -1) } }(sessionid, userid) } } return er } //判断当前token是否具有指定的某个接口权限 func HasApiAccess(sessionid, apipath string) bool { key := sessionid + "_apis" if v, h := global.GoCahce.Get(key); h { v1 := v.(map[string]bool) if v1["all"] { //拥有所有权限的用户 return true } if v1[apipath] { return true } else { //检查当前接口是否在授权列表中,如果不在授权列表中,表示该接口不需要授权访问 _, h := global.ApiDocCache.Load(fmt.Sprintf("apidoc_%s", apipath)) return !h } } else { return false } return false } //根据token返回当前登录用户信息 func GetUserInfoByToken(token string) (info map[string]interface{}, err error) { key := token + "_userinfo" tokenSync.Lock() defer tokenSync.Unlock() if v, ok := global.GoCahce.Get(key); ok { newObj := make(map[string]interface{}) //拷贝一个新对象 for k, v := range v.(map[string]interface{}) { newObj[k] = v } return newObj, nil } o := orm.NewOrm() sql := "select a.*,b.name,b.account,b.role from t_data_usersession a,t_data_user b where a.userid=b.id and a.sessionid=?" obj := []orm.Params{} _, dberr := o.Raw(sql, token).Values(&obj) if dberr != nil { return nil, dberr } if len(obj) == 0 { return nil, nil } returninfo := make(map[string]interface{}) for k, v := range obj[0] { returninfo[k] = v } global.GoCahce.Set(key, returninfo, 30*time.Minute) return returninfo, nil } func CacheLoginFialInfo(key string) { if info, ok := LoginInfo.Load(key); ok { //失败次数 info2 := info.(map[string]interface{}) failcount := info2["count"].(int) info2["count"] = failcount + 1 info2["lasttime"] = time.Now().Unix() } else { LoginInfo.Store(key, map[string]interface{}{"count": 1, "lasttime": time.Now().Unix()}) } } //加载全局参数 func LoadGlobalParam() { v, err := GetSysParamValue("session_timeout", "600") if err != nil { tools.Log("加载Session超时时长参数失败:" + err.Error()) return } global.SessionTimeout, _ = strconv.Atoi(v) } //加载并检查系统管理员帐号 func CheckSystemUser() (exists bool, err error) { o := orm.NewOrm() data := []orm.Params{} result := false sqlCommandText := "select 1 from t_data_user where account=?;" _, dbError := o.Raw(sqlCommandText, "Administrator").Values(&data) if dbError == nil { if len(data) == 0 { //获取超级管理员角色ID key := "global_code_pl_role_coderole_superadmin" v, _ := global.GoCahce.Get(key) parameter := map[string]interface{}{} parameter["userid"] = "0" parameter["username"] = "Administrator" parameter["account"] = "Administrator" parameter["password"] = "Administrator@123" if v == nil { parameter["role"] = 1 } else { v1 := v.(orm.Params) parameter["role"], _ = strconv.Atoi(tools.IsEmpty(v1["id"])) } parameter["memo"] = "系统超级管理员" result, dbError = CreateUser(parameter) if dbError != nil { return false, dbError } else { result = true } } else { result = true } } return result, dbError } func UserLogin(account string, pwd string) (userinfo map[string]interface{}, err error) { o := orm.NewOrm() data := []orm.Params{} var result = map[string]interface{}{} has := md5.Sum([]byte(pwd)) pwd = fmt.Sprintf("%x", has) sqlCommandText := "select a.*,b.name userrole,b.code rolecode from t_data_user a left join global_const_code b on a.role=b.id where a.account=? and a.pwd=?" _, dbError := o.Raw(sqlCommandText, account, pwd).Values(&data) if dbError == nil { if len(data) > 0 { //判断密码是否过期 pwd_expire := tools.IsEmpty(data[0]["pwd_expire"]) if tools.IsEmpty(data[0]["rolecode"]) != "role_superadmin" && pwd_expire != "" && pwd_expire != "1970-01-01 00:00:00" { //判断是否过期 expireDate, _ := time.Parse("2006-01-02 15:04:05", pwd_expire) if expireDate.Unix() < time.Now().Unix() { logger.Logger.Debug(data) return result, errors.New("您的密码已过期,请联系管理员更新后重试!") } } LoginInfo.Store(account, map[string]interface{}{"count": 1, "lasttime": time.Now().Unix()}) result["userid"] = tools.IsEmpty(data[0]["id"]) result["name"] = tools.IsEmpty(data[0]["name"]) result["role"] = tools.IsEmpty(data[0]["role"]) result["bind_ips"] = tools.IsEmpty(data[0]["bind_ips"]) result["datelimit_start"] = tools.IsEmpty(data[0]["datelimit_start"]) result["datelimit_end"] = tools.IsEmpty(data[0]["datelimit_end"]) result["rolename"] = tools.IsEmpty(data[0]["userrole"]) return result, nil } else { CacheLoginFialInfo(account) return result, errors.New("用户帐号" + account + "或密码" + pwd + "错误!") } } else { return result, dbError } } //创建用户信息 func CreateUser(parameter map[string]interface{}, userinfo ...map[string]interface{}) (status bool, errs error) { userData := T_data_user{} o := orm.NewOrm() var paramvalues = []interface{}{} var userid int var Account string var modify_password = true //sqlCommandText := "" if userId, ok2 := parameter["userid"]; ok2 && tools.IsEmpty(userId) != "" { userid, _ = strconv.Atoi(userId.(string)) userData.Id = userid o.Read(&userData) } dblog := new(SystemLog) dblog.Audittype = enum.AuditType_admin_system_user dblog.Logtype = enum.LogType_Insert dblog.Eventtype = enum.OptEventType_Bus dblog.Eventlevel = enum.OptEventLevel_Hight if len(userinfo) > 0 { dblog.SetUserInfo(userinfo[0]) userData.Createuser, _ = strconv.Atoi(tools.IsEmpty(userinfo[0]["userid"])) } else { dblog.SetUserInfo(map[string]interface{}{"name": "", "ip": "127.0.0.1"}) } if username, ok2 := parameter["username"]; ok2 { if tools.IsEmpty(username) != "" { paramvalues = append(paramvalues, username) } else { dblog.Description = fmt.Sprintf("保存用户信息失败|%s,错误:%s", "", "用户姓名为空") dblog.Fail2() return false, errors.New("用户姓名字段不允许为空!") } userData.Name = tools.IsEmpty(username) } else { return false, errors.New("请传入用户姓名参数!") } if account, ok2 := parameter["account"]; ok2 { if tools.IsEmpty(account) != "" { paramvalues = append(paramvalues, account) } else { dblog.Description = fmt.Sprintf("保存用户信息失败|%s,错误:%s", parameter["username"], "用户帐号为空") dblog.Fail2() return false, errors.New("用户帐号字段不允许为空!") } userData.Account = tools.IsEmpty(account) } else { dblog.Description = fmt.Sprintf("保存用户信息失败|%s,错误:%s", parameter["username"], "未设置用户帐号") dblog.Fail2() return false, errors.New("请传入用户帐号参数!") } if password, ok2 := parameter["password"]; ok2 { passwordStr := tools.IsEmpty(password) if passwordStr != "" { if len(passwordStr) > 32 { passwordStr = tools.OriginalCode(passwordStr) } //密码规则校验 check, msg := PwdRuleCheck(passwordStr) if !check { dblog.Description = fmt.Sprintf("保存用户信息失败|%s,错误:%s", parameter["username"], msg) dblog.Fail2() return false, errors.New(msg) } has := md5.Sum([]byte(passwordStr)) password = fmt.Sprintf("%x", has) paramvalues = append(paramvalues, password) modify_password = true userData.Pwd = tools.IsEmpty(password) } else if userid == 0 { dblog.Description = fmt.Sprintf("保存用户信息失败|%s,错误:%s", parameter["username"], "帐号密码为空") dblog.Fail2() return false, errors.New("用户帐号密码不允许为空!") } else { modify_password = false } } else { dblog.Description = fmt.Sprintf("保存用户信息失败|%s,错误:%s", parameter["username"], "未设置帐号密码") dblog.Fail2() return false, errors.New("请传入用户密码参数!") } if memo, ok2 := parameter["memo"]; ok2 { paramvalues = append(paramvalues, memo) userData.Memo = tools.IsEmpty(memo) } else { paramvalues = append(paramvalues, "") } if role, ok2 := parameter["role"]; ok2 { paramvalues = append(paramvalues, role) userData.Role, _ = strconv.Atoi(tools.IsEmpty(role)) } else { paramvalues = append(paramvalues, 0) } if mbphone, ok2 := parameter["mobilephone"]; ok2 { paramvalues = append(paramvalues, mbphone) userData.Mobilephone = tools.IsEmpty(mbphone) } else { paramvalues = append(paramvalues, "") } if ips, ok2 := parameter["bind_ips"]; ok2 { paramvalues = append(paramvalues, ips) userData.BindIps = tools.IsEmpty(ips) if userData.BindIps != "" && !tools.VerifyIPFormat(userData.BindIps) { dblog.Description = fmt.Sprintf("保存用户信息失败|%s,错误:%s", parameter["username"], "无效的ip或者ip段") dblog.Fail2() return false, errors.New("无效的ip或者ip段!") } } else { paramvalues = append(paramvalues, "") } //判断用户是否存在 message := existsUser(userid, Account) if message != nil { dblog.Description = fmt.Sprintf("保存用户信息失败|%s,错误:%s", parameter["username"], message) dblog.Fail2() return false, message } if v, ok2 := parameter["datelimit_start"]; ok2 { userData.DatelimitStart = tools.IsEmpty(v) } if v, ok2 := parameter["datelimit_end"]; ok2 { userData.DatelimitEnd = tools.IsEmpty(v) } if modify_password || userData.DatelimitEnd != "" { //密码过期时间:单位天 pwd_expire_day, _ := GetSysParamValue("user_pwd_expire_day", "60") pwd_expire_date := "" if pwd_expire_day == "0" { //永不过期 pwd_expire_date = "1970-01-01 00:00:00" } else if userData.DatelimitEnd != "" { pwd_expire_date = userData.DatelimitEnd } else { pwd_expire_dayInt, _ := strconv.Atoi(pwd_expire_day) pwd_expire_dayInt = pwd_expire_dayInt * 24 d, _ := time.ParseDuration(strconv.Itoa(pwd_expire_dayInt) + "h") pwd_expire_date = time.Now().Add(d).Format("2006-01-02 15:04:05") } paramvalues = append(paramvalues, pwd_expire_date) userData.PwdExpire = pwd_expire_date } var err error if userid > 0 { //判断修改用户信息时是否修改了密码 /*if modify_password { sqlCommandText = "update t_data_user set name=?,account=?,pwd=?,memo=?,role=?,mobilephone=?,bind_ips=?,pwd_expire=? where id=?" } else { sqlCommandText = "update t_data_user set name=?,account=?,memo=?,role=?,mobilephone=?,bind_ips=? where id=?" } paramvalues = append(paramvalues, userid) */ _, err = o.Update(&userData) } else { userData.Createtime = tools.NowTime() //sqlCommandText = "insert into t_data_user(name,account,pwd,memo,role,mobilephone,bind_ips,pwd_expire)values(?,?,?,?,?,?,?);" _, err = o.Insert(&userData) } //_, err := o.Raw(sqlCommandText, paramvalues).Exec() if err != nil { logger.Logger.Error(err) dblog.Description = fmt.Sprintf("保存用户信息失败|%s,错误:%s", parameter["username"], err.Error()) dblog.Fail2() return false, err } else { dblog.Description = fmt.Sprintf("保存用户信息成功|%s", parameter["username"]) dblog.Success2() return true, nil } } //密码规则检查 func PwdRuleCheck(passwordStr string) (bool, string) { //密码规则校验 rule, _ := GetSysParamValue("user_pwd_rule", "simple") if rule == "simple" { if len(passwordStr) < 6 || len(passwordStr) > 32 { return false, "用户帐号密码长度只能为6-32位字符!" } } else { if len(passwordStr) < 8 || len(passwordStr) > 32 { return false, "用户帐号密码长度只能为8-32位字符!" } reg1, _ := regexp.Compile("[A-Z]") reg2, _ := regexp.Compile("[a-z]") reg3, _ := regexp.Compile("[0-9]") reg4, _ := regexp.Compile(`[~!@#$%^&*()_\-+=<>?:"{}|,.\/;'\\[\]·~!@#¥%&*]`) if !reg1.MatchString(passwordStr) || !reg2.MatchString(passwordStr) || !reg3.MatchString(passwordStr) || !reg4.MatchString(passwordStr) { return false, "用户帐号密码长度只能为8-32位字符且由大小写字母、数字和特殊字符组成!" } } return true, "" } //初始化用户表 func InitUser() (status bool, errs error) { o := orm.NewOrm() sqlCommandText := "delete from t_data_user where name!=?" _, err := o.Raw(sqlCommandText, "Rtelec").Exec() if err != nil { return false, err } else { o.Raw("delete from t_data_usersession").Exec() return true, nil } } //删除用户 func DelUser(userId string, userinfo map[string]interface{}) (status bool, errs error) { dblog := new(SystemLog) dblog.SetUserInfo(userinfo) dblog.Audittype = enum.AuditType_admin_system_user dblog.Logtype = enum.LogType_Delete dblog.Eventtype = enum.OptEventType_Bus dblog.Eventlevel = enum.OptEventLevel_Hight o := orm.NewOrm() sqlCommandText := "delete from t_data_user where id=?" _, err := o.Raw(sqlCommandText, userId).Exec() if err != nil { dblog.Description = fmt.Sprintf("删除用户%s失败,错误:%s", userId, err.Error()) dblog.Fail2() return false, err } else { //删除该用户的关联区域信息 usArea := new(UserAreaRelationObject) usArea.SetUserInfo(userinfo) usArea.Model.Userid, _ = strconv.Atoi(userId) usArea.Delete() dblog.Description = fmt.Sprintf("删除用户%s成功", userId) dblog.Success2() return true, nil } } func existsUser(userId int, account string) error { ts := []orm.Params{} o := orm.NewOrm() var parameter = []interface{}{} sqlCommandText := "" if userId > 0 { sqlCommandText = "select 1 from t_data_user where account=? and id!=?" parameter = append(parameter, account, userId) } else { sqlCommandText = "select 1 from t_data_user where account=? " parameter = append(parameter, account) } _, err := o.Raw(sqlCommandText, parameter).Values(&ts) if err != nil { return err } if len(ts) > 0 { return errors.New("已存在用户帐号:" + account) } else { return nil } } func SearchUserInfo(area_id, name, role_id string, pageIndex, pageSize int, userinfo map[string]interface{}) ([]orm.Params, int, error) { dblog := new(SystemLog) dblog.SetUserInfo(userinfo) dblog.Audittype = enum.AuditType_admin_system_user dblog.Logtype = enum.LogType_Query dblog.Eventtype = enum.OptEventType_Bus dblog.Eventlevel = enum.OptEventLevel_Low o := orm.NewOrm() var sqlCommandText, totalSql string sqlCommandText = "select a.*,b.name rolename,b.code rolecode,(select ifnull(count(1),0) from t_relation_user_area where userid=a.id and areaid>0)area_count from t_data_user a left join global_const_code b on a.role=b.id where " sqlWhere := []string{"1=1"} sqlParamer := []interface{}{} sqlWhere = append(sqlWhere, " not EXISTS (select 1 from global_const_code where a.role=id and code='role_superadmin')") var limit = " limit " + strconv.Itoa((pageIndex-1)*pageSize) + "," + strconv.Itoa(pageSize) if role_id != "" { sqlWhere = append(sqlWhere, " a.role=?") sqlParamer = append(sqlParamer, role_id) } if name != "" { sqlWhere = append(sqlWhere, " a.name like ?") sqlParamer = append(sqlParamer, "%"+name+"%") } if area_id != "" { sqlWhere = append(sqlWhere, " EXISTS(select 1 from t_relation_user_area ua where a.id=ua.userid and ua.areaid=?)") sqlParamer = append(sqlParamer, area_id) } sqlCommandText += strings.Join(sqlWhere, " and ") sqlCommandText += " order by a.id desc " + limit totalSql = "select count(1) number from t_data_user a where " + strings.Join(sqlWhere, " and ") var tableData []orm.Params var number int _, err := o.Raw(sqlCommandText, sqlParamer).Values(&tableData) dblog.Description = fmt.Sprintf("SQL:%s,参数:%+v", sqlCommandText, sqlParamer) if err == nil { dblog.Success2() var totalData []orm.Params _, err = o.Raw(totalSql, sqlParamer).Values(&totalData) if err == nil { number, _ = strconv.Atoi(totalData[0]["number"].(string)) } } else { logger.Logger.Error(err, dblog.Description) dblog.Fail2() } return tableData, number, err }