mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-19 08:19:15 +08:00
feat: 网站增加密码访问功能 (#782)
This commit is contained in:
parent
79622f324b
commit
37806f1113
@ -715,3 +715,46 @@ func (b *BaseApi) UpdateProxyConfigFile(c *gin.Context) {
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags Website
|
||||
// @Summary Get AuthBasic conf
|
||||
// @Description 获取密码访问配置
|
||||
// @Accept json
|
||||
// @Param request body request.NginxAuthReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/auths [post]
|
||||
func (b *BaseApi) GetAuthConfig(c *gin.Context) {
|
||||
var req request.NginxAuthReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
res, err := websiteService.GetAuthBasics(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, res)
|
||||
}
|
||||
|
||||
// @Tags Website
|
||||
// @Summary Get AuthBasic conf
|
||||
// @Description 更新密码访问配置
|
||||
// @Accept json
|
||||
// @Param request body request.NginxAuthUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/auths/update [post]
|
||||
func (b *BaseApi) UpdateAuthConfig(c *gin.Context) {
|
||||
var req request.NginxAuthUpdate
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := websiteService.UpdateAuthBasic(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
@ -28,6 +28,11 @@ type NginxParam struct {
|
||||
Params []string
|
||||
}
|
||||
|
||||
type NginxAuth struct {
|
||||
Username string `json:"username"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
type NginxKey string
|
||||
|
||||
const (
|
||||
|
@ -36,3 +36,15 @@ type NginxProxyUpdate struct {
|
||||
Content string `json:"content" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
}
|
||||
|
||||
type NginxAuthUpdate struct {
|
||||
WebsiteID uint `json:"websiteID" validate:"required"`
|
||||
Operate string `json:"operate" validate:"required"`
|
||||
Username string `json:"username" validate:"required"`
|
||||
Password string `json:"password" validate:"required"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
type NginxAuthReq struct {
|
||||
WebsiteID uint `json:"websiteID" validate:"required"`
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package response
|
||||
|
||||
import "github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
|
||||
type NginxStatus struct {
|
||||
Active string `json:"active"`
|
||||
Accepts string `json:"accepts"`
|
||||
@ -14,3 +16,8 @@ type NginxParam struct {
|
||||
Name string `json:"name"`
|
||||
Params []string `json:"params"`
|
||||
}
|
||||
|
||||
type NginxAuthRes struct {
|
||||
Enable bool `json:"enable"`
|
||||
Items []dto.NginxAuth `json:"items"`
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/nginx/components"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/nginx/parser"
|
||||
"github.com/1Panel-dev/1Panel/cmd/server/nginx_conf"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"gorm.io/gorm"
|
||||
"os"
|
||||
"path"
|
||||
@ -70,6 +71,8 @@ type IWebsiteService interface {
|
||||
OperateProxy(req request.WebsiteProxyConfig) (err error)
|
||||
GetProxies(id uint) (res []request.WebsiteProxyConfig, err error)
|
||||
UpdateProxyFile(req request.NginxProxyUpdate) (err error)
|
||||
GetAuthBasics(req request.NginxAuthReq) (res response.NginxAuthRes, err error)
|
||||
UpdateAuthBasic(req request.NginxAuthUpdate) (err error)
|
||||
}
|
||||
|
||||
func NewIWebsiteService() IWebsiteService {
|
||||
@ -1327,3 +1330,170 @@ func (w WebsiteService) UpdateProxyFile(req request.NginxProxyUpdate) (err error
|
||||
}()
|
||||
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
|
||||
}
|
||||
|
||||
func (w WebsiteService) UpdateAuthBasic(req request.NginxAuthUpdate) (err error) {
|
||||
var (
|
||||
website model.Website
|
||||
nginxInstall model.AppInstall
|
||||
params []dto.NginxParam
|
||||
authContent []byte
|
||||
authArray []string
|
||||
)
|
||||
website, err = websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
authPath := fmt.Sprintf("/www/sites/%s/auth_basic/auth.pass", website.Alias)
|
||||
absoluteAuthPath := path.Join(nginxInstall.GetPath(), authPath)
|
||||
fileOp := files.NewFileOp()
|
||||
if !fileOp.Stat(path.Dir(absoluteAuthPath)) {
|
||||
_ = fileOp.CreateDir(path.Dir(absoluteAuthPath), 755)
|
||||
}
|
||||
if !fileOp.Stat(absoluteAuthPath) {
|
||||
_ = fileOp.CreateFile(absoluteAuthPath)
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
switch req.Operate {
|
||||
case "create":
|
||||
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
params = append(params, dto.NginxParam{Name: "auth_basic", Params: []string{`"Authentication"`}})
|
||||
params = append(params, dto.NginxParam{Name: "auth_basic_user_file", Params: []string{authPath}})
|
||||
authContent, err = fileOp.GetContent(absoluteAuthPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
authArray = strings.Split(string(authContent), "\n")
|
||||
switch req.Operate {
|
||||
case "disable":
|
||||
return deleteNginxConfig(constant.NginxScopeServer, params, &website)
|
||||
case "enable":
|
||||
return updateNginxConfig(constant.NginxScopeServer, params, &website)
|
||||
case "create":
|
||||
for _, line := range authArray {
|
||||
authParams := strings.Split(line, ":")
|
||||
username := authParams[0]
|
||||
if username == req.Username {
|
||||
err = buserr.New(constant.ErrUsernameIsExist)
|
||||
return
|
||||
}
|
||||
}
|
||||
var passwdHash []byte
|
||||
passwdHash, err = bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
line := fmt.Sprintf("%s:%s\n", req.Username, passwdHash)
|
||||
if req.Remark != "" {
|
||||
line = fmt.Sprintf("%s:%s:%s\n", req.Username, passwdHash, req.Remark)
|
||||
}
|
||||
authArray = append(authArray, line)
|
||||
case "edit":
|
||||
userExist := false
|
||||
for index, line := range authArray {
|
||||
authParams := strings.Split(line, ":")
|
||||
username := authParams[0]
|
||||
if username == req.Username {
|
||||
userExist = true
|
||||
var passwdHash []byte
|
||||
passwdHash, err = bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
userPasswd := fmt.Sprintf("%s:%s\n", req.Username, passwdHash)
|
||||
if req.Remark != "" {
|
||||
userPasswd = fmt.Sprintf("%s:%s:%s\n", req.Username, passwdHash, req.Remark)
|
||||
}
|
||||
authArray[index] = userPasswd
|
||||
}
|
||||
}
|
||||
if !userExist {
|
||||
err = buserr.New(constant.ErrUsernameIsNotExist)
|
||||
return
|
||||
}
|
||||
case "delete":
|
||||
deleteIndex := -1
|
||||
for index, line := range authArray {
|
||||
authParams := strings.Split(line, ":")
|
||||
username := authParams[0]
|
||||
if username == req.Username {
|
||||
deleteIndex = index
|
||||
}
|
||||
}
|
||||
if deleteIndex < 0 {
|
||||
return
|
||||
}
|
||||
authArray = append(authArray[:deleteIndex], authArray[deleteIndex+1:]...)
|
||||
}
|
||||
|
||||
var passFile *os.File
|
||||
passFile, err = os.Create(absoluteAuthPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer passFile.Close()
|
||||
writer := bufio.NewWriter(passFile)
|
||||
for _, line := range authArray {
|
||||
_, err = writer.WriteString(line + "\n")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
err = writer.Flush()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (w WebsiteService) GetAuthBasics(req request.NginxAuthReq) (res response.NginxAuthRes, err error) {
|
||||
var (
|
||||
website model.Website
|
||||
nginxInstall model.AppInstall
|
||||
authContent []byte
|
||||
nginxParams []response.NginxParam
|
||||
)
|
||||
website, err = websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
authPath := fmt.Sprintf("/www/sites/%s/auth_basic/auth.pass", website.Alias)
|
||||
absoluteAuthPath := path.Join(nginxInstall.GetPath(), authPath)
|
||||
fileOp := files.NewFileOp()
|
||||
if !fileOp.Stat(absoluteAuthPath) {
|
||||
return
|
||||
}
|
||||
nginxParams, err = getNginxParamsByKeys(constant.NginxScopeServer, []string{"auth_basic"}, &website)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
res.Enable = len(nginxParams[0].Params) > 0
|
||||
authContent, err = fileOp.GetContent(absoluteAuthPath)
|
||||
authArray := strings.Split(string(authContent), "\n")
|
||||
for _, line := range authArray {
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
params := strings.Split(line, ":")
|
||||
auth := dto.NginxAuth{
|
||||
Username: params[0],
|
||||
}
|
||||
if len(params) == 3 {
|
||||
auth.Remark = params[2]
|
||||
}
|
||||
res.Items = append(res.Items, auth)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -65,10 +65,12 @@ var (
|
||||
|
||||
// website
|
||||
var (
|
||||
ErrDomainIsExist = "ErrDomainIsExist"
|
||||
ErrAliasIsExist = "ErrAliasIsExist"
|
||||
ErrAppDelete = "ErrAppDelete"
|
||||
ErrGroupIsUsed = "ErrGroupIsUsed"
|
||||
ErrDomainIsExist = "ErrDomainIsExist"
|
||||
ErrAliasIsExist = "ErrAliasIsExist"
|
||||
ErrAppDelete = "ErrAppDelete"
|
||||
ErrGroupIsUsed = "ErrGroupIsUsed"
|
||||
ErrUsernameIsExist = "ErrUsernameIsExist"
|
||||
ErrUsernameIsNotExist = "ErrUsernameIsNotExist"
|
||||
)
|
||||
|
||||
// ssl
|
||||
|
@ -43,6 +43,8 @@ ErrDomainIsExist: "Domain is already exist"
|
||||
ErrAliasIsExist: "Alias is already exist"
|
||||
ErrAppDelete: 'Other Website use this App'
|
||||
ErrGroupIsUsed: 'The group is in use and cannot be deleted'
|
||||
ErrUsernameIsExist: 'Username is already exist'
|
||||
ErrUsernameIsNotExist: 'Username is not exist'
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: "The certificate is being used by the website and cannot be removed"
|
||||
|
@ -43,6 +43,8 @@ ErrDomainIsExist: "域名已存在"
|
||||
ErrAliasIsExist: "代号已存在"
|
||||
ErrAppDelete: '其他网站使用此应用,无法删除'
|
||||
ErrGroupIsUsed: '分组正在使用中,无法删除'
|
||||
ErrUsernameIsExist: '用户名已存在'
|
||||
ErrUsernameIsNotExist: '用户不存在'
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: "证书正在被网站使用,无法删除"
|
||||
|
@ -55,5 +55,8 @@ func (a *WebsiteRouter) InitWebsiteRouter(Router *gin.RouterGroup) {
|
||||
groupRouter.POST("/proxies", baseApi.GetProxyConfig)
|
||||
groupRouter.POST("/proxies/update", baseApi.UpdateProxyConfig)
|
||||
groupRouter.POST("/proxies/file", baseApi.UpdateProxyConfigFile)
|
||||
|
||||
groupRouter.POST("/auths", baseApi.GetAuthConfig)
|
||||
groupRouter.POST("/auths/update", baseApi.UpdateAuthConfig)
|
||||
}
|
||||
}
|
||||
|
@ -7904,6 +7904,72 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/auths": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取密码访问配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website"
|
||||
],
|
||||
"summary": "Get AuthBasic conf",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.NginxAuthReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/auths/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "更新密码访问配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website"
|
||||
],
|
||||
"summary": "Get AuthBasic conf",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.NginxAuthUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/check": {
|
||||
"post": {
|
||||
"security": [
|
||||
@ -12764,6 +12830,43 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.NginxAuthReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"websiteID"
|
||||
],
|
||||
"properties": {
|
||||
"websiteID": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.NginxAuthUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"operate",
|
||||
"password",
|
||||
"username",
|
||||
"websiteID"
|
||||
],
|
||||
"properties": {
|
||||
"operate": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"remark": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
},
|
||||
"websiteID": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.NginxConfigFileUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -7897,6 +7897,72 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/auths": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取密码访问配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website"
|
||||
],
|
||||
"summary": "Get AuthBasic conf",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.NginxAuthReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/auths/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "更新密码访问配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Website"
|
||||
],
|
||||
"summary": "Get AuthBasic conf",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.NginxAuthUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/websites/check": {
|
||||
"post": {
|
||||
"security": [
|
||||
@ -12757,6 +12823,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.NginxAuthReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"websiteID"
|
||||
],
|
||||
"properties": {
|
||||
"websiteID": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.NginxAuthUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"operate",
|
||||
"password",
|
||||
"username",
|
||||
"websiteID"
|
||||
],
|
||||
"properties": {
|
||||
"operate": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"remark": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
},
|
||||
"websiteID": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.NginxConfigFileUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -2124,6 +2124,31 @@ definitions:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
type: object
|
||||
request.NginxAuthReq:
|
||||
properties:
|
||||
websiteID:
|
||||
type: integer
|
||||
required:
|
||||
- websiteID
|
||||
type: object
|
||||
request.NginxAuthUpdate:
|
||||
properties:
|
||||
operate:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
remark:
|
||||
type: string
|
||||
username:
|
||||
type: string
|
||||
websiteID:
|
||||
type: integer
|
||||
required:
|
||||
- operate
|
||||
- password
|
||||
- username
|
||||
- websiteID
|
||||
type: object
|
||||
request.NginxConfigFileUpdate:
|
||||
properties:
|
||||
backup:
|
||||
@ -8018,6 +8043,46 @@ paths:
|
||||
summary: Page website acme accounts
|
||||
tags:
|
||||
- Website Acme
|
||||
/websites/auths:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 获取密码访问配置
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.NginxAuthReq'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Get AuthBasic conf
|
||||
tags:
|
||||
- Website
|
||||
/websites/auths/update:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 更新密码访问配置
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.NginxAuthUpdate'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Get AuthBasic conf
|
||||
tags:
|
||||
- Website
|
||||
/websites/check:
|
||||
post:
|
||||
consumes:
|
||||
|
@ -338,4 +338,26 @@ export namespace Website {
|
||||
name: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
export interface AuthReq {
|
||||
websiteID: number;
|
||||
}
|
||||
|
||||
export interface NginxAuth {
|
||||
username: string;
|
||||
remark: string;
|
||||
}
|
||||
|
||||
export interface AuthConfig {
|
||||
enable: boolean;
|
||||
items: NginxAuth[];
|
||||
}
|
||||
|
||||
export interface NginxAuthConfig {
|
||||
websiteID: number;
|
||||
operate: string;
|
||||
username: string;
|
||||
password: string;
|
||||
remark: string;
|
||||
}
|
||||
}
|
||||
|
@ -198,3 +198,11 @@ export const OperateProxyConfig = (req: Website.ProxyReq) => {
|
||||
export const UpdateProxyConfigFile = (req: Website.ProxyFileUpdate) => {
|
||||
return http.post<any>(`/websites/proxies/file`, req);
|
||||
};
|
||||
|
||||
export const GetAuthConfig = (req: Website.AuthReq) => {
|
||||
return http.post<Website.AuthConfig>(`/websites/auths`, req);
|
||||
};
|
||||
|
||||
export const OperateAuthConfig = (req: Website.NginxAuthConfig) => {
|
||||
return http.post<any>(`/websites/auths/update`, req);
|
||||
};
|
||||
|
@ -1224,6 +1224,10 @@ const message = {
|
||||
replaceText: 'Replacement text, can be empty',
|
||||
replacedErr: 'The replaced text cannot be empty',
|
||||
replacedErr2: 'The replaced text cannot be repeated',
|
||||
basicAuth: 'Password Access',
|
||||
editBasicAuthHelper:
|
||||
'The password is asymmetrically encrypted and cannot be echoed. Editing needs to reset the password',
|
||||
createPassword: 'Generate password',
|
||||
},
|
||||
php: {
|
||||
short_open_tag: 'Short tag support',
|
||||
|
@ -1223,6 +1223,9 @@ const message = {
|
||||
replaceText: '替换的文本,可为空',
|
||||
replacedErr: '被替换的文本不能为空',
|
||||
replacedErr2: '被替换的文本不能重复',
|
||||
basicAuth: '密码访问',
|
||||
editBasicAuthHelper: '密码为非对称加密,无法回显,编辑需要重新设置密码',
|
||||
createPassword: '生成密码',
|
||||
},
|
||||
php: {
|
||||
short_open_tag: '短标签支持',
|
||||
|
@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<el-drawer v-model="open" :close-on-click-modal="false" size="40%" :before-close="handleClose">
|
||||
<template #header>
|
||||
<DrawerHeader
|
||||
:header="$t('commons.button.' + authBasic.operate) + $t('website.basicAuth')"
|
||||
:back="handleClose"
|
||||
/>
|
||||
</template>
|
||||
<el-row v-loading="loading">
|
||||
<el-col :span="22" :offset="1">
|
||||
<el-form-item>
|
||||
<el-alert
|
||||
v-if="authBasic.operate === 'edit'"
|
||||
:title="$t('website.editBasicAuthHelper')"
|
||||
type="info"
|
||||
:closable="false"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form ref="proxyForm" label-position="top" :model="authBasic" :rules="rules">
|
||||
<el-form-item :label="$t('commons.table.name')" prop="username">
|
||||
<el-input v-model.trim="authBasic.username" :disabled="authBasic.operate === 'edit'"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('commons.login.password')" prop="password">
|
||||
<el-input type="password" clearable show-password v-model.trim="authBasic.password">
|
||||
<template #append>
|
||||
<el-button @click="random">
|
||||
{{ $t('website.createPassword') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('website.remark')" prop="remark">
|
||||
<el-input v-model.trim="authBasic.remark"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="submit(proxyForm)" :disabled="loading">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { OperateAuthConfig } from '@/api/modules/website';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import i18n from '@/lang';
|
||||
import { FormInstance } from 'element-plus';
|
||||
import { ref } from 'vue';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { Website } from '@/api/interface/website';
|
||||
import { getRandomStr } from '@/utils/util';
|
||||
|
||||
const proxyForm = ref<FormInstance>();
|
||||
const rules = ref({
|
||||
username: [Rules.requiredInput, Rules.name],
|
||||
password: [Rules.requiredInput],
|
||||
});
|
||||
const open = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
const initData = (): Website.NginxAuthConfig => ({
|
||||
websiteID: 0,
|
||||
operate: 'create',
|
||||
username: '',
|
||||
password: '',
|
||||
remark: '',
|
||||
});
|
||||
|
||||
let authBasic = ref(initData());
|
||||
const em = defineEmits(['close']);
|
||||
const handleClose = () => {
|
||||
proxyForm.value?.resetFields();
|
||||
open.value = false;
|
||||
em('close', false);
|
||||
};
|
||||
|
||||
const random = async () => {
|
||||
authBasic.value.password = getRandomStr(16);
|
||||
};
|
||||
|
||||
const acceptParams = (proxyParam: Website.NginxAuthConfig) => {
|
||||
authBasic.value = proxyParam;
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
const submit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid) => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
OperateAuthConfig(authBasic.value)
|
||||
.then(() => {
|
||||
if (authBasic.value.operate == 'create') {
|
||||
MsgSuccess(i18n.global.t('commons.msg.createSuccess'));
|
||||
} else {
|
||||
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
|
||||
}
|
||||
handleClose();
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<el-form-item prop="enable" :label="$t('website.enableOrNot')">
|
||||
<el-switch v-model="enable" @change="changeEnable"></el-switch>
|
||||
</el-form-item>
|
||||
<ComplexTable :data="data" @search="search" v-loading="loading">
|
||||
<template #toolbar>
|
||||
<el-button type="primary" plain @click="openCreate">
|
||||
{{ $t('commons.button.create') + $t('website.basicAuth') }}
|
||||
</el-button>
|
||||
</template>
|
||||
<el-table-column :label="$t('commons.table.name')" prop="username"></el-table-column>
|
||||
<el-table-column :label="$t('website.remark')" prop="remark"></el-table-column>
|
||||
<fu-table-operations
|
||||
:ellipsis="10"
|
||||
width="260px"
|
||||
:buttons="buttons"
|
||||
:label="$t('commons.table.operate')"
|
||||
fixed="right"
|
||||
fix
|
||||
/>
|
||||
</ComplexTable>
|
||||
<Create ref="createRef" @close="search()" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name="proxy">
|
||||
import { Website } from '@/api/interface/website';
|
||||
import { OperateAuthConfig, GetAuthConfig } from '@/api/modules/website';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import i18n from '@/lang';
|
||||
import Create from './create/index.vue';
|
||||
import { useDeleteData } from '@/hooks/use-delete-data';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
|
||||
const props = defineProps({
|
||||
id: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
const id = computed(() => {
|
||||
return props.id;
|
||||
});
|
||||
const loading = ref(false);
|
||||
const data = ref();
|
||||
const createRef = ref();
|
||||
const enable = ref(false);
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
label: i18n.global.t('commons.button.edit'),
|
||||
click: function (row: Website.NginxAuthConfig) {
|
||||
openEdit(row);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.button.delete'),
|
||||
click: function (row: Website.NginxAuthConfig) {
|
||||
deleteAuth(row);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const initData = (id: number): Website.NginxAuthConfig => ({
|
||||
websiteID: id,
|
||||
operate: 'create',
|
||||
username: '',
|
||||
password: '',
|
||||
remark: '',
|
||||
});
|
||||
|
||||
const openCreate = () => {
|
||||
createRef.value.acceptParams(initData(id.value));
|
||||
};
|
||||
|
||||
const openEdit = (authConfig: Website.NginxAuthConfig) => {
|
||||
let authParam = JSON.parse(JSON.stringify(authConfig));
|
||||
authParam.operate = 'edit';
|
||||
authParam.websiteID = id.value;
|
||||
createRef.value.acceptParams(authParam);
|
||||
};
|
||||
|
||||
const deleteAuth = async (authConfig: Website.NginxAuthConfig) => {
|
||||
authConfig.operate = 'delete';
|
||||
authConfig.websiteID = id.value;
|
||||
await useDeleteData(OperateAuthConfig, authConfig, 'commons.msg.delete');
|
||||
search();
|
||||
};
|
||||
|
||||
const changeEnable = () => {
|
||||
const req = initData(id.value);
|
||||
req.operate = enable.value ? 'enable' : 'disable';
|
||||
loading.value = true;
|
||||
OperateAuthConfig(req)
|
||||
.then(() => {
|
||||
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
|
||||
search();
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const search = async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
const res = await GetAuthConfig({ websiteID: id.value });
|
||||
data.value = res.data.items || [];
|
||||
enable.value = res.data.enable;
|
||||
} catch (error) {
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
search();
|
||||
});
|
||||
</script>
|
@ -15,14 +15,17 @@
|
||||
<el-tab-pane :label="$t('website.proxy')">
|
||||
<Proxy :id="id" v-if="tabIndex == '4'"></Proxy>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('website.basicAuth')">
|
||||
<AuthBasic :id="id" v-if="tabIndex == '5'"></AuthBasic>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="'HTTPS'">
|
||||
<HTTPS :id="id" v-if="tabIndex == '5'"></HTTPS>
|
||||
<HTTPS :id="id" v-if="tabIndex == '6'"></HTTPS>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('website.rewrite')">
|
||||
<Rewrite :id="id" v-if="tabIndex == '6'"></Rewrite>
|
||||
<Rewrite :id="id" v-if="tabIndex == '7'"></Rewrite>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('website.other')">
|
||||
<Other :id="id" v-if="tabIndex == '7'"></Other>
|
||||
<Other :id="id" v-if="tabIndex == '8'"></Other>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
@ -38,6 +41,7 @@ import HTTPS from './https/index.vue';
|
||||
import SitePath from './site-folder/index.vue';
|
||||
import Rewrite from './rewrite/index.vue';
|
||||
import Proxy from './proxy/index.vue';
|
||||
import AuthBasic from './auth-basic/index.vue';
|
||||
|
||||
const props = defineProps({
|
||||
id: {
|
||||
|
Loading…
x
Reference in New Issue
Block a user