1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-01-19 08:19:15 +08:00

fix: 登陆接口增加安全入口校验 (#2199)

This commit is contained in:
ssongliu 2023-09-06 15:00:12 +08:00 committed by GitHub
parent 278fac6d80
commit df5a1b3e40
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 110 additions and 9 deletions

View File

@ -1,6 +1,8 @@
package v1 package v1
import ( import (
"encoding/base64"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper" "github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/app/dto" "github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/model" "github.com/1Panel-dev/1Panel/backend/app/model"
@ -20,6 +22,7 @@ type BaseApi struct{}
// @Param request body dto.Login true "request" // @Param request body dto.Login true "request"
// @Success 200 {object} dto.UserLoginInfo // @Success 200 {object} dto.UserLoginInfo
// @Router /auth/login [post] // @Router /auth/login [post]
// @Header 200 {string} EntranceCode "安全入口"
func (b *BaseApi) Login(c *gin.Context) { func (b *BaseApi) Login(c *gin.Context) {
var req dto.Login var req dto.Login
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@ -32,8 +35,13 @@ func (b *BaseApi) Login(c *gin.Context) {
return return
} }
} }
entranceItem := c.Request.Header.Get("EntranceCode")
var entrance []byte
if len(entranceItem) != 0 {
entrance, _ = base64.StdEncoding.DecodeString(entranceItem)
}
user, err := authService.Login(c, req) user, err := authService.Login(c, req, string(entrance))
go saveLoginLogs(c, err) go saveLoginLogs(c, err)
if err != nil { if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
@ -49,6 +57,7 @@ func (b *BaseApi) Login(c *gin.Context) {
// @Param request body dto.MFALogin true "request" // @Param request body dto.MFALogin true "request"
// @Success 200 {object} dto.UserLoginInfo // @Success 200 {object} dto.UserLoginInfo
// @Router /auth/mfalogin [post] // @Router /auth/mfalogin [post]
// @Header 200 {string} EntranceCode "安全入口"
func (b *BaseApi) MFALogin(c *gin.Context) { func (b *BaseApi) MFALogin(c *gin.Context) {
var req dto.MFALogin var req dto.MFALogin
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
@ -59,8 +68,13 @@ func (b *BaseApi) MFALogin(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return return
} }
entranceItem := c.Request.Header.Get("EntranceCode")
var entrance []byte
if len(entranceItem) != 0 {
entrance, _ = base64.StdEncoding.DecodeString(entranceItem)
}
user, err := authService.MFALogin(c, req) user, err := authService.MFALogin(c, req, string(entrance))
if err != nil { if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return return

View File

@ -4,6 +4,7 @@ import (
"strconv" "strconv"
"github.com/1Panel-dev/1Panel/backend/app/dto" "github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant" "github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global" "github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/encrypt" "github.com/1Panel-dev/1Panel/backend/utils/encrypt"
@ -19,16 +20,16 @@ type AuthService struct{}
type IAuthService interface { type IAuthService interface {
CheckIsSafety(code string) (string, error) CheckIsSafety(code string) (string, error)
VerifyCode(code string) (bool, error) VerifyCode(code string) (bool, error)
Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo, error) Login(c *gin.Context, info dto.Login, entrance string) (*dto.UserLoginInfo, error)
LogOut(c *gin.Context) error LogOut(c *gin.Context) error
MFALogin(c *gin.Context, info dto.MFALogin) (*dto.UserLoginInfo, error) MFALogin(c *gin.Context, info dto.MFALogin, entrance string) (*dto.UserLoginInfo, error)
} }
func NewIAuthService() IAuthService { func NewIAuthService() IAuthService {
return &AuthService{} return &AuthService{}
} }
func (u *AuthService) Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo, error) { func (u *AuthService) Login(c *gin.Context, info dto.Login, entrance string) (*dto.UserLoginInfo, error) {
nameSetting, err := settingRepo.Get(settingRepo.WithByKey("UserName")) nameSetting, err := settingRepo.Get(settingRepo.WithByKey("UserName"))
if err != nil { if err != nil {
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error()) return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
@ -44,6 +45,13 @@ func (u *AuthService) Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo,
if info.Password != pass || nameSetting.Value != info.Name { if info.Password != pass || nameSetting.Value != info.Name {
return nil, constant.ErrAuth return nil, constant.ErrAuth
} }
entranceSetting, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
if err != nil {
return nil, err
}
if len(entranceSetting.Value) != 0 && entranceSetting.Value != entrance {
return nil, buserr.New(constant.ErrEntrance)
}
mfa, err := settingRepo.Get(settingRepo.WithByKey("MFAStatus")) mfa, err := settingRepo.Get(settingRepo.WithByKey("MFAStatus"))
if err != nil { if err != nil {
return nil, err return nil, err
@ -57,7 +65,7 @@ func (u *AuthService) Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo,
return u.generateSession(c, info.Name, info.AuthMethod) return u.generateSession(c, info.Name, info.AuthMethod)
} }
func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin) (*dto.UserLoginInfo, error) { func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin, entrance string) (*dto.UserLoginInfo, error) {
nameSetting, err := settingRepo.Get(settingRepo.WithByKey("UserName")) nameSetting, err := settingRepo.Get(settingRepo.WithByKey("UserName"))
if err != nil { if err != nil {
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error()) return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
@ -73,7 +81,13 @@ func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin) (*dto.UserLogi
if info.Password != pass || nameSetting.Value != info.Name { if info.Password != pass || nameSetting.Value != info.Name {
return nil, constant.ErrAuth return nil, constant.ErrAuth
} }
entranceSetting, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
if err != nil {
return nil, err
}
if len(entranceSetting.Value) != 0 && entranceSetting.Value != entrance {
return nil, buserr.New(constant.ErrEntrance)
}
mfaSecret, err := settingRepo.Get(settingRepo.WithByKey("MFASecret")) mfaSecret, err := settingRepo.Get(settingRepo.WithByKey("MFASecret"))
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -124,4 +124,5 @@ var (
var ( var (
ErrBackupInUsed = "ErrBackupInUsed" ErrBackupInUsed = "ErrBackupInUsed"
ErrOSSConn = "ErrOSSConn" ErrOSSConn = "ErrOSSConn"
ErrEntrance = "ErrEntrance"
) )

View File

@ -104,6 +104,7 @@ ErrDelWithWebsite: "The operating environment has been associated with a website
#setting #setting
ErrBackupInUsed: "The backup account is already being used in a cronjob and cannot be deleted." ErrBackupInUsed: "The backup account is already being used in a cronjob and cannot be deleted."
ErrOSSConn: "Unable to successfully request the latest version. Please check if the server can connect to the external network environment." ErrOSSConn: "Unable to successfully request the latest version. Please check if the server can connect to the external network environment."
ErrEntrance: "Security entrance information error. Please check and try again!"
#tool #tool
ErrConfigNotFound: "Configuration file does not exist" ErrConfigNotFound: "Configuration file does not exist"

View File

@ -104,6 +104,7 @@ ErrDelWithWebsite: "運行環境已經關聯網站,無法刪除"
#setting #setting
ErrBackupInUsed: "該備份帳號已在計劃任務中使用,無法刪除" ErrBackupInUsed: "該備份帳號已在計劃任務中使用,無法刪除"
ErrOSSConn: "無法成功請求最新版本,請檢查伺服器是否能夠連接到外部網絡環境。" ErrOSSConn: "無法成功請求最新版本,請檢查伺服器是否能夠連接到外部網絡環境。"
ErrEntrance: "安全入口信息錯誤,請檢查後重試!"
#tool #tool
ErrConfigNotFound: "配置文件不存在" ErrConfigNotFound: "配置文件不存在"

View File

@ -104,6 +104,7 @@ ErrDelWithWebsite: "运行环境已经关联网站,无法删除"
#setting #setting
ErrBackupInUsed: "该备份账号已在计划任务中使用,无法删除" ErrBackupInUsed: "该备份账号已在计划任务中使用,无法删除"
ErrOSSConn: "无法成功请求最新版本,请检查服务器是否能够连接到外部网络环境。" ErrOSSConn: "无法成功请求最新版本,请检查服务器是否能够连接到外部网络环境。"
ErrEntrance: "安全入口信息错误,请检查后重试!"
#tool #tool
ErrConfigNotFound: "配置文件不存在" ErrConfigNotFound: "配置文件不存在"

View File

@ -1,5 +1,5 @@
// Package docs GENERATED BY SWAG; DO NOT EDIT // Code generated by swaggo/swag. DO NOT EDIT.
// This file was generated by swaggo/swag
package docs package docs
import "github.com/swaggo/swag" import "github.com/swaggo/swag"
@ -956,6 +956,12 @@ const docTemplate = `{
"description": "OK", "description": "OK",
"schema": { "schema": {
"$ref": "#/definitions/dto.UserLoginInfo" "$ref": "#/definitions/dto.UserLoginInfo"
},
"headers": {
"EntranceCode": {
"type": "string",
"description": "安全入口"
}
} }
} }
} }
@ -1006,6 +1012,12 @@ const docTemplate = `{
"description": "OK", "description": "OK",
"schema": { "schema": {
"$ref": "#/definitions/dto.UserLoginInfo" "$ref": "#/definitions/dto.UserLoginInfo"
},
"headers": {
"EntranceCode": {
"type": "string",
"description": "安全入口"
}
} }
} }
} }
@ -14925,6 +14937,9 @@ const docTemplate = `{
"extension": { "extension": {
"type": "string" "type": "string"
}, },
"gid": {
"type": "string"
},
"group": { "group": {
"type": "string" "type": "string"
}, },
@ -14970,6 +14985,9 @@ const docTemplate = `{
"type": { "type": {
"type": "string" "type": "string"
}, },
"uid": {
"type": "string"
},
"updateTime": { "updateTime": {
"type": "string" "type": "string"
}, },
@ -17313,6 +17331,9 @@ const docTemplate = `{
"extension": { "extension": {
"type": "string" "type": "string"
}, },
"gid": {
"type": "string"
},
"group": { "group": {
"type": "string" "type": "string"
}, },
@ -17358,6 +17379,9 @@ const docTemplate = `{
"type": { "type": {
"type": "string" "type": "string"
}, },
"uid": {
"type": "string"
},
"updateTime": { "updateTime": {
"type": "string" "type": "string"
}, },

View File

@ -949,6 +949,12 @@
"description": "OK", "description": "OK",
"schema": { "schema": {
"$ref": "#/definitions/dto.UserLoginInfo" "$ref": "#/definitions/dto.UserLoginInfo"
},
"headers": {
"EntranceCode": {
"type": "string",
"description": "安全入口"
}
} }
} }
} }
@ -999,6 +1005,12 @@
"description": "OK", "description": "OK",
"schema": { "schema": {
"$ref": "#/definitions/dto.UserLoginInfo" "$ref": "#/definitions/dto.UserLoginInfo"
},
"headers": {
"EntranceCode": {
"type": "string",
"description": "安全入口"
}
} }
} }
} }
@ -14918,6 +14930,9 @@
"extension": { "extension": {
"type": "string" "type": "string"
}, },
"gid": {
"type": "string"
},
"group": { "group": {
"type": "string" "type": "string"
}, },
@ -14963,6 +14978,9 @@
"type": { "type": {
"type": "string" "type": "string"
}, },
"uid": {
"type": "string"
},
"updateTime": { "updateTime": {
"type": "string" "type": "string"
}, },
@ -17306,6 +17324,9 @@
"extension": { "extension": {
"type": "string" "type": "string"
}, },
"gid": {
"type": "string"
},
"group": { "group": {
"type": "string" "type": "string"
}, },
@ -17351,6 +17372,9 @@
"type": { "type": {
"type": "string" "type": "string"
}, },
"uid": {
"type": "string"
},
"updateTime": { "updateTime": {
"type": "string" "type": "string"
}, },

View File

@ -2177,6 +2177,8 @@ definitions:
type: string type: string
extension: extension:
type: string type: string
gid:
type: string
group: group:
type: string type: string
isDir: isDir:
@ -2207,6 +2209,8 @@ definitions:
type: integer type: integer
type: type:
type: string type: string
uid:
type: string
updateTime: updateTime:
type: string type: string
user: user:
@ -3778,6 +3782,8 @@ definitions:
type: string type: string
extension: extension:
type: string type: string
gid:
type: string
group: group:
type: string type: string
isDir: isDir:
@ -3808,6 +3814,8 @@ definitions:
type: integer type: integer
type: type:
type: string type: string
uid:
type: string
updateTime: updateTime:
type: string type: string
user: user:
@ -4620,6 +4628,10 @@ paths:
responses: responses:
"200": "200":
description: OK description: OK
headers:
EntranceCode:
description: 安全入口
type: string
schema: schema:
$ref: '#/definitions/dto.UserLoginInfo' $ref: '#/definitions/dto.UserLoginInfo'
summary: User login summary: User login
@ -4651,6 +4663,10 @@ paths:
responses: responses:
"200": "200":
description: OK description: OK
headers:
EntranceCode:
description: 安全入口
type: string
schema: schema:
$ref: '#/definitions/dto.UserLoginInfo' $ref: '#/definitions/dto.UserLoginInfo'
summary: User login with mfa summary: User login with mfa

View File

@ -5,6 +5,7 @@ import { checkStatus } from './helper/check-status';
import router from '@/routers'; import router from '@/routers';
import { GlobalStore } from '@/store'; import { GlobalStore } from '@/store';
import { MsgError } from '@/utils/message'; import { MsgError } from '@/utils/message';
import { Base64 } from 'js-base64';
const globalStore = GlobalStore(); const globalStore = GlobalStore();
@ -25,6 +26,10 @@ class RequestHttp {
'Accept-Language': language, 'Accept-Language': language,
...config.headers, ...config.headers,
}; };
if (config.url === '/auth/login' || config.url === '/auth/mfalogin') {
let entrace = Base64.encode(globalStore.entrance);
config.headers.EntranceCode = entrace;
}
return { return {
...config, ...config,
}; };