用户增加OTP认证设置

This commit is contained in:
刘祥超
2022-07-24 16:14:38 +08:00
parent 847d08a9bb
commit f3ac8a5cc5
9 changed files with 222 additions and 7 deletions

View File

@@ -5,6 +5,8 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
"github.com/xlzd/gotp"
)
type CreatePopupAction struct {
@@ -30,6 +32,9 @@ func (this *CreatePopupAction) RunPost(params struct {
Remark string
ClusterId int64
// OTP
OtpOn bool
Must *actions.Must
CSRF *actionutils.CSRF
}) {
@@ -91,7 +96,28 @@ func (this *CreatePopupAction) RunPost(params struct {
this.ErrorPage(err)
return
}
defer this.CreateLogInfo("创建用户 %d", createResp.UserId)
var userId = createResp.UserId
defer this.CreateLogInfo("创建用户 %d", userId)
// OTP
if params.OtpOn {
_, err = this.RPC().LoginRPC().UpdateLogin(this.AdminContext(), &pb.UpdateLoginRequest{Login: &pb.Login{
Id: 0,
Type: "otp",
ParamsJSON: maps.Map{
"secret": gotp.RandomSecret(16), // TODO 改成可以设置secret长度
}.AsJSON(),
IsOn: true,
AdminId: 0,
UserId: userId,
}})
if err != nil {
this.ErrorPage(err)
return
}
}
this.Success()
}

View File

@@ -20,6 +20,7 @@ func init() {
Post("/delete", new(DeleteAction)).
GetPost("/features", new(FeaturesAction)).
GetPost("/verifyPopup", new(VerifyPopupAction)).
Get("/otpQrcode", new(OtpQrcodeAction)).
// AccessKeys
Prefix("/users/accessKeys").

View File

@@ -0,0 +1,75 @@
package users
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
"github.com/skip2/go-qrcode"
"github.com/xlzd/gotp"
)
type OtpQrcodeAction struct {
actionutils.ParentAction
}
func (this *OtpQrcodeAction) Init() {
this.Nav("", "", "")
}
func (this *OtpQrcodeAction) RunGet(params struct {
UserId int64
}) {
loginResp, err := this.RPC().LoginRPC().FindEnabledLogin(this.AdminContext(), &pb.FindEnabledLoginRequest{
UserId: params.UserId,
Type: "otp",
})
if err != nil {
this.ErrorPage(err)
return
}
login := loginResp.Login
if login == nil || !login.IsOn {
this.NotFound("userLogin", params.UserId)
return
}
loginParams := maps.Map{}
err = json.Unmarshal(login.ParamsJSON, &loginParams)
if err != nil {
this.ErrorPage(err)
return
}
secret := loginParams.GetString("secret")
// 当前用户信息
userResp, err := this.RPC().UserRPC().FindEnabledUser(this.AdminContext(), &pb.FindEnabledUserRequest{UserId: params.UserId})
if err != nil {
this.ErrorPage(err)
return
}
var user = userResp.User
if user == nil {
this.NotFound("user", params.UserId)
return
}
uiConfig, err := configloaders.LoadAdminUIConfig()
if err != nil {
this.ErrorPage(err)
return
}
var productName = uiConfig.ProductName
if len(productName) == 0 {
productName = "GoEdge用户"
}
var url = gotp.NewDefaultTOTP(secret).ProvisioningUri(user.Username, productName)
data, err := qrcode.Encode(url, qrcode.Medium, 256)
if err != nil {
this.ErrorPage(err)
return
}
this.AddHeader("Content-Type", "image/png")
this.Write(data)
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
"github.com/xlzd/gotp"
)
type UpdateAction struct {
@@ -30,7 +31,7 @@ func (this *UpdateAction) RunGet(params struct {
this.ErrorPage(err)
return
}
user := userResp.User
var user = userResp.User
if user == nil {
this.NotFound("user", params.UserId)
return
@@ -42,7 +43,7 @@ func (this *UpdateAction) RunGet(params struct {
this.ErrorPage(err)
return
}
countAccessKeys := countAccessKeyResp.Count
var countAccessKeys = countAccessKeyResp.Count
// 是否有实名认证
hasNewIndividualIdentity, hasNewEnterpriseIdentity, identityTag, err := userutils.CheckUserIdentity(this.RPC(), this.AdminContext(), params.UserId)
@@ -51,6 +52,12 @@ func (this *UpdateAction) RunGet(params struct {
return
}
// OTP认证
var otpLoginIsOn = false
if user.OtpLogin != nil {
otpLoginIsOn = user.OtpLogin.IsOn
}
this.Data["user"] = maps.Map{
"id": user.Id,
"username": user.Username,
@@ -66,6 +73,9 @@ func (this *UpdateAction) RunGet(params struct {
"hasNewIndividualIdentity": hasNewIndividualIdentity,
"hasNewEnterpriseIdentity": hasNewEnterpriseIdentity,
"identityTag": identityTag,
// otp
"otpLoginIsOn": otpLoginIsOn,
}
this.Data["clusterId"] = 0
@@ -89,6 +99,9 @@ func (this *UpdateAction) RunPost(params struct {
IsOn bool
ClusterId int64
// OTP
OtpOn bool
Must *actions.Must
CSRF *actionutils.CSRF
}) {
@@ -152,5 +165,50 @@ func (this *UpdateAction) RunPost(params struct {
return
}
// 修改OTP
otpLoginResp, err := this.RPC().LoginRPC().FindEnabledLogin(this.AdminContext(), &pb.FindEnabledLoginRequest{
UserId: params.UserId,
Type: "otp",
})
if err != nil {
this.ErrorPage(err)
return
}
{
var otpLogin = otpLoginResp.Login
if params.OtpOn {
if otpLogin == nil {
otpLogin = &pb.Login{
Id: 0,
Type: "otp",
ParamsJSON: maps.Map{
"secret": gotp.RandomSecret(16), // TODO 改成可以设置secret长度
}.AsJSON(),
IsOn: true,
UserId: params.UserId,
}
} else {
// 如果已经有了,就覆盖,这样可以保留既有的参数
otpLogin.IsOn = true
}
_, err = this.RPC().LoginRPC().UpdateLogin(this.AdminContext(), &pb.UpdateLoginRequest{Login: otpLogin})
if err != nil {
this.ErrorPage(err)
return
}
} else {
_, err = this.RPC().LoginRPC().UpdateLogin(this.AdminContext(), &pb.UpdateLoginRequest{Login: &pb.Login{
Type: "otp",
IsOn: false,
UserId: params.UserId,
}})
if err != nil {
this.ErrorPage(err)
return
}
}
}
this.Success()
}

View File

@@ -1,6 +1,7 @@
package users
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/users/userutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
@@ -76,6 +77,21 @@ func (this *UserAction) RunGet(params struct {
return
}
// OTP
this.Data["otp"] = nil
if user.OtpLogin != nil && user.OtpLogin.IsOn {
loginParams := maps.Map{}
err = json.Unmarshal(user.OtpLogin.ParamsJSON, &loginParams)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["otp"] = maps.Map{
"isOn": true,
"params": loginParams,
}
}
this.Data["user"] = maps.Map{
"id": user.Id,
"username": user.Username,