mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-03 12:30:19 +08:00
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:
@ -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()
|
||||||
|
}
|
||||||
|
@ -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()
|
||||||
|
}
|
||||||
|
@ -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
93
web/src/PasswordModal.js
Normal 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;
|
@ -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'}} >
|
||||||
|
@ -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());
|
||||||
|
}
|
||||||
|
@ -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":
|
||||||
{
|
{
|
||||||
|
@ -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":
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user