feat:add mobile login

This commit is contained in:
samwaf
2025-10-17 15:31:42 +08:00
parent a6039121c8
commit a4b76607de
6 changed files with 92 additions and 7 deletions

View File

@@ -101,13 +101,19 @@ func (w *WafLoginApi) LoginApi(c *gin.Context) {
// 密码正确,清除错误计数
global.GCACHE_WAFCACHE.Remove(cacheKey)
//如果存在旧的状态删除 相同帐号 只允许一个
allTokenInfo := wafTokenInfoService.GetAllTokenInfoByLoginAccount(req.LoginAccount)
// 获取登录类型
loginType := c.GetHeader("X-Login-Type")
if loginType == "" {
loginType = "web" // 默认为web类型
}
//如果存在旧的状态删除 相同帐号和登录类型 只允许一个
allTokenInfo := wafTokenInfoService.GetAllTokenInfoByLoginAccountAndType(req.LoginAccount, loginType)
if allTokenInfo != nil {
for i := 0; i < len(allTokenInfo); i++ {
oldTokenInfo := allTokenInfo[i]
if oldTokenInfo.Id != "" {
wafTokenInfoService.DelApiByAccount(oldTokenInfo.LoginAccount)
wafTokenInfoService.DelApiByAccountAndType(oldTokenInfo.LoginAccount, oldTokenInfo.LoginType)
global.GCACHE_WAFCACHE.Remove(enums.CACHE_TOKEN + oldTokenInfo.AccessToken)
}
}
@@ -121,7 +127,7 @@ func (w *WafLoginApi) LoginApi(c *gin.Context) {
//记录状态
accessToken := utils.Md5String(uuid.GenUUID())
tokenInfo := wafTokenInfoService.AddApiWithFingerprint(bean.LoginAccount, accessToken, c.ClientIP(), deviceFingerprint)
tokenInfo := wafTokenInfoService.AddApiWithFingerprintAndType(bean.LoginAccount, accessToken, c.ClientIP(), deviceFingerprint, loginType)
//令牌记录到cache里
global.GCACHE_WAFCACHE.SetWithTTl(enums.CACHE_TOKEN+accessToken, *tokenInfo, time.Duration(global.GCONFIG_RECORD_TOKEN_EXPIRE_MINTUTES)*time.Minute)
@@ -165,10 +171,20 @@ func (w *WafLoginApi) LoginOutApi(c *gin.Context) {
var req request.WafLoginOutReq
err := c.ShouldBind(&req)
if err == nil {
tokenStr := c.GetHeader("X-Token")
// 根据登录类型获取不同的token头部
loginType := c.GetHeader("X-Login-Type")
var tokenStr string
if loginType == "mobile" {
tokenStr = c.GetHeader("X-Mobile-Token")
} else {
tokenStr = c.GetHeader("X-Token")
}
bean := wafTokenInfoService.GetInfoByAccessToken(tokenStr)
if bean.Id != "" {
wafTokenInfoService.DelApi(bean.LoginAccount, bean.AccessToken)
global.GCACHE_WAFCACHE.Remove(enums.CACHE_TOKEN + bean.AccessToken)
response.OkWithDetailed("json", "注销成功"+tokenStr, c)
return
} else {

View File

@@ -25,12 +25,19 @@ func Auth() gin.HandlerFunc {
return func(c *gin.Context) {
// 获取请求头中 token实际是一个完整被签名过的 tokena complete, signed token
tokenStr := ""
loginType := c.GetHeader("X-Login-Type")
if c.Request.RequestURI == "/samwaf/ws" {
tokenStr = c.GetHeader("Sec-WebSocket-Protocol")
} else if strings.HasPrefix(c.Request.RequestURI, "/samwaf/waflog/attack/download") {
tokenStr = c.Query("X-Token")
} else {
tokenStr = c.GetHeader("X-Token")
// 根据登录类型获取不同的token头部
if loginType == "mobile" {
tokenStr = c.GetHeader("X-Mobile-Token")
} else {
tokenStr = c.GetHeader("X-Token")
}
}
if tokenStr == "" {
zlog.Debug("无token")

View File

@@ -1,6 +1,7 @@
package middleware
import (
"SamWaf/common/zlog"
"SamWaf/global"
"SamWaf/wafsec"
"bytes"
@@ -32,6 +33,14 @@ func SecApi() gin.HandlerFunc {
if err == nil {
c.Request.Body = io.NopCloser(bytes.NewBuffer(decryptBytes))
}
} else if c.Request.Header.Get("X-Login-Type") == "mobile" && c.Request.Header.Get("Content-Type") == "application/json" {
decryptBytes, err := wafsec.AesDecrypt(string(bodyBytes), global.GWAF_COMMUNICATION_KEY)
if err == nil {
c.Request.Body = io.NopCloser(bytes.NewBuffer(decryptBytes))
} else {
zlog.Debug("Decrypt error", err.Error())
}
}
c.Next()
}

View File

@@ -25,4 +25,5 @@ type TokenInfo struct {
LoginIp string `json:"login_ip"` //登录IP
AccessToken string `json:"access_token" crypto:"aes"` //访问码
DeviceFingerprint string `json:"device_fingerprint"` //设备指纹
LoginType string `json:"login_type"` //登录类型 web/mobile
}

View File

@@ -28,6 +28,7 @@ func (receiver *WafTokenInfoService) AddApi(loginAccount string, AccessToken str
LoginAccount: loginAccount,
AccessToken: AccessToken,
LoginIp: LoginIp,
LoginType: "web", // 默认为web类型
}
global.GWAF_LOCAL_DB.Create(bean)
mod := receiver.GetInfoByLoginAccount(loginAccount)
@@ -49,12 +50,35 @@ func (receiver *WafTokenInfoService) AddApiWithFingerprint(loginAccount string,
AccessToken: AccessToken,
LoginIp: LoginIp,
DeviceFingerprint: deviceFingerprint,
LoginType: "web", // 默认为web类型
}
global.GWAF_LOCAL_DB.Create(bean)
mod := receiver.GetInfoByLoginAccount(loginAccount)
return &mod
}
// AddApiWithFingerprintAndType 添加带指纹和登录类型的token信息
func (receiver *WafTokenInfoService) AddApiWithFingerprintAndType(loginAccount string, AccessToken string, LoginIp string, deviceFingerprint string, loginType string) *model.TokenInfo {
var bean = &model.TokenInfo{
BaseOrm: baseorm.BaseOrm{
Id: uuid.GenUUID(),
USER_CODE: global.GWAF_USER_CODE,
Tenant_ID: global.GWAF_TENANT_ID,
CREATE_TIME: customtype.JsonTime(time.Now()),
UPDATE_TIME: customtype.JsonTime(time.Now()),
},
LoginAccount: loginAccount,
AccessToken: AccessToken,
LoginIp: LoginIp,
DeviceFingerprint: deviceFingerprint,
LoginType: loginType,
}
global.GWAF_LOCAL_DB.Create(bean)
mod := receiver.GetInfoByLoginAccountAndType(loginAccount, loginType)
return &mod
}
func (receiver *WafTokenInfoService) CheckIsExistByLoginAccountApi(loginAccount string) error {
return global.GWAF_LOCAL_DB.First(&model.TokenInfo{}, "login_account = ? ", loginAccount).Error
}
@@ -90,6 +114,20 @@ func (receiver *WafTokenInfoService) GetAllTokenInfoByLoginAccount(loginAccount
return bean
}
// GetInfoByLoginAccountAndType 通过登录account和类型获取账号信息
func (receiver *WafTokenInfoService) GetInfoByLoginAccountAndType(loginAccount string, loginType string) model.TokenInfo {
var bean model.TokenInfo
global.GWAF_LOCAL_DB.Where("login_account=? AND login_type=? ", loginAccount, loginType).Limit(1).Find(&bean)
return bean
}
// GetAllTokenInfoByLoginAccountAndType 通过登录account和类型获取所有账号信息
func (receiver *WafTokenInfoService) GetAllTokenInfoByLoginAccountAndType(loginAccount string, loginType string) []model.TokenInfo {
var bean []model.TokenInfo
global.GWAF_LOCAL_DB.Where("login_account=? AND login_type=? ", loginAccount, loginType).Find(&bean)
return bean
}
/*
*
获取一个可用的token TODO 将来应该是一个
@@ -138,6 +176,20 @@ func (receiver *WafTokenInfoService) DelApiByAccount(loginAccount string) error
return err
}
/*
*
通过账号和登录类型删除关联状态
*/
func (receiver *WafTokenInfoService) DelApiByAccountAndType(loginAccount string, loginType string) error {
var bean model.TokenInfo
err := global.GWAF_LOCAL_DB.Where("login_account = ? AND login_type = ?", loginAccount, loginType).First(&bean).Error
if err != nil {
return err
}
err = global.GWAF_LOCAL_DB.Where("login_account = ? AND login_type = ?", loginAccount, loginType).Delete(model.TokenInfo{}).Error
return err
}
/*
* 检测所有的token是否过期没有过期就重新加载到cache
*/

View File

@@ -117,7 +117,7 @@ func (web *WafWebManager) cors() gin.HandlerFunc {
// 将该域添加到allow-origin中
c.Header("Access-Control-Allow-Origin", origin) //
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization,X-Token,Remote-Waf-User-Id,OPEN-X-Token")
c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization,X-Token,Remote-Waf-User-Id,OPEN-X-Token,X-Login-Type,X-Mobile-Token")
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
//允许客户端传递校验信息比如 cookie
c.Header("Access-Control-Allow-Credentials", "true")