mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-03 12:30:19 +08:00
feat: add access key and secret key for user (#1971)
This commit is contained in:
@ -528,3 +528,25 @@ func (c *ApiController) GetUserCount() {
|
|||||||
c.Data["json"] = count
|
c.Data["json"] = count
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddUserkeys
|
||||||
|
// @Title AddUserkeys
|
||||||
|
// @router /add-user-keys [post]
|
||||||
|
// @Tag User API
|
||||||
|
func (c *ApiController) AddUserkeys() {
|
||||||
|
var user object.User
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
isAdmin := c.IsAdmin()
|
||||||
|
affected, err := object.AddUserkeys(&user, isAdmin)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.ResponseOk(affected)
|
||||||
|
}
|
||||||
|
@ -78,6 +78,8 @@ type User struct {
|
|||||||
Hash string `xorm:"varchar(100)" json:"hash"`
|
Hash string `xorm:"varchar(100)" json:"hash"`
|
||||||
PreHash string `xorm:"varchar(100)" json:"preHash"`
|
PreHash string `xorm:"varchar(100)" json:"preHash"`
|
||||||
Groups []string `xorm:"varchar(1000)" json:"groups"`
|
Groups []string `xorm:"varchar(1000)" json:"groups"`
|
||||||
|
AccessKey string `xorm:"varchar(100)" json:"accessKey"`
|
||||||
|
SecretKey string `xorm:"varchar(100)" json:"secretKey"`
|
||||||
|
|
||||||
CreatedIp string `xorm:"varchar(100)" json:"createdIp"`
|
CreatedIp string `xorm:"varchar(100)" json:"createdIp"`
|
||||||
LastSigninTime string `xorm:"varchar(100)" json:"lastSigninTime"`
|
LastSigninTime string `xorm:"varchar(100)" json:"lastSigninTime"`
|
||||||
@ -422,6 +424,23 @@ func GetUserByUserId(owner string, userId string) (*User, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetUserByAccessKey(accessKey string) (*User, error) {
|
||||||
|
if accessKey == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
user := User{AccessKey: accessKey}
|
||||||
|
existed, err := adapter.Engine.Get(&user)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if existed {
|
||||||
|
return &user, nil
|
||||||
|
} else {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func GetUser(id string) (*User, error) {
|
func GetUser(id string) (*User, error) {
|
||||||
owner, name := util.GetOwnerAndNameFromId(id)
|
owner, name := util.GetOwnerAndNameFromId(id)
|
||||||
return getUser(owner, name)
|
return getUser(owner, name)
|
||||||
@ -526,7 +545,7 @@ func UpdateUser(id string, user *User, columns []string, isAdmin bool) (bool, er
|
|||||||
"owner", "display_name", "avatar",
|
"owner", "display_name", "avatar",
|
||||||
"location", "address", "country_code", "region", "language", "affiliation", "title", "homepage", "bio", "tag", "language", "gender", "birthday", "education", "score", "karma", "ranking", "signup_application",
|
"location", "address", "country_code", "region", "language", "affiliation", "title", "homepage", "bio", "tag", "language", "gender", "birthday", "education", "score", "karma", "ranking", "signup_application",
|
||||||
"is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts",
|
"is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts",
|
||||||
"signin_wrong_times", "last_signin_wrong_time", "groups",
|
"signin_wrong_times", "last_signin_wrong_time", "groups", "access_key", "secret_key",
|
||||||
"github", "google", "qq", "wechat", "facebook", "dingtalk", "weibo", "gitee", "linkedin", "wecom", "lark", "gitlab", "adfs",
|
"github", "google", "qq", "wechat", "facebook", "dingtalk", "weibo", "gitee", "linkedin", "wecom", "lark", "gitlab", "adfs",
|
||||||
"baidu", "alipay", "casdoor", "infoflow", "apple", "azuread", "slack", "steam", "bilibili", "okta", "douyin", "line", "amazon",
|
"baidu", "alipay", "casdoor", "infoflow", "apple", "azuread", "slack", "steam", "bilibili", "okta", "douyin", "line", "amazon",
|
||||||
"auth0", "battlenet", "bitbucket", "box", "cloudfoundry", "dailymotion", "deezer", "digitalocean", "discord", "dropbox",
|
"auth0", "battlenet", "bitbucket", "box", "cloudfoundry", "dailymotion", "deezer", "digitalocean", "discord", "dropbox",
|
||||||
@ -928,3 +947,14 @@ func (user *User) GetPreferMfa(masked bool) *MfaProps {
|
|||||||
return user.MultiFactorAuths[0]
|
return user.MultiFactorAuths[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AddUserkeys(user *User, isAdmin bool) (bool, error) {
|
||||||
|
if user == nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
user.AccessKey = util.GenerateId()
|
||||||
|
user.SecretKey = util.GenerateId()
|
||||||
|
|
||||||
|
return UpdateUser(user.GetId(), user, []string{}, isAdmin)
|
||||||
|
}
|
||||||
|
@ -26,8 +26,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Object struct {
|
type Object struct {
|
||||||
Owner string `json:"owner"`
|
Owner string `json:"owner"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
AccessKey string `json:"accessKey"`
|
||||||
|
SecretKey string `json:"secretKey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUsername(ctx *context.Context) (username string) {
|
func getUsername(ctx *context.Context) (username string) {
|
||||||
@ -43,6 +45,9 @@ func getUsername(ctx *context.Context) (username string) {
|
|||||||
username = getUsernameByClientIdSecret(ctx)
|
username = getUsernameByClientIdSecret(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if username == "" {
|
||||||
|
username = getUsernameByKeys(ctx)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,6 +103,30 @@ func getObject(ctx *context.Context) (string, string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getKeys(ctx *context.Context) (string, string) {
|
||||||
|
method := ctx.Request.Method
|
||||||
|
|
||||||
|
if method == http.MethodGet {
|
||||||
|
accessKey := ctx.Input.Query("accesskey")
|
||||||
|
secretKey := ctx.Input.Query("secretkey")
|
||||||
|
return accessKey, secretKey
|
||||||
|
} else {
|
||||||
|
body := ctx.Input.RequestBody
|
||||||
|
|
||||||
|
if len(body) == 0 {
|
||||||
|
return ctx.Request.Form.Get("accesskey"), ctx.Request.Form.Get("secretkey")
|
||||||
|
}
|
||||||
|
|
||||||
|
var obj Object
|
||||||
|
err := json.Unmarshal(body, &obj)
|
||||||
|
if err != nil {
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj.AccessKey, obj.SecretKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func willLog(subOwner string, subName string, method string, urlPath string, objOwner string, objName string) bool {
|
func willLog(subOwner string, subName string, method string, urlPath string, objOwner string, objName string) bool {
|
||||||
if subOwner == "anonymous" && subName == "anonymous" && method == "GET" && (urlPath == "/api/get-account" || urlPath == "/api/get-app-login") && objOwner == "" && objName == "" {
|
if subOwner == "anonymous" && subName == "anonymous" && method == "GET" && (urlPath == "/api/get-account" || urlPath == "/api/get-app-login") && objOwner == "" && objName == "" {
|
||||||
return false
|
return false
|
||||||
|
@ -84,6 +84,18 @@ func getUsernameByClientIdSecret(ctx *context.Context) string {
|
|||||||
return fmt.Sprintf("app/%s", application.Name)
|
return fmt.Sprintf("app/%s", application.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getUsernameByKeys(ctx *context.Context) string {
|
||||||
|
accessKey, secretKey := getKeys(ctx)
|
||||||
|
user, err := object.GetUserByAccessKey(accessKey)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if user != nil && secretKey == user.SecretKey {
|
||||||
|
return user.GetId()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func getSessionUser(ctx *context.Context) string {
|
func getSessionUser(ctx *context.Context) string {
|
||||||
user := ctx.Input.CruSession.Get("username")
|
user := ctx.Input.CruSession.Get("username")
|
||||||
if user == nil {
|
if user == nil {
|
||||||
|
@ -73,6 +73,7 @@ func initAPI() {
|
|||||||
beego.Router("/api/get-user-count", &controllers.ApiController{}, "GET:GetUserCount")
|
beego.Router("/api/get-user-count", &controllers.ApiController{}, "GET:GetUserCount")
|
||||||
beego.Router("/api/get-user", &controllers.ApiController{}, "GET:GetUser")
|
beego.Router("/api/get-user", &controllers.ApiController{}, "GET:GetUser")
|
||||||
beego.Router("/api/update-user", &controllers.ApiController{}, "POST:UpdateUser")
|
beego.Router("/api/update-user", &controllers.ApiController{}, "POST:UpdateUser")
|
||||||
|
beego.Router("/api/add-user-keys", &controllers.ApiController{}, "POST:AddUserkeys")
|
||||||
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-users", &controllers.ApiController{}, "POST:UploadUsers")
|
beego.Router("/api/upload-users", &controllers.ApiController{}, "POST:UploadUsers")
|
||||||
|
@ -60,6 +60,7 @@ class OrganizationListPage extends BaseListPage {
|
|||||||
{name: "Bio", visible: true, viewRule: "Public", modifyRule: "Self"},
|
{name: "Bio", visible: true, viewRule: "Public", modifyRule: "Self"},
|
||||||
{name: "Tag", visible: true, viewRule: "Public", modifyRule: "Admin"},
|
{name: "Tag", visible: true, viewRule: "Public", modifyRule: "Admin"},
|
||||||
{name: "Signup application", visible: true, viewRule: "Public", modifyRule: "Admin"},
|
{name: "Signup application", visible: true, viewRule: "Public", modifyRule: "Admin"},
|
||||||
|
{name: "API key", label: i18next.t("general:API key")},
|
||||||
{name: "Roles", visible: true, viewRule: "Public", modifyRule: "Immutable"},
|
{name: "Roles", visible: true, viewRule: "Public", modifyRule: "Immutable"},
|
||||||
{name: "Permissions", visible: true, viewRule: "Public", modifyRule: "Immutable"},
|
{name: "Permissions", visible: true, viewRule: "Public", modifyRule: "Immutable"},
|
||||||
{name: "Groups", visible: true, viewRule: "Public", modifyRule: "Immutable"},
|
{name: "Groups", visible: true, viewRule: "Public", modifyRule: "Immutable"},
|
||||||
|
@ -91,6 +91,17 @@ class UserEditPage extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addUserKeys() {
|
||||||
|
UserBackend.addUserKeys(this.state.user)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.status === "ok") {
|
||||||
|
this.getUser();
|
||||||
|
} else {
|
||||||
|
Setting.showMessage("error", res.msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
getOrganizations() {
|
getOrganizations() {
|
||||||
OrganizationBackend.getOrganizations("admin")
|
OrganizationBackend.getOrganizations("admin")
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
@ -266,6 +277,11 @@ class UserEditPage extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let isKeysGenerated = false;
|
||||||
|
if (this.state.user.accessKey !== "" && this.state.user.accessKey !== "") {
|
||||||
|
isKeysGenerated = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (accountItem.name === "Organization") {
|
if (accountItem.name === "Organization") {
|
||||||
return (
|
return (
|
||||||
<Row style={{marginTop: "10px"}} >
|
<Row style={{marginTop: "10px"}} >
|
||||||
@ -691,6 +707,37 @@ class UserEditPage extends React.Component {
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
);
|
);
|
||||||
|
} else if (accountItem.name === "API key") {
|
||||||
|
return (
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("general:API key"), i18next.t("general:API key - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 1}>
|
||||||
|
{Setting.getLabel(i18next.t("general:Access key"), i18next.t("general:Access key - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Input value={this.state.user.accessKey} disabled={true} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 1}>
|
||||||
|
{Setting.getLabel(i18next.t("general:Secret key"), i18next.t("general:Secret key - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Input value={this.state.user.secretKey} disabled={true} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col span={22} >
|
||||||
|
<Button onClick={() => this.addUserKeys()}>{i18next.t(isKeysGenerated ? "general:update" : "general:generate")}</Button>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
} else if (accountItem.name === "Roles") {
|
} else if (accountItem.name === "Roles") {
|
||||||
return (
|
return (
|
||||||
<Row style={{marginTop: "20px", alignItems: "center"}} >
|
<Row style={{marginTop: "20px", alignItems: "center"}} >
|
||||||
|
@ -45,6 +45,17 @@ export function getUser(owner, name) {
|
|||||||
}).then(res => res.json());
|
}).then(res => res.json());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function addUserKeys(user) {
|
||||||
|
return fetch(`${Setting.ServerUrl}/api/add-user-keys`, {
|
||||||
|
method: "POST",
|
||||||
|
credentials: "include",
|
||||||
|
body: JSON.stringify(user),
|
||||||
|
headers: {
|
||||||
|
"Accept-Language": Setting.getAcceptLanguage(),
|
||||||
|
},
|
||||||
|
}).then(res => res.json());
|
||||||
|
}
|
||||||
|
|
||||||
export function updateUser(owner, name, user) {
|
export function updateUser(owner, name, user) {
|
||||||
const newUser = Setting.deepCopy(user);
|
const newUser = Setting.deepCopy(user);
|
||||||
return fetch(`${Setting.ServerUrl}/api/update-user?id=${owner}/${encodeURIComponent(name)}`, {
|
return fetch(`${Setting.ServerUrl}/api/update-user?id=${owner}/${encodeURIComponent(name)}`, {
|
||||||
|
@ -91,6 +91,7 @@ class AccountTable extends React.Component {
|
|||||||
{name: "Karma", label: i18next.t("user:Karma")},
|
{name: "Karma", label: i18next.t("user:Karma")},
|
||||||
{name: "Ranking", label: i18next.t("user:Ranking")},
|
{name: "Ranking", label: i18next.t("user:Ranking")},
|
||||||
{name: "Signup application", label: i18next.t("general:Signup application")},
|
{name: "Signup application", label: i18next.t("general:Signup application")},
|
||||||
|
{name: "API key", label: i18next.t("general:API key")},
|
||||||
{name: "Roles", label: i18next.t("general:Roles")},
|
{name: "Roles", label: i18next.t("general:Roles")},
|
||||||
{name: "Permissions", label: i18next.t("general:Permissions")},
|
{name: "Permissions", label: i18next.t("general:Permissions")},
|
||||||
{name: "Groups", label: i18next.t("general:Groups")},
|
{name: "Groups", label: i18next.t("general:Groups")},
|
||||||
|
Reference in New Issue
Block a user