:building:修改二次验证方式

This commit is contained in:
sunxiaolong
2024-01-01 15:40:43 +08:00
parent eb1e1ffe1e
commit 0fbf4602cc
12 changed files with 107 additions and 57 deletions

View File

@@ -20,7 +20,10 @@ func (c *TotpQuery) GenTotp() {
}
_ = c.ServeJSON()
return
}
newTotp, err := c.GetInt("newTotp")
if err != nil {
newTotp = 0
}
userInfo := user.GetUserInfoByUserID(userID)
@@ -33,7 +36,11 @@ func (c *TotpQuery) GenTotp() {
return
}
otp, err := mfa.GetOtp(userInfo.UserId, userInfo.Nick)
otpSecret := ""
if userInfo.OtpSecret != "" && newTotp == 0 {
otpSecret = userInfo.OtpSecret
}
otp, err := mfa.GetOtp(userInfo.UserId, userInfo.Nick, otpSecret, userInfo.OtpKey)
if err != nil {
c.Data["json"] = datas.BaseDataJSON{
Code: -1,
@@ -41,7 +48,6 @@ func (c *TotpQuery) GenTotp() {
}
_ = c.ServeJSON()
return
}
c.Data["json"] = datas.KeyDataJSON2{
@@ -58,8 +64,9 @@ func (c *TotpQuery) GenTotp() {
func (c *TotpQuery) SaveTotp() {
code := c.GetString("code")
secret := c.GetString("secret")
key := c.GetString("key")
if code == "" || secret == "" {
if code == "" || secret == "" || key == "" {
c.Data["json"] = datas.BaseDataJSON{
Code: -1,
Msg: "提交消息不准确",
@@ -67,7 +74,6 @@ func (c *TotpQuery) SaveTotp() {
_ = c.ServeJSON()
return
}
userID, ok := c.GetSession("userID").(string)
if !ok {
c.Data["json"] = datas.BaseDataJSON{
@@ -76,7 +82,6 @@ func (c *TotpQuery) SaveTotp() {
}
_ = c.ServeJSON()
return
}
userInfo := user.GetUserInfoByUserID(userID)
@@ -102,7 +107,7 @@ func (c *TotpQuery) SaveTotp() {
}
err2 := user.UpdateOtpByUserID(userInfo.UserId, secret)
err2 := user.UpdateOtpByUserID(userInfo.UserId, secret, key)
if err2 != nil {
c.Data["json"] = datas.BaseDataJSON{
Code: -1,

2
go.mod
View File

@@ -6,10 +6,12 @@ require (
github.com/beego/beego/v2 v2.0.2
github.com/go-sql-driver/mysql v1.6.0
github.com/gogf/gf v1.16.9
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/golang/protobuf v1.5.3 // indirect
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
github.com/rs/xid v1.2.1
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/xlzd/gotp v0.1.0
golang.org/x/exp v0.0.0-20190121172915-509febef88a4
google.golang.org/protobuf v1.32.0 // indirect
)

4
go.sum
View File

@@ -109,6 +109,7 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
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=
@@ -126,7 +127,6 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
@@ -405,6 +405,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4 h1:c2HOrn5iMezYjSlGPncknSEr/8x5LELb/ilJbXi9DEA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -554,7 +555,6 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=

View File

@@ -32,6 +32,7 @@ type UserInfo struct {
CreateTime string
UpdateTime string
OtpSecret string
OtpKey string
}
func GetUserInfoByUserID(userID string) UserInfo {
@@ -44,11 +45,11 @@ func GetUserInfoByUserID(userID string) UserInfo {
return userInfo
}
func UpdateOtpByUserID(userID, totpSecret string) error {
func UpdateOtpByUserID(userID, totpSecret, key string) error {
o := orm.NewOrm()
_, err := o.QueryTable(USERINFO).Exclude("status", "delete").
Filter("user_id", userID).
Update(orm.Params{"otp_secret": totpSecret})
Update(orm.Params{"otp_secret": totpSecret, "otp_key": key})
if err != nil {
logs.Error("更新totp失败", err)

View File

@@ -1,12 +1,3 @@
/***************************************************
** @Desc : generate login verify code image
** @Time : 2019/8/7 17:14
** @Author : yuebin
** @File : login_verify_code
** @Last Modified by : yuebin
** @Last Modified time: 2019/8/7 17:14
** @Software: GoLand
****************************************************/
package utils
import (

View File

@@ -1,12 +1,3 @@
/***************************************************
** @Desc : 获取一个md5的字符串
** @Time : 2019/8/9 16:06
** @Author : yuebin
** @File : md5
** @Last Modified by : yuebin
** @Last Modified time: 2019/8/9 16:06
** @Software: GoLand
****************************************************/
package utils
import (

View File

@@ -1,6 +1,7 @@
package mfa
import (
"boss/utils"
"bytes"
"encoding/base64"
"fmt"
@@ -17,13 +18,17 @@ const secretLength = 16
type Otp struct {
Secret string `json:"secret"`
QrImage string `json:"qrImage"`
Key string `json:"key"`
}
func GetOtp(userId, username string) (otp Otp, err error) {
secret := gotp.RandomSecret(secretLength)
func GetOtp(userId, username, secret, key string) (otp Otp, err error) {
if secret == "" {
secret = gotp.RandomSecret(secretLength)
key = utils.RandomString(6)
}
otp.Secret = secret
totp := gotp.NewDefaultTOTP(secret)
uri := totp.ProvisioningUri(userId, fmt.Sprintf("卡销平台 管理员 %s", username))
uri := totp.ProvisioningUri(userId, fmt.Sprintf("卡销平台 管理员 %s %s", username, key))
uri, err = url.PathUnescape(uri)
if err != nil {
return
@@ -34,6 +39,7 @@ func GetOtp(userId, username string) (otp Otp, err error) {
index := bytes.IndexByte(dist, 0)
baseImage := dist[0:index]
otp.QrImage = "data:image/png;base64," + string(baseImage)
otp.Key = key
return
}

11
utils/mfa/mfa_test.go Normal file
View File

@@ -0,0 +1,11 @@
package mfa
import (
"fmt"
"testing"
)
func TestGetOtp(t *testing.T) {
otp, _ := GetOtp("10086", "admin", "TT37BPUE3RJOT372X3ZNX5HM7Y")
fmt.Println(otp.QrImage)
}

16
utils/random.go Normal file
View File

@@ -0,0 +1,16 @@
package utils
import (
"golang.org/x/exp/rand"
"strings"
)
func RandomString(n int) string {
const charset = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
sb := strings.Builder{}
sb.Grow(n)
for i := 0; i < n; i++ {
sb.WriteByte(charset[rand.Intn(len(charset))])
}
return sb.String()
}

View File

@@ -1,12 +1,3 @@
/***************************************************
** @Desc : This file for ...
** @Time : 2019/10/26 11:08
** @Author : yuebin
** @File : sign_verify
** @Last Modified by : yuebin
** @Last Modified time: 2019/10/26 11:08
** @Software: GoLand
****************************************************/
package utils
func GetMD5Sign(params map[string]string, keys []string, paySecret string) string {

View File

@@ -193,18 +193,24 @@
<h4 class="modal-title" id="totpLabel">TOTP二次验证</h4>
</div>
<div class="modal-body">
<div class="row margin-top-20">
<div class="col-xs-5">
<label>请输入二次验证:
<input id="totp-value" type="text" name="">
</label>
<div class="totp-regeneration">
<div class="row">
当前标识:<span id="totp-key"></span>
</div>
<div class="row">
<button class="btn btn-warning totp-regeneration-btn" data-toggle="tooltip"
title="重新生成将导致此前的二次验证不可用,请谨慎生成">重新生成
</button>
</div>
</div>
<div class="row">
<div class="row margin-top-20 totp-body">
<div id="totp-img">
<img src="" alt="" srcset="">
<input value="" id="totp-secret" hidden>
</div>
<label>请输入二次验证:
<input id="totp-value" type="text" name="">
</label>
</div>
<div class="col-xs-4 color-red totp-new-error">
</div>
@@ -506,11 +512,11 @@
});
});
$(".logout").click(function () {
$(".logout").click(() => {
$.ajax({
url: "/logout",
success: function (res) {
if (res.Code == 200) {
if (res.Code === 200) {
window.parent.location = "/login.html";
} else {
alert("系统异常,退出失败!");
@@ -565,31 +571,51 @@
if (res.Code === 0) {
$("#totp-img img").attr("src", res.Data.qrImage);
$("#totp-secret").attr("value", res.Data.secret);
$("#totp-key").text(res.Data.key);
} else {
alert(res.Msg)
}
},
})
});
$(".totp-regeneration-btn").click(() => {
$.ajax({
url: "/user/genTotp",
data: {
newTotp: 1,
},
method: "post",
success: (res) => {
if (res.Code === 0) {
$("#totp-img img").attr("src", res.Data.qrImage);
$("#totp-secret").attr("value", res.Data.secret);
$("#totp-key").text(res.Data.key);
} else {
alert(res.Msg)
}
},
})
})
$(".totp-save").click(function (event) {
// 获取secret
const secret = $("#totp-secret").val();
const code = $("#totp-value").val();
if (secret === "" || code === "") {
const key = $("#totp-key").text();
console.log(secret, code, key)
if (secret === "" || code === "" || key === "") {
setError(".totp-new-error", "信息填写不完整,需要重新填写");
return;
}
$.ajax({
url: "/user/saveTotp",
method: "post",
data: {
code: code,
secret: secret,
code,
secret,
key,
},
success: (res) => {
if (res.Code === 0) {
$("#totp-secret").val("");
$("#totp-value").val("");
$(".cancal-save").trigger('click');
alert("保存成功!")
@@ -603,5 +629,16 @@
})
})
</script>
<style>
.totp-regeneration {
float: right;
margin-right: 20px;
text-align: right;
}
.totp-body {
margin: 20px;
}
</style>
</html>

View File

@@ -1308,7 +1308,7 @@
"agentName": agentName
},
success: function (res) {
if (res.Code == 404) {
if (res.Code === 404) {
window.parent.location = "/login.html";
} else if (res.Code == -1) {
} else {
@@ -1512,7 +1512,6 @@
}
},
})
})
$("#pay-type").val("CARD_DH")