feat: set password for users

Signed-off-by: Kininaru <shiftregister233@outlook.com>

removed useless blank

Signed-off-by: Kininaru <shiftregister233@outlook.com>

add license header

Signed-off-by: Kininaru <shiftregister233@outlook.com>

i18n

Signed-off-by: Kininaru <shiftregister233@outlook.com>

database logic

Signed-off-by: Kininaru <shiftregister233@outlook.com>

i18n

Signed-off-by: Kininaru <shiftregister233@outlook.com>

i18n

Signed-off-by: Kininaru <shiftregister233@outlook.com>
This commit is contained in:
Kininaru
2021-05-09 19:54:20 +08:00
parent 19c1ef1b68
commit 33e61cc5cf
8 changed files with 220 additions and 7 deletions

View File

@ -16,6 +16,8 @@ package controllers
import ( import (
"encoding/json" "encoding/json"
"fmt"
"strings"
"github.com/casdoor/casdoor/object" "github.com/casdoor/casdoor/object"
) )
@ -103,3 +105,71 @@ func (c *ApiController) DeleteUser() {
c.Data["json"] = wrapActionResponse(object.DeleteUser(&user)) c.Data["json"] = wrapActionResponse(object.DeleteUser(&user))
c.ServeJSON() c.ServeJSON()
} }
// @Title SetPassword
// @Description set password
// @Param userOwner formData string true "The owner of the user"
// @Param userName formData string true "The name of the user"
// @Param oldPassword formData string true "The old password of the user"
// @Param newPassword formData string true "The new password of the user"
// @Success 200 {object} controllers.Response The Response object
// @router /set-password [post]
func (c *ApiController) SetPassword() {
userOwner := c.Ctx.Request.Form.Get("userOwner")
userName := c.Ctx.Request.Form.Get("userName")
oldPassword := c.Ctx.Request.Form.Get("oldPassword")
newPassword := c.Ctx.Request.Form.Get("newPassword")
requestUserId := c.GetSessionUser()
if requestUserId == "" {
c.ResponseError("Please login first.")
return
}
requestUser := object.GetUser(requestUserId)
if requestUser == nil {
c.ResponseError("Session outdated. Please login again.")
return
}
userId := fmt.Sprintf("%s/%s", userOwner, userName)
targetUser := object.GetUser(userId)
if targetUser == nil {
c.ResponseError("Invalid user id.")
return
}
hasPermission := false
if requestUser.IsGlobalAdmin {
hasPermission = true
} else if requestUserId == userId {
hasPermission = true
} else if targetUser.Owner == requestUser.Owner && requestUser.IsAdmin {
hasPermission = true
}
if !hasPermission {
c.ResponseError("You don't have the permission to do this.")
return
}
if oldPassword != targetUser.Password {
c.ResponseError("Old password wrong.")
return
}
if strings.Index(newPassword, " ") >= 0 {
c.ResponseError("New password contains blank space.")
return
}
if newPassword == "" {
c.ResponseError("Invalid new password")
return
}
targetUser.Password = newPassword
object.SetUserField(targetUser, "password", targetUser.Password)
c.Data["json"] = Response{Status: "ok"}
c.ServeJSON()
}

View File

@ -52,3 +52,8 @@ func InitHttpClient() {
//defer resp.Body.Close() //defer resp.Body.Close()
//println("Response status: %s", resp.Status) //println("Response status: %s", resp.Status)
} }
func (c *ApiController) ResponseError(error string) {
c.Data["json"] = Response{Status: "error", Msg: error}
c.ServeJSON()
}

View File

@ -59,6 +59,7 @@ func initAPI() {
beego.Router("/api/add-user", &controllers.ApiController{}, "POST:AddUser") beego.Router("/api/add-user", &controllers.ApiController{}, "POST:AddUser")
beego.Router("/api/delete-user", &controllers.ApiController{}, "POST:DeleteUser") beego.Router("/api/delete-user", &controllers.ApiController{}, "POST:DeleteUser")
beego.Router("/api/upload-avatar", &controllers.ApiController{}, "POST:UploadAvatar") beego.Router("/api/upload-avatar", &controllers.ApiController{}, "POST:UploadAvatar")
beego.Router("/api/set-password", &controllers.ApiController{}, "POST:SetPassword")
beego.Router("/api/get-providers", &controllers.ApiController{}, "GET:GetProviders") beego.Router("/api/get-providers", &controllers.ApiController{}, "GET:GetProviders")
beego.Router("/api/get-default-providers", &controllers.ApiController{}, "GET:GetDefaultProviders") beego.Router("/api/get-default-providers", &controllers.ApiController{}, "GET:GetDefaultProviders")

93
web/src/PasswordModal.js Normal file
View File

@ -0,0 +1,93 @@
// Copyright 2021 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import {Button, Col, Modal, Row, Input,} from "antd";
import i18next from "i18next";
import React from "react";
import * as UserBackend from "./backend/UserBackend";
import * as Setting from "./Setting";
export const PasswordModal = (props) => {
const [visible, setVisible] = React.useState(false);
const [confirmLoading, setConfirmLoading] = React.useState(false);
const {user} = props;
const showModal = () => {
setVisible(true);
};
const handleCancel = () => {
setVisible(false);
};
const handleOk = () => {
let oldPassword = document.getElementById("old-password")?.value;
let newPassword = document.getElementById("new-password").value;
let rePassword = document.getElementById("re-new-password").value;
if (oldPassword === null || oldPassword === undefined) oldPassword = "";
if (newPassword === "" || rePassword === "") {
Setting.showMessage("error", i18next.t("user:Empty input!"));
return;
}
if (newPassword !== rePassword) {
Setting.showMessage("error", i18next.t("user:Two passwords you typed do not match."));
return;
}
setConfirmLoading(true);
UserBackend.setPassword(user.owner, user.name, oldPassword, newPassword).then((res) => {
setConfirmLoading(false);
if (res.status === "ok") {
Setting.showMessage("success", i18next.t("user:Password Set"));
setVisible(false);
}
else Setting.showMessage("error", i18next.t(`user:${res.msg}`));
})
}
let hasOldPassword = user.password !== "";
return (
<Row>
<Button type="default" onClick={showModal}>
{ hasOldPassword ? i18next.t("user:Modify password...") : i18next.t("user:Set password...")}
</Button>
<Modal
title={i18next.t("user:Password")}
visible={visible}
okText={i18next.t("user:Set Password")}
cancelText={i18next.t("user:Cancel")}
confirmLoading={confirmLoading}
onCancel={handleCancel}
onOk={handleOk}
width={600}
>
<Col style={{margin: "0px auto 40px auto", width: 1000, height: 300}}>
{ hasOldPassword ? (
<Row style={{width: "100%", marginBottom: "20px"}}>
<Input.Password addonBefore={i18next.t("user:Old Password")} placeholder={i18next.t("user:input password")} id="old-password"/>
</Row>
) : null}
<Row style={{width: "100%", marginBottom: "20px"}}>
<Input.Password addonBefore={i18next.t("user:New Password")} placeholder={i18next.t("user:input password")} id="new-password"/>
</Row>
<Row style={{width: "100%", marginBottom: "20px"}}>
<Input.Password addonBefore={i18next.t("user:Re-enter New")} placeholder={i18next.t("user:input password")} id="re-new-password"/>
</Row>
</Col>
</Modal>
</Row>
)
}
export default PasswordModal;

View File

@ -24,6 +24,7 @@ import * as AuthBackend from "./auth/AuthBackend";
import * as ApplicationBackend from "./backend/ApplicationBackend"; import * as ApplicationBackend from "./backend/ApplicationBackend";
import * as ProviderBackend from "./backend/ProviderBackend"; import * as ProviderBackend from "./backend/ProviderBackend";
import * as Provider from "./auth/Provider"; import * as Provider from "./auth/Provider";
import PasswordModal from "./PasswordModal";
const { Option } = Select; const { Option } = Select;
@ -266,11 +267,7 @@ class UserEditPage extends React.Component {
{i18next.t("general:Password")}: {i18next.t("general:Password")}:
</Col> </Col>
<Col span={22} > <Col span={22} >
<Row> <PasswordModal user={this.state.user} />
<Button type="default">
{this.state.user.password === "" ? i18next.t("user:Set password...") : i18next.t("user:Modify password...")}
</Button>
</Row>
</Col> </Col>
</Row> </Row>
<Row style={{marginTop: '20px'}} > <Row style={{marginTop: '20px'}} >

View File

@ -79,3 +79,16 @@ export function uploadAvatar(avatar) {
}); });
}); });
} }
export function setPassword(userOwner, userName, oldPassword, newPassword) {
let formData = new FormData();
formData.append("userOwner", userOwner);
formData.append("userName", userName);
formData.append("oldPassword", oldPassword);
formData.append("newPassword", newPassword);
return fetch(`${Setting.ServerUrl}/api/set-password`, {
method: "POST",
credentials: "include",
body: formData
}).then(res => res.json());
}

View File

@ -98,7 +98,24 @@
"Unlink": "Unlink", "Unlink": "Unlink",
"Is admin": "Is admin", "Is admin": "Is admin",
"Is global admin": "Is global admin", "Is global admin": "Is global admin",
"Is forbidden": "Is forbidden" "Is forbidden": "Is forbidden",
"Empty input!": "Empty input!",
"Two passwords you typed do not match.": "Two passwords you typed do not match.",
"Password Set": "Password Set",
"Set Password": "Set Password",
"Old Password": "Old Password",
"New Password": "New Password",
"Re-enter New": "Re-enter New",
"Please login first.": "Please login first.",
"Session outdated. Please login again.": "Session outdated. Please login again.",
"Invalid user id.": "Invalid user id.",
"You don't have the permission to do this.": "You don't have the permission to do this.",
"Old password wrong.": "Old password wrong.",
"New password contains blank space.": "New password contains blank space.",
"Invalid new password": "Invalid new password",
"Password": "Password",
"Cancel": "Cancel",
"input password": "input password"
}, },
"application": "application":
{ {

View File

@ -100,7 +100,24 @@
"Unlink": "解绑", "Unlink": "解绑",
"Is admin": "是管理员", "Is admin": "是管理员",
"Is global admin": "是全局管理员", "Is global admin": "是全局管理员",
"Is forbidden": "被禁用" "Is forbidden": "被禁用",
"Empty input!": "输入为空!",
"Two passwords you typed do not match.": "两次输入的密码不匹配。",
"Password Set": "密码已设置",
"Set Password": "设置密码",
"Old Password": "旧密码",
"New Password": "新密码",
"Re-enter New": "重复新密码",
"Please login first.": "请先登录。",
"Session outdated. Please login again.": "会话已过期,请重新登陆。",
"Invalid user id.": "用户 ID 错误",
"You don't have the permission to do this.": "你没有权限这么做。",
"Old password wrong.": "旧密码错误!",
"New password contains blank space.": "新密码包含空格。",
"Invalid new password": "非法的新密码。",
"Password": "密码",
"Cancel": "取消",
"input password": "输入密码"
}, },
"application": "application":
{ {