系统登录和验证码开关
This commit is contained in:
@@ -3,12 +3,18 @@ package security
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"image/color"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"ems.agt/features/security/service"
|
||||
sysConfigService "ems.agt/features/sys_config/service"
|
||||
"ems.agt/lib/core/account"
|
||||
"ems.agt/lib/core/cache"
|
||||
"ems.agt/lib/core/conf"
|
||||
"ems.agt/lib/core/constants/cachekey"
|
||||
"ems.agt/lib/core/utils/ctx"
|
||||
"ems.agt/lib/core/vo/result"
|
||||
"ems.agt/lib/dborm"
|
||||
@@ -17,6 +23,8 @@ import (
|
||||
"ems.agt/lib/oauth"
|
||||
"ems.agt/lib/services"
|
||||
"ems.agt/restagent/config"
|
||||
"github.com/go-admin-team/go-admin-core/logger"
|
||||
"github.com/mojocn/base64Captcha"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -26,6 +34,14 @@ var (
|
||||
CustomUriOauthToken = config.UriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/token"
|
||||
CustomUriOauthHandshake = config.UriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/handshake"
|
||||
|
||||
// 系统登录
|
||||
UriLogin = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/login"
|
||||
CustomUriLogin = config.UriPrefix + "/securityManagement/{apiVersion}/login"
|
||||
|
||||
// 获取验证码
|
||||
UriCaptchaImage = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/captchaImage"
|
||||
CustomUriCaptchaImage = config.UriPrefix + "/securityManagement/{apiVersion}/captchaImage"
|
||||
|
||||
// 登录用户信息
|
||||
UriUserInfo = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/getUserInfo"
|
||||
CustomUriUserInfo = config.UriPrefix + "/securityManagement/{apiVersion}/getUserInfo"
|
||||
@@ -208,6 +224,163 @@ func HandshakeFromOMC(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// 系统登录
|
||||
//
|
||||
// POST /login
|
||||
func LoginOMC(w http.ResponseWriter, r *http.Request) {
|
||||
log.Info("LoginFromOMC processing... ")
|
||||
var body struct {
|
||||
Username string `json:"username" binding:"required"` // Username 用户名
|
||||
Password string `json:"password" binding:"required"` // Password 用户密码
|
||||
Code string `json:"code"` // Code 验证码
|
||||
UUID string `json:"uuid"` // UUID 验证码唯一标识
|
||||
}
|
||||
err := ctx.ShouldBindJSON(r, &body)
|
||||
if err != nil {
|
||||
log.Error("Invalid Json Format")
|
||||
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||
return
|
||||
}
|
||||
// response 400-5
|
||||
if body.Username == "" || body.Password == "" {
|
||||
log.Error("Wrong parameter value")
|
||||
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||
return
|
||||
}
|
||||
|
||||
// 校验验证码
|
||||
// 从数据库配置获取验证码开关 true开启,false关闭
|
||||
captchaEnabledStr := sysConfigService.NewServiceSysConfig.SelectConfigValueByKey("sys.account.captchaEnabled")
|
||||
captchaEnabled, err := strconv.ParseBool(captchaEnabledStr)
|
||||
if err != nil {
|
||||
captchaEnabled = false
|
||||
}
|
||||
if captchaEnabled {
|
||||
if body.Code == "" || body.UUID == "" {
|
||||
log.Error("Authentication failed, mismatch captcha")
|
||||
ctx.JSON(w, 400, result.CodeMsg(400, "验证码信息错误"))
|
||||
return
|
||||
}
|
||||
verifyKey := cachekey.CAPTCHA_CODE_KEY + body.UUID
|
||||
captcha, ok := cache.GetLocalTTL(verifyKey)
|
||||
if captcha == nil || !ok {
|
||||
log.Error("Authentication failed, captcha emtry")
|
||||
ctx.JSON(w, 400, result.CodeMsg(400, "验证码已失效"))
|
||||
return
|
||||
}
|
||||
cache.DeleteLocalTTL(verifyKey)
|
||||
if captcha.(string) != body.Code {
|
||||
log.Error("Authentication failed, not match captcha")
|
||||
ctx.JSON(w, 400, result.CodeMsg(400, "验证码错误"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
validUser, user, err := dborm.XormCheckLoginUser(body.Username, body.Password, config.GetYamlConfig().Auth.Crypt)
|
||||
if !validUser || err != nil {
|
||||
// response 400-4
|
||||
log.Error("Authentication failed, mismatch user or password")
|
||||
ctx.JSON(w, 400, result.CodeMsg(400, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
token := oauth.GenRandToken("omc") // Generate new token to session ID
|
||||
sourceAddr := r.RemoteAddr
|
||||
affected, err := dborm.XormInsertSession(body.Username, sourceAddr, token,
|
||||
config.GetExpiresFromConfig(), config.GetYamlConfig().Auth.Session)
|
||||
if err != nil {
|
||||
log.Error("Failed to XormInsertSession:", err)
|
||||
if affected == -1 {
|
||||
services.ResponseForbidden403MultiLoginNotAllowed(w)
|
||||
} else {
|
||||
services.ResponseBadRequest400IncorrectLogin(w)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if user != nil {
|
||||
// 缓存用户信息
|
||||
account.CacheLoginUser(user)
|
||||
ctx.JSON(w, 200, result.OkData(map[string]any{
|
||||
"accessToken": token,
|
||||
}))
|
||||
return
|
||||
}
|
||||
ctx.JSON(w, 200, result.Err(nil))
|
||||
}
|
||||
|
||||
// 获取验证码
|
||||
//
|
||||
// GET /captchaImage
|
||||
func CaptchaImage(w http.ResponseWriter, r *http.Request) {
|
||||
configService := sysConfigService.NewServiceSysConfig
|
||||
|
||||
// 从数据库配置获取验证码开关 true开启,false关闭
|
||||
captchaEnabledStr := configService.SelectConfigValueByKey("sys.account.captchaEnabled")
|
||||
captchaEnabled, err := strconv.ParseBool(captchaEnabledStr)
|
||||
if err != nil {
|
||||
captchaEnabled = false
|
||||
}
|
||||
if !captchaEnabled {
|
||||
ctx.JSON(w, 200, result.Ok(map[string]any{
|
||||
"captchaEnabled": captchaEnabled,
|
||||
}))
|
||||
return
|
||||
}
|
||||
|
||||
// 生成唯一标识
|
||||
verifyKey := ""
|
||||
data := map[string]any{
|
||||
"captchaEnabled": captchaEnabled,
|
||||
"uuid": "",
|
||||
"img": "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
|
||||
}
|
||||
|
||||
// char 字符验证
|
||||
driverCaptcha := &base64Captcha.DriverString{
|
||||
//Height png height in pixel.
|
||||
Height: 40,
|
||||
// Width Captcha png width in pixel.
|
||||
Width: 120,
|
||||
//NoiseCount text noise count.
|
||||
NoiseCount: 4,
|
||||
//Length random string length.
|
||||
Length: 4,
|
||||
//Source is a unicode which is the rand string from.
|
||||
Source: "023456789abcdefghjkmnprstuvwxyz",
|
||||
//ShowLineOptions := OptionShowHollowLine | OptionShowSlimeLine | OptionShowSineLine .
|
||||
ShowLineOptions: base64Captcha.OptionShowHollowLine,
|
||||
//BgColor captcha image background color (optional)
|
||||
BgColor: &color.RGBA{
|
||||
R: 250,
|
||||
G: 250,
|
||||
B: 250,
|
||||
A: 255, // 不透明
|
||||
},
|
||||
}
|
||||
// 验证码生成
|
||||
id, question, answer := driverCaptcha.GenerateIdQuestionAnswer()
|
||||
// 验证码表达式解析输出
|
||||
item, err := driverCaptcha.DrawCaptcha(question)
|
||||
if err != nil {
|
||||
logger.Infof("Generate Id Question Answer %s : %v", question, err)
|
||||
} else {
|
||||
data["uuid"] = id
|
||||
data["img"] = item.EncodeB64string()
|
||||
verifyKey = cachekey.CAPTCHA_CODE_KEY + id
|
||||
cache.SetLocalTTL(verifyKey, answer, 120*time.Second)
|
||||
}
|
||||
|
||||
// 本地开发下返回验证码结果,方便接口调试
|
||||
// text, ok := cache.GetLocalTTL(verifyKey)
|
||||
// if ok {
|
||||
// data["text"] = text.(string)
|
||||
// }
|
||||
|
||||
ctx.JSON(w, 200, result.Ok(data))
|
||||
}
|
||||
|
||||
// 登录用户信息
|
||||
func UserInfo(w http.ResponseWriter, r *http.Request) {
|
||||
loginUser, err := ctx.LoginUser(r)
|
||||
|
||||
5
go.mod
5
go.mod
@@ -59,6 +59,7 @@ require (
|
||||
github.com/go-redis/redis/v8 v8.11.5 // indirect
|
||||
github.com/go-redis/redis/v9 v9.0.0-rc.1 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
@@ -86,6 +87,7 @@ require (
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
||||
github.com/mojocn/base64Captcha v1.3.5
|
||||
github.com/nsqio/go-nsq v1.0.8 // indirect
|
||||
github.com/nyaruka/phonenumbers v1.0.55 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||
@@ -113,7 +115,8 @@ require (
|
||||
github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
golang.org/x/arch v0.3.0 // indirect
|
||||
golang.org/x/net v0.10.0 // indirect
|
||||
golang.org/x/image v0.5.0 // indirect
|
||||
golang.org/x/net v0.10.0
|
||||
golang.org/x/sys v0.11.0 // indirect
|
||||
golang.org/x/text v0.12.0 // indirect
|
||||
golang.org/x/tools v0.6.0 // indirect
|
||||
|
||||
5
go.sum
5
go.sum
@@ -203,6 +203,8 @@ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
@@ -486,6 +488,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||
github.com/mojocn/base64Captcha v1.3.5 h1:Qeilr7Ta6eDtG4S+tQuZ5+hO+QHbiGAJdi4PfoagaA0=
|
||||
github.com/mojocn/base64Captcha v1.3.5/go.mod h1:/tTTXn4WTpX9CfrmipqRytCpJ27Uw3G6I7NcP2WwcmY=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
|
||||
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
|
||||
@@ -748,6 +752,7 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI=
|
||||
golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4=
|
||||
|
||||
@@ -282,6 +282,14 @@ func init() {
|
||||
Register("POST", lm.ExtBackupDataUri, lm.ExtDatabaseBackupData, nil)
|
||||
Register("POST", lm.CustomExtBackupDataUri, lm.ExtDatabaseBackupData, nil)
|
||||
|
||||
// 系统登录
|
||||
Register("POST", security.UriLogin, security.LoginOMC, nil)
|
||||
Register("POST", security.CustomUriLogin, security.LoginOMC, nil)
|
||||
|
||||
// 获取验证码
|
||||
Register("GET", security.UriCaptchaImage, security.CaptchaImage, nil)
|
||||
Register("GET", security.CustomUriCaptchaImage, security.CaptchaImage, nil)
|
||||
|
||||
// 登录用户信息
|
||||
Register("GET", security.UriUserInfo, security.UserInfo, midware.Authorize(nil))
|
||||
Register("GET", security.CustomUriUserInfo, security.UserInfo, midware.Authorize(nil))
|
||||
|
||||
Reference in New Issue
Block a user