ZZH-wl 3 tahun lalu
induk
melakukan
87aa9bf32d

+ 521 - 0
opms_admin/app/common/gtoken/gtoken.go

@@ -0,0 +1,521 @@
+package gtoken
+
+import (
+	"strings"
+
+	"dashoo.cn/micro_libary/utils"
+	"github.com/gogf/gf/crypto/gaes"
+	"github.com/gogf/gf/crypto/gmd5"
+	"github.com/gogf/gf/encoding/gbase64"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/net/ghttp"
+	"github.com/gogf/gf/os/glog"
+	"github.com/gogf/gf/os/gtime"
+	"github.com/gogf/gf/text/gstr"
+	"github.com/gogf/gf/util/gconv"
+	"github.com/gogf/gf/util/grand"
+)
+
+const (
+	CacheModeCache = 1
+	CacheModeRedis = 2
+)
+
+// GfToken gtoken结构体
+type GfToken struct {
+	// 缓存模式 1 gcache 2 gredis 默认1
+	CacheMode int8
+	// 缓存key
+	CacheKey string
+	// 超时时间 默认10天
+	Timeout int
+	// 缓存刷新时间 默认为超时时间的一半
+	MaxRefresh int
+	// Token分隔符
+	TokenDelimiter string
+	// Token加密key
+	EncryptKey []byte
+	// 认证失败中文提示
+	AuthFailMsg string
+	// 是否支持多端登录,默认false
+	MultiLogin bool
+
+	// 登录路径
+	LoginPath string
+	// 登录验证方法 return userKey 用户标识 如果userKey为空,结束执行
+	LoginBeforeFunc func(r *ghttp.Request) (string, interface{})
+	// 登录返回方法
+	LoginAfterFunc func(r *ghttp.Request, respData Resp)
+	// 登出地址
+	LogoutPath string
+	// 登出验证方法 return true 继续执行,否则结束执行
+	LogoutBeforeFunc func(r *ghttp.Request) bool
+	// 登出返回方法
+	LogoutAfterFunc func(r *ghttp.Request, respData Resp)
+
+	// 拦截地址
+	AuthPaths g.SliceStr
+	// 认证验证方法 return true 继续执行,否则结束执行
+	AuthBeforeFunc func(r *ghttp.Request) bool
+	// 认证返回方法
+	AuthAfterFunc func(r *ghttp.Request, respData Resp)
+}
+
+// Init 初始化
+func (m *GfToken) Init() bool {
+	if m.CacheMode == 0 {
+		m.CacheMode = CacheModeCache
+	}
+
+	if m.CacheKey == "" {
+		m.CacheKey = "GToken:"
+	}
+
+	if m.Timeout == 0 {
+		m.Timeout = 10 * 24 * 60 * 60 * 1000
+	}
+
+	if m.MaxRefresh == 0 {
+		m.MaxRefresh = m.Timeout / 2
+	}
+
+	if m.TokenDelimiter == "" {
+		m.TokenDelimiter = "_"
+	}
+
+	if len(m.EncryptKey) == 0 {
+		m.EncryptKey = []byte("12345678912345678912345678912345")
+	}
+
+	if m.AuthFailMsg == "" {
+		m.AuthFailMsg = "请求错误或登录超时"
+	}
+
+	//if m.LoginAfterFunc == nil {
+	//	m.LoginAfterFunc = func(r *ghttp.Request, respData Resp) {
+	//		if !respData.Success() {
+	//			r.Response.WriteJson(respData)
+	//		} else {
+	//			r.Response.WriteJson(Succ(g.Map{
+	//				"token": respData.GetString("token"),
+	//			}))
+	//		}
+	//	}
+	//}
+	//
+	//if m.LogoutBeforeFunc == nil {
+	//	m.LogoutBeforeFunc = func(r *ghttp.Request) bool {
+	//		return true
+	//	}
+	//}
+	//
+	//if m.LogoutAfterFunc == nil {
+	//	m.LogoutAfterFunc = func(r *ghttp.Request, respData Resp) {
+	//		if respData.Success() {
+	//			r.Response.WriteJson(Succ("Logout success"))
+	//		} else {
+	//			r.Response.WriteJson(respData)
+	//		}
+	//	}
+	//}
+	//
+	//if m.AuthBeforeFunc == nil {
+	//	m.AuthBeforeFunc = func(r *ghttp.Request) bool {
+	//		// 静态页面不拦截
+	//		if r.IsFileRequest() {
+	//			return false
+	//		}
+	//
+	//		return true
+	//	}
+	//}
+	//if m.AuthAfterFunc == nil {
+	//	m.AuthAfterFunc = func(r *ghttp.Request, respData Resp) {
+	//		if respData.Success() {
+	//			r.Middleware.Next()
+	//		} else {
+	//			var params map[string]interface{}
+	//			if r.Method == "GET" {
+	//				params = r.GetMap()
+	//			} else if r.Method == "POST" {
+	//				params = r.GetMap()
+	//			} else {
+	//				r.Response.Writeln("Request Method is ERROR! ")
+	//				return
+	//			}
+	//
+	//			no := gconv.String(gtime.TimestampMilli())
+	//
+	//			glog.Info(fmt.Sprintf("[AUTH_%s][url:%s][params:%s][data:%s]",
+	//				no, r.URL.Path, params, respData.Json()))
+	//			respData.Msg = m.AuthFailMsg
+	//			r.Response.WriteJson(respData)
+	//			r.ExitAll()
+	//		}
+	//	}
+	//}
+
+	return true
+}
+
+// Start 启动
+func (m *GfToken) Start() bool {
+	if !m.Init() {
+		return false
+	}
+	glog.Info("[GToken][params:" + m.String() + "]start... ")
+
+	//s := g.Server()
+
+	// 缓存模式
+	if m.CacheMode > CacheModeRedis {
+		glog.Error("[GToken]CacheMode set error")
+		return false
+	}
+
+	// 认证拦截器
+	//if m.AuthPaths == nil {
+	//	glog.Error("[GToken]HookPathList not set")
+	//	return false
+	//}
+	//for _, authPath := range m.AuthPaths {
+	//	if strings.HasSuffix(authPath, "/*") {
+	//		s.BindMiddleware(authPath, m.AuthMiddleware)
+	//	} else {
+	//		s.BindMiddleware(authPath+"/*", m.AuthMiddleware)
+	//	}
+	//}
+
+	// 登录
+	//if m.LoginPath == "" || m.LoginBeforeFunc == nil {
+	//	glog.Error("[GToken]LoginPath or LoginBeforeFunc not set")
+	//	return false
+	//}
+	//s.BindHandler(m.LoginPath, m.Login)
+
+	// 登出
+	//if m.LogoutPath == "" {
+	//	glog.Error("[GToken]LogoutPath or LogoutFunc not set")
+	//	return false
+	//}
+	//s.BindHandler(m.LogoutPath, m.Logout)
+
+	return true
+}
+
+// Start 结束
+func (m *GfToken) Stop() bool {
+	glog.Info("[GToken]stop. ")
+	return true
+}
+
+// GetTokenData 通过token获取对象
+func (m *GfToken) GetTokenData(r *ghttp.Request) Resp {
+	respData := m.getRequestToken(r)
+	if respData.Success() {
+		// 验证token
+		respData = m.validToken(respData.DataString())
+	}
+
+	return respData
+}
+
+// Login 登录
+func (m *GfToken) Login(r *ghttp.Request) {
+	userKey, data := m.LoginBeforeFunc(r)
+	if userKey == "" {
+		glog.Error("[GToken]Login userKey is empty")
+		return
+	}
+
+	if m.MultiLogin {
+		// 支持多端重复登录,返回相同token
+		userCacheResp := m.getToken(userKey, "")
+		if userCacheResp.Success() {
+			respToken := m.EncryptToken(userKey, "", userCacheResp.GetString("uuid"))
+			m.LoginAfterFunc(r, respToken)
+			return
+		}
+	}
+
+	// 生成token
+	respToken := m.genToken(userKey, "", "", data)
+	m.LoginAfterFunc(r, respToken)
+
+}
+
+// Logout 登出
+func (m *GfToken) Logout(r *ghttp.Request) {
+	if m.LogoutBeforeFunc(r) {
+		// 获取请求token
+		respData := m.getRequestToken(r)
+		if respData.Success() {
+			// 删除token
+			m.removeToken(respData.DataString())
+		}
+
+		m.LogoutAfterFunc(r, respData)
+	}
+}
+
+// AuthMiddleware 认证拦截
+func (m *GfToken) AuthMiddleware(r *ghttp.Request) {
+	// 不需要认证,直接下一步
+	if !m.AuthBeforeFunc(r) {
+		r.Middleware.Next()
+		return
+	}
+
+	// 获取请求token
+	tokenResp := m.getRequestToken(r)
+	if tokenResp.Success() {
+		// 验证token
+		tokenResp = m.validToken(tokenResp.DataString())
+	}
+
+	m.AuthAfterFunc(r, tokenResp)
+
+}
+
+// getRequestToken 返回请求Token
+func (m *GfToken) getRequestToken(r *ghttp.Request) Resp {
+	authHeader := r.Header.Get("Authorization")
+	if authHeader != "" {
+		parts := strings.SplitN(authHeader, " ", 2)
+		if !(len(parts) == 2 && parts[0] == "Bearer") {
+			glog.Warning("[GToken]authHeader:" + authHeader + " get token key fail")
+			return Unauthorized("get token key fail", "")
+		} else if parts[1] == "" {
+			glog.Warning("[GToken]authHeader:" + authHeader + " get token fail")
+			return Unauthorized("get token fail", "")
+		}
+
+		return Succ(parts[1])
+	}
+
+	authHeader = r.GetString("token")
+	if authHeader == "" {
+		return Unauthorized("query token fail", "")
+	}
+	return Succ(authHeader)
+
+}
+
+// genToken 生成Token
+func (m *GfToken) genToken(tenant, userKey, uuid string, data interface{}) Resp {
+	token := m.EncryptToken(tenant, userKey, uuid)
+	if !token.Success() {
+		return token
+	}
+
+	cacheKey := m.CacheKey + tenant + userKey
+	userCache := g.Map{
+		"tenant":      tenant,
+		"userKey":     userKey,
+		"uuid":        token.GetString("uuid"),
+		"data":        data,
+		"createTime":  gtime.Now().Millisecond(),
+		"refreshTime": gtime.Now().Millisecond() + m.MaxRefresh,
+	}
+
+	cacheResp := m.setCache(cacheKey, userCache)
+	if !cacheResp.Success() {
+		return cacheResp
+	}
+
+	return token
+}
+
+// validToken 验证Token
+func (m *GfToken) validToken(token string) Resp {
+	if token == "" {
+		return Unauthorized("valid token empty", "")
+	}
+
+	decryptToken := m.DecryptToken(token)
+	if !decryptToken.Success() {
+		return decryptToken
+	}
+
+	userKey := decryptToken.GetString("userKey")
+	uuid := decryptToken.GetString("uuid")
+
+	userCacheResp := m.getToken(userKey, "")
+	if !userCacheResp.Success() {
+		return userCacheResp
+	}
+
+	if uuid != userCacheResp.GetString("uuid") {
+		glog.Error("[GToken]user auth error, decryptToken:" + decryptToken.Json() + " cacheValue:" + gconv.String(userCacheResp.Data))
+		return Unauthorized("user auth error", "")
+	}
+
+	return userCacheResp
+}
+
+// getToken 通过userKey获取Token
+func (m *GfToken) getToken(tenant, userKey string) Resp {
+	cacheKey := m.CacheKey + tenant + userKey
+
+	userCacheResp := m.getCache(cacheKey)
+	if !userCacheResp.Success() {
+		return userCacheResp
+	}
+	userCache := gconv.Map(userCacheResp.Data)
+
+	nowTime := gtime.Now().Millisecond()
+	refreshTime := userCache["refreshTime"]
+
+	// 需要进行缓存超时时间刷新
+	if gconv.Int64(refreshTime) == 0 || nowTime > gconv.Int(refreshTime) {
+		userCache["createTime"] = gtime.Now().Millisecond()
+		userCache["refreshTime"] = gtime.Now().Millisecond() + m.MaxRefresh
+		glog.Debug("[GToken]refreshToken:" + gconv.String(userCache))
+		return m.setCache(cacheKey, userCache)
+	}
+
+	return Succ(userCache)
+}
+
+// removeToken 删除Token
+func (m *GfToken) removeToken(token string) Resp {
+	decryptToken := m.DecryptToken(token)
+	if !decryptToken.Success() {
+		return decryptToken
+	}
+
+	cacheKey := m.CacheKey + decryptToken.GetString("userKey")
+	return m.removeCache(cacheKey)
+}
+
+// EncryptToken token加密方法
+func (m *GfToken) EncryptToken(tenant, userKey string, uuid string) Resp {
+	if userKey == "" {
+		return Fail("encrypt userKey empty")
+	}
+	if tenant == "" {
+		return Fail("encrypt tenant empty")
+	}
+	if uuid == "" {
+		// 重新生成uuid
+		newUuid, err := gmd5.Encrypt(grand.Str(utils.LetterDigits, 10))
+		if err != nil {
+			glog.Error("[GToken]uuid error", err)
+			return Error("uuid error")
+		}
+		uuid = newUuid
+	}
+
+	tokenStr := tenant + m.TokenDelimiter + userKey + m.TokenDelimiter + uuid
+	token, err := gaes.Encrypt([]byte(tokenStr), m.EncryptKey)
+	if err != nil {
+		glog.Error("[GToken]encrypt error", err)
+		return Error("encrypt error")
+	}
+	return Succ(g.Map{
+		"userKey": userKey,
+		"tenant":  tenant,
+		"uuid":    uuid,
+		"token":   string(gbase64.Encode(token)),
+	})
+}
+
+// DecryptToken token解密方法
+func (m *GfToken) DecryptToken(token string) Resp {
+	if token == "" {
+		return Fail("decrypt token empty")
+	}
+
+	token64, err := gbase64.Decode([]byte(token))
+	if err != nil {
+		glog.Error("[GToken]decode error", err)
+		return Error("decode error")
+	}
+
+	decryptToken, err2 := gaes.Decrypt([]byte(token64), m.EncryptKey)
+	if err2 != nil {
+		glog.Error("[GToken]decrypt error", err2)
+		return Error("decrypt error")
+	}
+	tokenArray := gstr.Split(string(decryptToken), m.TokenDelimiter)
+	if len(tokenArray) < 2 {
+		glog.Error("[GToken]token len error")
+		return Error("token len error")
+	}
+
+	return Succ(g.Map{
+		"tenant":  tokenArray[0],
+		"userKey": tokenArray[1],
+		"uuid":    tokenArray[2],
+	})
+}
+
+// String token解密方法
+func (m *GfToken) String() string {
+	return gconv.String(g.Map{
+		// 缓存模式 1 gcache 2 gredis 默认1
+		"CacheMode":      m.CacheMode,
+		"CacheKey":       m.CacheKey,
+		"Timeout":        m.Timeout,
+		"TokenDelimiter": m.TokenDelimiter,
+		"EncryptKey":     string(m.EncryptKey),
+		"LoginPath":      m.LoginPath,
+		"LogoutPath":     m.LogoutPath,
+		"AuthPaths":      gconv.String(m.AuthPaths),
+	})
+}
+
+// 微服务改造新增函数
+// 登录验证后获取或生成Token
+func (m *GfToken) GetOrGenToken(tenant, userKey, uuid string, data interface{}) Resp {
+	if m.MultiLogin {
+		// 支持多端重复登录,返回相同token
+		userCacheResp := m.getToken(tenant, userKey)
+		if userCacheResp.Success() {
+			respToken := m.EncryptToken(tenant, userKey, userCacheResp.GetString("uuid"))
+			return respToken
+		}
+	}
+	// 生成token
+	respToken := m.genToken(tenant, userKey, uuid, data)
+	return respToken
+}
+
+// removeToken 删除Token
+func (m *GfToken) RemoveToken(token string) Resp {
+	decryptToken := m.DecryptToken(token)
+	if !decryptToken.Success() {
+		return decryptToken
+	}
+
+	cacheKey := m.CacheKey + decryptToken.GetString("tenant") + decryptToken.GetString("userKey")
+	return m.removeCache(cacheKey)
+}
+
+// validToken 验证Token
+func (m *GfToken) ValidToken(token string) Resp {
+	if token == "" {
+		return Unauthorized("valid token empty", "")
+	}
+
+	decryptToken := m.DecryptToken(token)
+	if !decryptToken.Success() {
+		return decryptToken
+	}
+
+	userKey := decryptToken.GetString("userKey")
+	uuid := decryptToken.GetString("uuid")
+	tenant := decryptToken.GetString("tenant")
+
+	userCacheResp := m.getToken(tenant, userKey)
+	if !userCacheResp.Success() {
+		return userCacheResp
+	}
+
+	if uuid != userCacheResp.GetString("uuid") {
+		glog.Error("[GToken]user auth error, decryptToken:" + decryptToken.Json() + " cacheValue:" + gconv.String(userCacheResp.Data))
+		return Unauthorized("user auth error", "")
+	}
+
+	return userCacheResp
+}

+ 84 - 0
opms_admin/app/common/gtoken/gtoken_cache.go

@@ -0,0 +1,84 @@
+package gtoken
+
+import (
+	"github.com/gogf/gf/encoding/gjson"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/os/gcache"
+	"github.com/gogf/gf/os/glog"
+	"github.com/gogf/gf/util/gconv"
+	"time"
+)
+
+// setCache 设置缓存
+func (m *GfToken) setCache(cacheKey string, userCache g.Map) Resp {
+	switch m.CacheMode {
+	case CacheModeCache:
+		gcache.Set(cacheKey, userCache, gconv.Duration(m.Timeout)*time.Millisecond)
+	case CacheModeRedis:
+		cacheValueJson, err1 := gjson.Encode(userCache)
+		if err1 != nil {
+			glog.Error("[GToken]cache json encode error", err1)
+			return Error("cache json encode error")
+		}
+		_, err := g.Redis().Do("SETEX", cacheKey, m.Timeout, cacheValueJson)
+		if err != nil {
+			glog.Error("[GToken]cache set error", err)
+			return Error("cache set error")
+		}
+	default:
+		return Error("cache model error")
+	}
+
+	return Succ(userCache)
+}
+
+// getCache 获取缓存
+func (m *GfToken) getCache(cacheKey string) Resp {
+	var userCache g.Map
+	switch m.CacheMode {
+	case CacheModeCache:
+		userCacheValue, _ := gcache.Get(cacheKey)
+		if userCacheValue == nil {
+			return Unauthorized("login timeout or not login", "")
+		}
+		userCache = gconv.Map(userCacheValue)
+	case CacheModeRedis:
+		userCacheJson, err := g.Redis().Do("GET", cacheKey)
+		if err != nil {
+			glog.Error("[GToken]cache get error", err)
+			return Error("cache get error")
+		}
+		if userCacheJson == nil {
+			return Unauthorized("login timeout or not login", "")
+		}
+
+		err = gjson.DecodeTo(userCacheJson, &userCache)
+		if err != nil {
+			glog.Error("[GToken]cache get json error", err)
+			return Error("cache get json error")
+		}
+	default:
+		return Error("cache model error")
+	}
+
+	return Succ(userCache)
+}
+
+// removeCache 删除缓存
+func (m *GfToken) removeCache(cacheKey string) Resp {
+	switch m.CacheMode {
+	case CacheModeCache:
+		gcache.Remove(cacheKey)
+	case CacheModeRedis:
+		var err error
+		_, err = g.Redis().Do("DEL", cacheKey)
+		if err != nil {
+			glog.Error("[GToken]cache remove error", err)
+			return Error("cache remove error")
+		}
+	default:
+		return Error("cache model error")
+	}
+
+	return Succ("")
+}

+ 92 - 0
opms_admin/app/common/gtoken/gtoken_resp.go

@@ -0,0 +1,92 @@
+package gtoken
+
+import (
+	"encoding/json"
+	"github.com/gogf/gf/util/gconv"
+)
+
+const (
+	SUCCESS      = 0
+	FAIL         = -1
+	ERROR        = -99
+	UNAUTHORIZED = -401
+	//配置
+	TypeConfig = 1
+	//  字典
+	TypeDict = 2
+)
+
+type Resp struct {
+	Code int         `json:"code"`
+	Msg  string      `json:"msg"`
+	Data interface{} `json:"data"`
+}
+
+// 获取Data值转字符串
+func (resp Resp) Success() bool {
+	return resp.Code == SUCCESS
+}
+
+// 获取Data转字符串
+func (resp Resp) DataString() string {
+	return gconv.String(resp.Data)
+}
+
+// 获取Data转Int
+func (resp Resp) DataInt() int {
+	return gconv.Int(resp.Data)
+}
+
+// 获取Data值转字符串
+func (resp Resp) GetString(key string) string {
+	return gconv.String(resp.Get(key))
+}
+
+// 获取Data值转Int
+func (resp Resp) GetInt(key string) int {
+	return gconv.Int(resp.Get(key))
+}
+
+// 获取Data值
+func (resp Resp) Get(key string) interface{} {
+	m := gconv.Map(resp.Data)
+	if m == nil {
+		return ""
+	}
+	return m[key]
+}
+
+func (resp Resp) Json() string {
+	str, _ := json.Marshal(resp)
+	return string(str)
+}
+
+// 成功
+func Succ(data interface{}) Resp {
+	return Resp{SUCCESS, "success", data}
+}
+
+// 失败
+func Fail(msg string) Resp {
+	return Resp{FAIL, msg, ""}
+}
+
+// 失败设置Data
+func FailData(msg string, data interface{}) Resp {
+	return Resp{FAIL, msg, data}
+}
+
+// 错误
+func Error(msg string) Resp {
+	return Resp{ERROR, msg, ""}
+}
+
+// 错误设置Data
+func ErrorData(msg string, data interface{}) Resp {
+	return Resp{ERROR, msg, data}
+}
+
+// 认证失败
+func Unauthorized(msg string, data interface{}) Resp {
+	return Resp{UNAUTHORIZED, msg, data}
+}

+ 74 - 0
opms_admin/app/common/gtoken/gtoken_test.go

@@ -0,0 +1,74 @@
+package gtoken_test
+
+import (
+	"dashoo.cn/auth/gtoken"
+	"github.com/gogf/gf/encoding/gbase64"
+	"testing"
+)
+
+func TestEncryptDecryptToken(t *testing.T) {
+	t.Log("encrypt and decrypt token test ")
+	gfToken := gtoken.GfToken{}
+	gfToken.Init()
+
+	userKey := "123123"
+	token := gfToken.EncryptToken(userKey, "", "")
+	if !token.Success() {
+		t.Error(token.Json())
+	}
+	t.Log("data:", token.DataString())
+
+	t.Log("token", token.GetString("token"))
+	t.Logf("token:% X", token.Get("token"))
+	token2 := gfToken.DecryptToken(token.GetString("token"))
+	if !token2.Success() {
+		t.Error(token2.Json())
+	}
+	t.Log(token2.DataString())
+	if userKey != token2.GetString("userKey") {
+		t.Error("token decrypt userKey error")
+	}
+	if token.GetString("uuid") != token2.GetString("uuid") {
+		t.Error("token decrypt uuid error")
+	}
+
+	resp := gfToken.GetOrGenToken(userKey, "", "", nil)
+	t.Log("token3:", resp.DataString())
+	t.Log("token3", resp.GetString("token"))
+	t.Logf("token3:% X", resp.Get("token"))
+	token3 := gfToken.ValidToken(resp.GetString("token"))
+	t.Log("token3:", token3)
+
+	s := "ykzhYEEZne37xPXhQumjWITgmluQA179CcUlTYAr9onu1mgFSZWXqJyg2SOMdmEl"
+	s1 := gbase64.Encode([]byte(s))
+	t.Log(s1)
+	t.Log(string(s1))
+}
+
+func BenchmarkEncryptDecryptToken(b *testing.B) {
+	b.Log("encrypt and decrypt token test ")
+	gfToken := gtoken.GfToken{}
+	gfToken.Init()
+
+	userKey := "123123"
+	token := gfToken.EncryptToken(userKey, "", "")
+	if !token.Success() {
+		b.Error(token.Json())
+	}
+	b.Log(token.DataString())
+
+	for i := 0; i < b.N; i++ {
+		token2 := gfToken.DecryptToken(token.GetString("token"))
+		if !token2.Success() {
+			b.Error(token2.Json())
+		}
+		b.Log(token2.DataString())
+		if userKey != token2.GetString("userKey") {
+			b.Error("token decrypt userKey error")
+		}
+		if token.GetString("uuid") != token2.GetString("uuid") {
+			b.Error("token decrypt uuid error")
+		}
+	}
+
+}

+ 16 - 1
opms_admin/app/dao/sys_user.go

@@ -5,7 +5,11 @@
 package dao
 
 import (
+	"context"
 	"dashoo.cn/micro/app/dao/internal"
+	"dashoo.cn/micro/app/model"
+	"github.com/gogf/gf/errors/gerror"
+	"github.com/gogf/gf/frame/g"
 )
 
 // sysUserDao is the manager for logic model data accessing
@@ -33,4 +37,15 @@ func NewSysUserDao(tenant string) *SysUserDao {
 	}
 }
 
-// Fill with you ideas below.
+// Fill with you ideas below.
+
+// FindByUsername 通过用户名获取用户信息
+func (d *sysUserDao) FindByUsername(ctx context.Context, username string) (user *model.LoginUserRes, err error) {
+	user = &model.LoginUserRes{}
+	err = d.Ctx(ctx).Fields(user).Where(d.Columns.UserName, username).Scan(user)
+	if err != nil {
+		g.Log().Error(err)
+		err = gerror.New("获取用户信息失败")
+	}
+	return
+}

+ 127 - 0
opms_admin/app/handler/auth.go

@@ -0,0 +1,127 @@
+package handler
+
+import (
+	"context"
+	"dashoo.cn/common_definition/admin/user_def"
+	"dashoo.cn/common_definition/comm_def"
+	"dashoo.cn/micro/app/common/gtoken"
+	"dashoo.cn/opms_libary/micro_srv"
+	"github.com/gogf/gf/errors/gerror"
+
+	"github.com/gogf/gf/encoding/gjson"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/os/glog"
+	"github.com/gogf/gf/util/gconv"
+
+	"dashoo.cn/common_definition/auth"
+)
+
+type Auth struct{}
+
+var gfToken *gtoken.GfToken
+
+func init() {
+	// 启动gtoken
+	gfToken = &gtoken.GfToken{
+		Timeout:    24 * 60 * 60 * 1000, // 24小时
+		EncryptKey: []byte(g.Config().GetString("gtoken.encrypt-key")),
+		CacheMode:  g.Config().GetInt8("gtoken.cache-mode"),
+		MultiLogin: g.Config().GetBool("gtoken.multi-login"),
+	}
+	gfToken.Start()
+}
+
+// Login 用户登录验证
+func (e *Auth) Login(ctx context.Context, req *user_def.LoginReq, rsp *comm_def.CommonMsg) error {
+	// 获取租户码
+	tenant, err := micro_srv.GetTenant(ctx)
+	if err != nil {
+		return err
+	}
+	g.Log().Info("Received User.Login request @ " + tenant)
+	// 参数验证
+	if req.UserName == "" || req.Password == "" {
+		return NoParamsErr
+	}
+
+	service, err := user.NewService(tenant)
+	if err != nil {
+		g.Log().Error(err)
+		return gerror.New("系统异常,请重新尝试")
+	}
+
+	userInfo, err := service.Login(ctx, tenant, req.UserName, pridecrypt)
+
+	rsp.Data = userInfo
+	rsp.Code = code
+	rsp.Msg = msg
+	return nil
+}
+
+// LogOut 退出登录
+//func (e *Auth) LogOut(ctx context.Context, req interface{}, rsp *comm_def.CommonMsg) error {
+//	// 获取租户码
+//	tenant, err := micro_srv.GetTenant(ctx)
+//	if err != nil {
+//		return err
+//	}
+//	g.Log().Info("Received User.LogOut request @ " + tenant)
+//	token, err := micro_srv.GetToken(ctx)
+//	if err != nil {
+//		return err
+//	}
+//	if token == "" {
+//		return NoParamsErr
+//	}
+//	service, err := user.NewService(tenant)
+//	if err != nil {
+//		g.Log().Error(err)
+//		return gerror.New("系统异常,请重新尝试")
+//	}
+//	err = service.LogOut(ctx, token)
+//	_, err, code, msg := myerrors.CheckError(err)
+//	if err != nil {
+//		glog.Error(err)
+//		return err
+//	}
+//	rsp.Code = code
+//	rsp.Msg = msg
+//	return nil
+//}
+
+func (e *Auth) GetToken(ctx context.Context, req *auth.Request, rsp *auth.Response) (err error) {
+	glog.Info("Received Auth.GetToken request, UserKey:", req.UserKey, " @ ", req.Tenant)
+	// 获取Data,换成对象
+	var json interface{}
+	if req.Data != "" {
+		json, err = gjson.DecodeToJson(req.Data)
+		if err != nil {
+			return err
+		}
+	}
+	tokenResp := gfToken.GetOrGenToken(req.Tenant, req.UserKey, req.Uuid, json)
+	if err := gconv.Struct(tokenResp, rsp); err != nil {
+		return err
+	}
+	glog.Info(tokenResp.DataString())
+	return nil
+}
+
+func (e *Auth) RemoveToken(ctx context.Context, reqToken string, rsp *auth.Response) error {
+	glog.Info("Received Auth.RemoveToken request, token:", reqToken)
+	tokenResp := gfToken.RemoveToken(reqToken)
+	if err := gconv.Struct(tokenResp, rsp); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (e *Auth) ValidToken(ctx context.Context, reqToken string, rsp *auth.Response) error {
+	glog.Info("Received Auth.ValidToken request, token:", reqToken)
+	tokenResp := gfToken.ValidToken(reqToken)
+	if err := gconv.Struct(tokenResp, rsp); err != nil {
+		return err
+	}
+
+	return nil
+}

+ 12 - 1
opms_admin/app/model/sys_user.go

@@ -11,4 +11,15 @@ import (
 // SysUser is the golang structure for table sys_user.
 type SysUser internal.SysUser
 
-// Fill with you ideas below.
+// Fill with you ideas below.
+
+// LoginUserRes 登录返回
+type LoginUserRes struct {
+	Id           uint64 `orm:"id,primary"       json:"id"`           //
+	UserName     string `orm:"user_name,unique" json:"userName"`     // 用户名
+	UserNickname string `orm:"user_nickname"    json:"userNickname"` // 用户昵称
+	UserStatus   uint   `orm:"user_status"      json:"userStatus"`   // 用户状态;0:禁用,1:正常,2:未验证
+	IsAdmin      int    `orm:"is_admin"         json:"isAdmin"`      // 是否后台管理员 1 是  0   否
+	Avatar       string `orm:"avatar" json:"avatar"`                 //头像
+	DeptId       uint64 `orm:"dept_id"       json:"deptId"`          //部门id
+}

+ 1 - 1
opms_admin/config/config.toml

@@ -16,7 +16,7 @@
 [database]
     [[database.default]]
         Debug = true
-        link = "mysql:root:123456@tcp(127.0.0.1:3306)/crm"
+        link = "mysql:root:Dashoo#190801@tcp(127.0.0.1:3306)/dashoo_crm"
 
 [micro_srv]
     auth = "dashoo.labsop.auth-2.1"

+ 1 - 0
opms_admin/main.go

@@ -17,6 +17,7 @@ func main() {
 	// 创建总服务包
 	s := micro_srv.CreateAndInitService(basePath)
 	// 注册服务对象
+	s.RegisterName("Auth", new(handler.Auth), "")
 	s.RegisterName("Role", new(handler.RoleHandler), "")
 
 	// 注册文件处理Service对象