parent
be6eca5128
commit
814258931b
@ -1 +1 @@
|
|||||||
{"pid":27289}
|
{"pid":28155}
|
||||||
@ -1,3 +1,3 @@
|
|||||||
package init
|
package init
|
||||||
|
|
||||||
import _ "src/module/category"
|
//import _ "src/module/category"
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
package init
|
||||||
|
|
||||||
|
import "src/module/usercenter"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
usercenter.InitManageApi()
|
||||||
|
}
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
package usercenter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"math/big"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var regSMSVerificationCode sync.Map
|
||||||
|
|
||||||
|
// 登记注册用验证码
|
||||||
|
func StoreRegSMSVerificationCode(mobile string) (string, error) {
|
||||||
|
codeInterface, ok := regSMSVerificationCode.Load(mobile)
|
||||||
|
if ok {
|
||||||
|
return codeInterface.(string), nil
|
||||||
|
}
|
||||||
|
verificationCode := randCharNumber(6)
|
||||||
|
regSMSVerificationCode.Store(mobile, verificationCode)
|
||||||
|
go func(mobile string) {
|
||||||
|
time.Sleep(time.Second * 5 * 60)
|
||||||
|
regSMSVerificationCode.Delete(mobile)
|
||||||
|
}(mobile)
|
||||||
|
return verificationCode, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证注册验证码
|
||||||
|
func RegSMSVerification(mobile, verificationCode string) bool {
|
||||||
|
codeInterface, ok := regSMSVerificationCode.LoadAndDelete(mobile)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if codeInterface.(string) == verificationCode {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 随机验证码
|
||||||
|
func randCharNumber(size int) string {
|
||||||
|
char := "0123456789"
|
||||||
|
len64 := int64(len(char))
|
||||||
|
var s bytes.Buffer
|
||||||
|
for i := 0; i < size; i++ {
|
||||||
|
in, _ := rand.Int(rand.Reader, big.NewInt(len64))
|
||||||
|
s.WriteByte(char[in.Int64()])
|
||||||
|
}
|
||||||
|
return s.String()
|
||||||
|
}
|
||||||
@ -0,0 +1,293 @@
|
|||||||
|
package usercenter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"regexp"
|
||||||
|
"src/module/tencent"
|
||||||
|
|
||||||
|
"github.com/towgo/towgo/towgo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func InitManageApi() {
|
||||||
|
|
||||||
|
//初始化API加载器
|
||||||
|
initLoader()
|
||||||
|
|
||||||
|
//注册JSON-RPC服务处理器method路由
|
||||||
|
//账户登录 F
|
||||||
|
towgo.SetFunc(_methodHead+"/user/login", userLogin)
|
||||||
|
|
||||||
|
//获取自己的账户信息
|
||||||
|
towgo.SetFunc(_methodHead+"/user/myinfo", userMyinfo)
|
||||||
|
|
||||||
|
//账户注销 F
|
||||||
|
towgo.SetFunc(_methodHead+"/user/logoff", userLogoff)
|
||||||
|
|
||||||
|
//账户注册移动用户注册
|
||||||
|
towgo.SetFunc(_methodHead+"/user/regByMobile", userRegByMobile)
|
||||||
|
|
||||||
|
//获取注册短信验证码
|
||||||
|
towgo.SetFunc(_methodHead+"/user/getRegSMSVerificationCode", getRegSMSVerificationCode)
|
||||||
|
|
||||||
|
//修改密码 F
|
||||||
|
towgo.SetFunc(_methodHead+"/user/changepassword", userChangepassword)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func isPhoneNumber(input string) bool {
|
||||||
|
// 中国手机号码正则表达式
|
||||||
|
// 13[0-9], 14[5,7,9], 15[0-3,5-9], 16[6], 17[0-8], 18[0-9], 19[1,8,9]
|
||||||
|
phoneNumberPattern := `^1([38][0-9]|14[579]|5[^4]|6[6]|7[0-8]|9[189])\d{8}$`
|
||||||
|
reg := regexp.MustCompile(phoneNumberPattern)
|
||||||
|
return reg.MatchString(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRegSMSVerificationCode(rpcConn towgo.JsonRpcConnection) {
|
||||||
|
var params struct {
|
||||||
|
Mobile string `json:"mobile"`
|
||||||
|
}
|
||||||
|
rpcConn.ReadParams(¶ms)
|
||||||
|
|
||||||
|
if !isPhoneNumber(params.Mobile) {
|
||||||
|
rpcConn.WriteError(500, "手机号码非法")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
code, err := StoreRegSMSVerificationCode(params.Mobile)
|
||||||
|
|
||||||
|
err = tencent.SendSMSVerificationCode("2030693", "蕊鑫信息科技", params.Mobile, code)
|
||||||
|
if err != nil {
|
||||||
|
rpcConn.WriteError(500, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rpcConn.WriteResult("验证码已经发送,请查收")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册用户
|
||||||
|
func userRegByMobile(rpcConn towgo.JsonRpcConnection) {
|
||||||
|
result := map[string]interface{}{} //初始化结果参数
|
||||||
|
|
||||||
|
var params struct {
|
||||||
|
Mobile string `json:"mobile"`
|
||||||
|
VerificationCode string `json:"verification_code"`
|
||||||
|
}
|
||||||
|
|
||||||
|
rpcConn.ReadParams(¶ms)
|
||||||
|
|
||||||
|
if params.Mobile == "" {
|
||||||
|
rpcConn.WriteError(500, "手机号码不能为空")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if params.VerificationCode == "" {
|
||||||
|
rpcConn.WriteError(500, "验证码不能为空")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !RegSMSVerification(params.Mobile, params.VerificationCode) {
|
||||||
|
rpcConn.WriteError(500, "验证码错误")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var user User
|
||||||
|
user.Username = params.Mobile
|
||||||
|
user.Password = randCharNumber(8)
|
||||||
|
|
||||||
|
/*
|
||||||
|
user := user{}
|
||||||
|
user.Nickname = jsonObj.Params.Nickname
|
||||||
|
user.Email = jsonObj.Params.Email
|
||||||
|
*/
|
||||||
|
Err := user.Reg(user.Username, user.Password)
|
||||||
|
if Err != nil {
|
||||||
|
rpcConn.WriteError(500, Err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//拼装结果返回
|
||||||
|
result["id"] = user.ID
|
||||||
|
result["username"] = user.Username
|
||||||
|
rpcConn.WriteResult(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户登陆
|
||||||
|
func userLogin(rpcConn towgo.JsonRpcConnection) {
|
||||||
|
result := map[string]interface{}{} //初始化结果参数
|
||||||
|
var err error
|
||||||
|
|
||||||
|
rpcResponse := rpcConn.GetRpcResponse()
|
||||||
|
jsonObj := struct {
|
||||||
|
Params struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
} `json:"params"`
|
||||||
|
}{}
|
||||||
|
err = json.Unmarshal([]byte(rpcConn.Read()), &jsonObj)
|
||||||
|
if err != nil {
|
||||||
|
rpcResponse.Error.Set(1, err.Error())
|
||||||
|
rpcConn.Write()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if jsonObj.Params.Username == "" {
|
||||||
|
rpcResponse.Error.Set(1001, "")
|
||||||
|
rpcConn.Write()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if jsonObj.Params.Password == "" {
|
||||||
|
rpcResponse.Error.Set(1002, "")
|
||||||
|
rpcConn.Write()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user := User{}
|
||||||
|
loginErr := user.Login(jsonObj.Params.Username, jsonObj.Params.Password)
|
||||||
|
|
||||||
|
if loginErr != nil { //模型层登陆成功
|
||||||
|
//dblog.Write("user:info", fmt.Sprintf("%s@%s 登录失败! 错误信息:%s", user.Username, rpcConn.GetRemoteAddr(), loginErr.Error()))
|
||||||
|
rpcResponse.Error.Set(1, "用户名或密码错误")
|
||||||
|
rpcConn.Write()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result["id"] = user.ID
|
||||||
|
result["username"] = user.Username
|
||||||
|
|
||||||
|
result["token"] = user.UserToken.TokenKey
|
||||||
|
|
||||||
|
//dblog.Write("user:info", fmt.Sprintf("%s@%s 登录成功!", user.Username, rpcConn.GetRemoteAddr()))
|
||||||
|
rpcConn.WriteResult(result)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// token check
|
||||||
|
func userTokenCheck(rpcConn towgo.JsonRpcConnection) {
|
||||||
|
result := map[string]interface{}{} //初始化结果参数
|
||||||
|
var err error
|
||||||
|
|
||||||
|
rpcResponse := rpcConn.GetRpcResponse()
|
||||||
|
jsonObj := struct {
|
||||||
|
Session string `json:"session"`
|
||||||
|
Params struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
Userid int `json:"userid"`
|
||||||
|
Token string `json:"token"`
|
||||||
|
} `json:"params"`
|
||||||
|
}{}
|
||||||
|
err = json.Unmarshal([]byte(rpcConn.Read()), &jsonObj)
|
||||||
|
if err != nil {
|
||||||
|
rpcResponse.Error.Set(1, err.Error())
|
||||||
|
rpcConn.Write()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var user *User
|
||||||
|
user, err = user.LoginByToken(jsonObj.Params.Token)
|
||||||
|
if err != nil {
|
||||||
|
result["valid"] = false
|
||||||
|
rpcConn.WriteResult(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if user.ID == 0 {
|
||||||
|
result["valid"] = false
|
||||||
|
rpcConn.WriteResult(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !user.UserToken.Valid() {
|
||||||
|
result["valid"] = false
|
||||||
|
rpcConn.WriteResult(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result["valid"] = true
|
||||||
|
rpcConn.WriteResult(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户注销
|
||||||
|
func userLogoff(rpcConn towgo.JsonRpcConnection) {
|
||||||
|
//result := map[string]interface{}{} //初始化结果参数
|
||||||
|
var err error
|
||||||
|
|
||||||
|
rpcResponse := rpcConn.GetRpcResponse()
|
||||||
|
jsonObj := struct {
|
||||||
|
Session string `json:"session"`
|
||||||
|
}{}
|
||||||
|
err = json.Unmarshal([]byte(rpcConn.Read()), &jsonObj)
|
||||||
|
if err != nil {
|
||||||
|
rpcResponse.Error.Set(1, err.Error())
|
||||||
|
rpcConn.Write()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var user *User
|
||||||
|
user, err = user.LoginByToken(jsonObj.Session)
|
||||||
|
if err != nil {
|
||||||
|
rpcConn.WriteResult(map[string]string{"success": "ok"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if user.ID > 0 {
|
||||||
|
user.Logoff()
|
||||||
|
}
|
||||||
|
|
||||||
|
rpcConn.WriteResult(map[string]string{"success": "ok"})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func userMyinfo(rpcConn towgo.JsonRpcConnection) {
|
||||||
|
userSession, err := LoginByToken(rpcConn.GetRpcRequest().Session)
|
||||||
|
userSession.Token = rpcConn.GetRpcRequest().Session
|
||||||
|
if err != nil {
|
||||||
|
rpcConn.GetRpcResponse().Error.Set(401, err.Error())
|
||||||
|
rpcConn.Write()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rpcConn.WriteResult(userSession)
|
||||||
|
}
|
||||||
|
|
||||||
|
func userChangepassword(rpcConn towgo.JsonRpcConnection) {
|
||||||
|
result := map[string]interface{}{} //初始化结果参数
|
||||||
|
var err error
|
||||||
|
|
||||||
|
rpcResponse := rpcConn.GetRpcResponse()
|
||||||
|
jsonObj := struct {
|
||||||
|
Session string `json:"session"`
|
||||||
|
Params struct {
|
||||||
|
Oldpassword string `json:"oldpassword"`
|
||||||
|
Newpassword string `json:"newpassword"`
|
||||||
|
} `json:"params"`
|
||||||
|
}{}
|
||||||
|
err = json.Unmarshal([]byte(rpcConn.Read()), &jsonObj)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
rpcResponse.Error.Set(1, err.Error())
|
||||||
|
rpcConn.WriteResult(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var user *User
|
||||||
|
user, err = user.LoginByToken(jsonObj.Session)
|
||||||
|
if err != nil {
|
||||||
|
rpcResponse.Error.Set(401, err.Error())
|
||||||
|
rpcConn.WriteResult(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.ID == 0 {
|
||||||
|
rpcResponse.Error.Set(1003, "")
|
||||||
|
rpcConn.WriteResult(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = user.Changepassword(jsonObj.Params.Oldpassword, jsonObj.Params.Newpassword)
|
||||||
|
if err != nil {
|
||||||
|
rpcResponse.Error.Set(1, err.Error())
|
||||||
|
rpcConn.WriteResult(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rpcConn.WriteResult(struct {
|
||||||
|
Success string `json:"success"`
|
||||||
|
}{Success: "ok"})
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
package usercenter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/towgo/towgo/dao/ormDriver/xormDriver"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _methodHead string
|
||||||
|
var _tableHead string
|
||||||
|
|
||||||
|
func SetMethodHead(methodHead string) {
|
||||||
|
_methodHead = methodHead
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetTableHead(tableHead string) {
|
||||||
|
_tableHead = tableHead
|
||||||
|
}
|
||||||
|
|
||||||
|
func initLoader() {
|
||||||
|
|
||||||
|
//token任务
|
||||||
|
InitTokenTask()
|
||||||
|
|
||||||
|
xormDriver.Sync2(new(User), new(UserToken))
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,280 @@
|
|||||||
|
package usercenter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/towgo/towgo/dao/basedboperat"
|
||||||
|
"github.com/towgo/towgo/lib/system"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (User) TableName() string {
|
||||||
|
return _tableHead + "users"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*User) CacheExpire() int64 {
|
||||||
|
return 5000
|
||||||
|
}
|
||||||
|
|
||||||
|
// 账户对象 关联账户信息
|
||||||
|
type User struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Nickname string `json:"nickname"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Salt string `json:"-"` //密码加盐
|
||||||
|
Email string `json:"email"`
|
||||||
|
Mobile string `json:"mobile"`
|
||||||
|
CanDelete bool `json:"-"`
|
||||||
|
AccessToken string `json:"-"`
|
||||||
|
Token string `json:"token" gorm:"-" xorm:"-"`
|
||||||
|
UserToken *UserToken `json:"-" gorm:"-" xorm:"-"`
|
||||||
|
CreatedAt int64 `json:"created_at"` //创建时间
|
||||||
|
UpdatedAt int64 `json:"updated_at"` //更新时间
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册
|
||||||
|
func (a *User) Reg(username, password string) error {
|
||||||
|
|
||||||
|
e := a.CheckForInput(username, password)
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
//数据库查询出用户信息
|
||||||
|
|
||||||
|
finduser := User{}
|
||||||
|
basedboperat.Get(&finduser, nil, "username = ?", username)
|
||||||
|
|
||||||
|
//检查用户名是否存在
|
||||||
|
if username == finduser.Username {
|
||||||
|
return errors.New("账户已经存在")
|
||||||
|
}
|
||||||
|
|
||||||
|
//生成密码
|
||||||
|
a.NewPassword(password)
|
||||||
|
|
||||||
|
a.Username = username
|
||||||
|
a.CanDelete = true
|
||||||
|
|
||||||
|
_, err := basedboperat.Create(a) // 通过数据的指针来创建
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = a.CreateRelation()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查输入参数
|
||||||
|
func (a *User) CheckForInput(username, password string) error {
|
||||||
|
|
||||||
|
if username == "" {
|
||||||
|
return errors.New("用户名不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
if password == "" {
|
||||||
|
return errors.New("密码不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
//防sql注入
|
||||||
|
if system.FilteredSQLInject(username) {
|
||||||
|
return errors.New("用户名存在系统保留或非法的字符")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *User) NewPassword(newpassword string) {
|
||||||
|
if newpassword == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//加密密码
|
||||||
|
|
||||||
|
password := system.MD5(newpassword)
|
||||||
|
|
||||||
|
//生成salt
|
||||||
|
salt := system.RandCharCrypto(6)
|
||||||
|
|
||||||
|
//密码加盐
|
||||||
|
password = password + salt
|
||||||
|
|
||||||
|
//混合加密
|
||||||
|
password = system.MD5(password)
|
||||||
|
|
||||||
|
a.Password = password
|
||||||
|
a.Salt = salt
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户登陆
|
||||||
|
func (a *User) Login(username, password string) error {
|
||||||
|
|
||||||
|
erro := a.CheckForInput(username, password)
|
||||||
|
if erro != nil {
|
||||||
|
return erro
|
||||||
|
}
|
||||||
|
|
||||||
|
//通过用户名查询用户数据
|
||||||
|
err := basedboperat.Get(a, nil, "username = ?", username)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//检查用户名是否存在
|
||||||
|
|
||||||
|
//判断用户是否存在
|
||||||
|
if a.Username == "" {
|
||||||
|
return errors.New("用户名不存在")
|
||||||
|
}
|
||||||
|
|
||||||
|
//加密密码
|
||||||
|
upassword := system.MD5(password)
|
||||||
|
|
||||||
|
//撒盐
|
||||||
|
upassword = upassword + a.Salt
|
||||||
|
|
||||||
|
//混合加密
|
||||||
|
upassword = system.MD5(upassword)
|
||||||
|
|
||||||
|
//判断密码是否一致
|
||||||
|
if a.Password != upassword {
|
||||||
|
//不一致:返回错误
|
||||||
|
return errors.New("密码错误")
|
||||||
|
}
|
||||||
|
|
||||||
|
//验证通过
|
||||||
|
|
||||||
|
//生成用户信息
|
||||||
|
a.UserToken = NewToken(a)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户注销
|
||||||
|
func (a *User) Logoff() {
|
||||||
|
DeleteToken(a.UserToken.TokenKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoginByToken(tokenKey string) (*User, error) {
|
||||||
|
userToken, err := GetToken(tokenKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sessionuser := userToken.Payload.(*User)
|
||||||
|
sessionuser.UserToken = userToken
|
||||||
|
return sessionuser, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *User) LoginByToken(tokenKey string) (*User, error) {
|
||||||
|
userToken, err := GetToken(tokenKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sessionuser := userToken.Payload.(*User)
|
||||||
|
sessionuser.UserToken = userToken
|
||||||
|
return sessionuser, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *User) CheckToken(s string) bool {
|
||||||
|
//判断token是否正确
|
||||||
|
if s != a.UserToken.TokenKey {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
//再判断token是否过期
|
||||||
|
return a.UserToken.Valid()
|
||||||
|
}
|
||||||
|
func (a *User) Get() error {
|
||||||
|
|
||||||
|
if a.ID > 0 {
|
||||||
|
return basedboperat.Get(a, nil, "id = ?", a.ID)
|
||||||
|
}
|
||||||
|
if a.Username != "" {
|
||||||
|
return basedboperat.Get(a, nil, "username = ?", a.Username)
|
||||||
|
}
|
||||||
|
return errors.New("id或username不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改密码
|
||||||
|
func (a *User) Changepassword(oldpassword, newpassword string) error {
|
||||||
|
|
||||||
|
//通过用户名查询用户数据
|
||||||
|
|
||||||
|
err := basedboperat.Get(a, nil, "id = ?", a.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//检查用户名是否存在
|
||||||
|
|
||||||
|
//判断用户是否存在
|
||||||
|
if a.Username == "" {
|
||||||
|
return errors.New("用户名不存在")
|
||||||
|
}
|
||||||
|
|
||||||
|
//加密密码
|
||||||
|
upassword := system.MD5(oldpassword)
|
||||||
|
|
||||||
|
//撒盐
|
||||||
|
upassword = upassword + a.Salt
|
||||||
|
|
||||||
|
//混合加密
|
||||||
|
upassword = system.MD5(upassword)
|
||||||
|
|
||||||
|
//判断密码是否一致
|
||||||
|
if a.Password != upassword {
|
||||||
|
//不一致:返回错误
|
||||||
|
return errors.New("原始密码错误")
|
||||||
|
}
|
||||||
|
|
||||||
|
a.NewPassword(newpassword)
|
||||||
|
|
||||||
|
basedboperat.Update(a, []string{"password", "salt"}, "id = ?", a.ID)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *User) Update() error {
|
||||||
|
var findModel User
|
||||||
|
basedboperat.Get(&findModel, nil, "id = ?", a.ID)
|
||||||
|
if findModel.ID <= 0 {
|
||||||
|
return errors.New("记录不存在")
|
||||||
|
}
|
||||||
|
a.DeleteRelation()
|
||||||
|
_, err := a.CreateRelation()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
basedboperat.Update(a, []string{"nickname", "email"}, "id = ?", a.ID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *User) Delete() (int64, error) {
|
||||||
|
var findModel User
|
||||||
|
basedboperat.Get(&findModel, nil, "id = ?", a.ID)
|
||||||
|
if !findModel.CanDelete {
|
||||||
|
return 0, errors.New("无法删除系统用户")
|
||||||
|
}
|
||||||
|
a.DeleteRelation()
|
||||||
|
return basedboperat.Delete(a, a.ID, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除关联数据
|
||||||
|
func (a *User) DeleteRelation() {
|
||||||
|
if a.ID == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建关联数据
|
||||||
|
func (a *User) CreateRelation() (int64, error) {
|
||||||
|
if a.ID == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
var rowsAffected int64
|
||||||
|
|
||||||
|
return rowsAffected, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *User) AfterQuery() {
|
||||||
|
if a.ID == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,227 @@
|
|||||||
|
package usercenter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/towgo/towgo/dao/basedboperat"
|
||||||
|
"github.com/towgo/towgo/lib/system"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 缓存有效期
|
||||||
|
var memCacheTimer int64 = 60 * 10
|
||||||
|
|
||||||
|
// token有效期 秒单位计算
|
||||||
|
var expirationLimit int64 = 86400 * 20
|
||||||
|
|
||||||
|
var autoClearLimit int64 = 60 * 10 //10分钟清理一次过期的token
|
||||||
|
|
||||||
|
// var expirationLimit int64 = 60
|
||||||
|
var memCache *MemCache
|
||||||
|
|
||||||
|
// UserToken结构体
|
||||||
|
func (UserToken) TableName() string {
|
||||||
|
return _tableHead + "users_token"
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserToken struct {
|
||||||
|
TokenKey string
|
||||||
|
Uid int64
|
||||||
|
Payload any `gorm:"-" xorm:"-"`
|
||||||
|
Expiration int64
|
||||||
|
UpdatedAt int64
|
||||||
|
CreatedAt int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitTokenTask() {
|
||||||
|
memCache = &MemCache{}
|
||||||
|
autoTimeToClear()
|
||||||
|
}
|
||||||
|
|
||||||
|
type MemCache struct {
|
||||||
|
timers sync.Map
|
||||||
|
cacheObject sync.Map
|
||||||
|
cancels sync.Map
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mc *MemCache) CreateTimerToDelete(tokenKey string) {
|
||||||
|
timer := time.NewTimer(time.Second * time.Duration(memCacheTimer))
|
||||||
|
mc.timers.Store(tokenKey, timer)
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
mc.cancels.Store(tokenKey, cancel)
|
||||||
|
go mc.DeleteWhenTimeOut(ctx, tokenKey, timer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mc *MemCache) DeleteWhenTimeOut(ctx context.Context, tokenKey string, timer *time.Timer) {
|
||||||
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
mc.timers.Delete(tokenKey)
|
||||||
|
mc.cacheObject.Delete(tokenKey)
|
||||||
|
mc.cancels.Delete(tokenKey)
|
||||||
|
return
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mc *MemCache) ResetTimer(tokenKey string) {
|
||||||
|
timerInterface, ok := mc.timers.Load(tokenKey)
|
||||||
|
if ok {
|
||||||
|
timer := timerInterface.(*time.Timer)
|
||||||
|
timer.Reset(time.Second * time.Duration(memCacheTimer))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mc *MemCache) Add(tokenKey string, value any) {
|
||||||
|
mc.cacheObject.Store(tokenKey, value)
|
||||||
|
mc.CreateTimerToDelete(tokenKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mc *MemCache) Del(tokenKey string) {
|
||||||
|
timerInterface, ok := mc.timers.Load(tokenKey)
|
||||||
|
if ok {
|
||||||
|
timer := timerInterface.(*time.Timer)
|
||||||
|
timer.Stop() //关闭定时器
|
||||||
|
cancel_any, isLoaded := mc.cancels.LoadAndDelete(tokenKey) //关闭定时器线程
|
||||||
|
if isLoaded {
|
||||||
|
cancel := cancel_any.(context.CancelFunc)
|
||||||
|
if cancel != nil {
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mc.timers.Delete(tokenKey) //清除定时器委托
|
||||||
|
}
|
||||||
|
mc.cacheObject.Delete(tokenKey) //清除内存
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mc *MemCache) Get(tokenKey string) (any, bool) {
|
||||||
|
return mc.cacheObject.Load(tokenKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自动清理过期token定时器
|
||||||
|
func autoTimeToClear() {
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
err := recover()
|
||||||
|
if err != nil {
|
||||||
|
log.Print(err)
|
||||||
|
}
|
||||||
|
autoTimeToClear()
|
||||||
|
}()
|
||||||
|
var userToken UserToken
|
||||||
|
for {
|
||||||
|
time.Sleep(time.Second * time.Duration(autoClearLimit))
|
||||||
|
basedboperat.SqlExec("delete from "+userToken.TableName()+" where expiration < ?", time.Now().Unix())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *UserToken) NewTokenGUID(salt string) {
|
||||||
|
guid := system.GetGUID().Hex()
|
||||||
|
saltEncode := system.MD5(salt)
|
||||||
|
tokenCode := system.MD5(guid + saltEncode)
|
||||||
|
t.TokenKey = tokenCode
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回一个唯一标识的token令牌
|
||||||
|
func (t *UserToken) String() string {
|
||||||
|
return t.TokenKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// token是否有效 检查有效期
|
||||||
|
// 有效返回true
|
||||||
|
// 无效返回false
|
||||||
|
func (t *UserToken) Valid() bool {
|
||||||
|
return time.Now().Unix() < t.Expiration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *UserToken) Check(tokenKey string) bool {
|
||||||
|
return tokenKey == t.TokenKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新token有效期
|
||||||
|
func (t *UserToken) Update(expiration int64) {
|
||||||
|
if expiration > 0 {
|
||||||
|
t.Expiration = time.Now().Unix() + expiration
|
||||||
|
} else {
|
||||||
|
t.Expiration = time.Now().Unix() + expirationLimit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新建一个token
|
||||||
|
func NewToken(user *User) *UserToken {
|
||||||
|
timenow := time.Now().Unix()
|
||||||
|
token := &UserToken{
|
||||||
|
CreatedAt: timenow,
|
||||||
|
Uid: user.ID,
|
||||||
|
Payload: user,
|
||||||
|
Expiration: timenow + expirationLimit,
|
||||||
|
}
|
||||||
|
user.Token = token.TokenKey
|
||||||
|
token.NewTokenGUID(user.Salt)
|
||||||
|
basedboperat.Create(token)
|
||||||
|
memCache.Add(token.TokenKey, token)
|
||||||
|
return token
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetToken(tokenKey string) (*UserToken, error) {
|
||||||
|
var userToken *UserToken = &UserToken{}
|
||||||
|
|
||||||
|
//缓存查询
|
||||||
|
userTokenInterface, ok := memCache.Get(tokenKey)
|
||||||
|
if ok {
|
||||||
|
//缓存命中
|
||||||
|
userToken = userTokenInterface.(*UserToken)
|
||||||
|
//缓存过期 清理
|
||||||
|
if !userToken.Valid() {
|
||||||
|
memCache.Del(tokenKey)
|
||||||
|
return nil, errors.New("token过期(登录失效,请重新登录)")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//数据库查询
|
||||||
|
|
||||||
|
//查询持久化数据
|
||||||
|
err := basedboperat.Get(userToken, nil, "token_key = ?", tokenKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if userToken.Uid == 0 {
|
||||||
|
return nil, errors.New("token不存在(登录失效,请重新登录)") //数据不存在
|
||||||
|
}
|
||||||
|
|
||||||
|
//token过期
|
||||||
|
if !userToken.Valid() {
|
||||||
|
return nil, errors.New("token过期(登录失效,请重新登录)")
|
||||||
|
}
|
||||||
|
|
||||||
|
//查询token关联的用户
|
||||||
|
var user *User = &User{}
|
||||||
|
basedboperat.Get(user, nil, "id = ?", userToken.Uid)
|
||||||
|
if user.ID == 0 {
|
||||||
|
return nil, errors.New("token关联用户不存在(登录失效,请重新登录)") //用户不存在
|
||||||
|
}
|
||||||
|
|
||||||
|
//写入缓存
|
||||||
|
userToken.Payload = user
|
||||||
|
memCache.Add(userToken.TokenKey, userToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
return userToken, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteToken(tokenKey string) {
|
||||||
|
memCache.Del(tokenKey)
|
||||||
|
var userToken *UserToken = &UserToken{}
|
||||||
|
userToken.TokenKey = tokenKey
|
||||||
|
|
||||||
|
basedboperat.Delete(userToken, nil, "token_key = ?", tokenKey)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetExpiration(hour int64) {
|
||||||
|
expirationLimit = 3600 * hour
|
||||||
|
}
|
||||||
Loading…
Reference in new issue