casdoor/controllers/account.go

346 lines
9.5 KiB
Go
Raw Normal View History

2022-02-13 23:39:27 +08:00
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
feat: added avatar tailoring and uploading Signed-off-by: Kininaru <shiftregister233@outlook.com> fixed type errors Signed-off-by: Kininaru <shiftregister233@outlook.com> fixed the wrong folder Signed-off-by: Kininaru <shiftregister233@outlook.com> rewrite login check logic, added unix time to avatar url Signed-off-by: Kininaru <shiftregister233@outlook.com> fixed a bug about strconv Signed-off-by: Kininaru <shiftregister233@outlook.com> supported oss Signed-off-by: Kininaru <shiftregister233@outlook.com> disabled oss provide qiniu Signed-off-by: Kininaru <shiftregister233@outlook.com> Fixed avatar url error Signed-off-by: Kininaru <shiftregister233@outlook.com> Fixed avatar length bug Signed-off-by: Kininaru <shiftregister233@outlook.com> Fixed avatar length bug Signed-off-by: Kininaru <shiftregister233@outlook.com> fixed oss.conf Signed-off-by: Kininaru <shiftregister233@outlook.com> Put uploading avatar into UserEditPage Signed-off-by: Kininaru <shiftregister233@outlook.com> removed avatar dir Signed-off-by: Kininaru <shiftregister233@outlook.com> removed avatar in main.go Signed-off-by: Kininaru <shiftregister233@outlook.com> Made CropperDiv a reusable component, and updated README for OSS config Signed-off-by: Kininaru <shiftregister233@outlook.com> Convert ts to js Signed-off-by: Kininaru <shiftregister233@outlook.com> removed ts Signed-off-by: Kininaru <shiftregister233@outlook.com> fix: set avatar link to string 255 Signed-off-by: Kininaru <shiftregister233@outlook.com> fix: updated yarn lock Signed-off-by: Kininaru <shiftregister233@outlook.com> add: Casbin license Signed-off-by: Kininaru <shiftregister233@outlook.com>
2021-03-14 15:50:36 +08:00
//
// 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.
2021-02-11 22:56:08 +08:00
package controllers
import (
"encoding/json"
2021-04-28 19:02:01 +08:00
"fmt"
2021-06-17 00:49:02 +08:00
"strconv"
2022-03-13 00:30:18 +08:00
"strings"
2021-03-20 00:23:37 +08:00
2022-01-20 14:11:46 +08:00
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
2021-02-11 22:56:08 +08:00
)
2021-03-20 10:51:00 +08:00
const (
ResponseTypeLogin = "login"
ResponseTypeCode = "code"
ResponseTypeToken = "token"
ResponseTypeIdToken = "id_token"
ResponseTypeSaml = "saml"
ResponseTypeCas = "cas"
2021-03-20 10:51:00 +08:00
)
2021-03-20 09:11:03 +08:00
type RequestForm struct {
2021-03-15 00:49:16 +08:00
Type string `json:"type"`
2021-02-11 22:56:08 +08:00
Organization string `json:"organization"`
Username string `json:"username"`
Password string `json:"password"`
Name string `json:"name"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
2021-02-11 22:56:08 +08:00
Email string `json:"email"`
Phone string `json:"phone"`
2021-04-28 21:25:58 +08:00
Affiliation string `json:"affiliation"`
2021-12-28 17:48:24 +08:00
IdCard string `json:"idCard"`
Region string `json:"region"`
2021-03-15 00:49:16 +08:00
Application string `json:"application"`
Provider string `json:"provider"`
Code string `json:"code"`
State string `json:"state"`
RedirectUri string `json:"redirectUri"`
Method string `json:"method"`
EmailCode string `json:"emailCode"`
PhoneCode string `json:"phoneCode"`
PhonePrefix string `json:"phonePrefix"`
AutoSignin bool `json:"autoSignin"`
RelayState string `json:"relayState"`
SamlRequest string `json:"samlRequest"`
SamlResponse string `json:"samlResponse"`
2021-02-11 22:56:08 +08:00
}
type Response struct {
Status string `json:"status"`
Msg string `json:"msg"`
Sub string `json:"sub"`
Name string `json:"name"`
2021-02-11 22:56:08 +08:00
Data interface{} `json:"data"`
2021-04-29 19:51:03 +08:00
Data2 interface{} `json:"data2"`
2021-02-11 22:56:08 +08:00
}
type Captcha struct {
Type string `json:"type"`
AppKey string `json:"appKey"`
Scene string `json:"scene"`
CaptchaId string `json:"captchaId"`
CaptchaImage []byte `json:"captchaImage"`
ClientId string `json:"clientId"`
ClientSecret string `json:"clientSecret"`
ClientId2 string `json:"clientId2"`
ClientSecret2 string `json:"clientSecret2"`
SubType string `json:"subType"`
}
2021-08-07 22:02:56 +08:00
// Signup
// @Tag Login API
2021-04-27 22:47:44 +08:00
// @Title Signup
// @Description sign up a new user
// @Param username formData string true "The username to sign up"
2021-02-11 22:56:08 +08:00
// @Param password formData string true "The password"
// @Success 200 {object} controllers.Response The Response object
2021-04-27 22:47:44 +08:00
// @router /signup [post]
func (c *ApiController) Signup() {
if c.GetSessionUsername() != "" {
2021-08-08 11:06:45 +08:00
c.ResponseError("Please sign out first before signing up", c.GetSessionUsername())
2021-02-11 22:56:08 +08:00
return
}
2021-03-20 09:11:03 +08:00
var form RequestForm
2021-02-11 22:56:08 +08:00
err := json.Unmarshal(c.Ctx.Input.RequestBody, &form)
if err != nil {
c.ResponseError(err.Error())
return
2021-02-11 22:56:08 +08:00
}
2021-06-17 00:49:02 +08:00
application := object.GetApplication(fmt.Sprintf("admin/%s", form.Application))
if !application.EnableSignUp {
c.ResponseError("The application does not allow to sign up new account")
return
}
organization := object.GetOrganization(fmt.Sprintf("%s/%s", "admin", form.Organization))
msg := object.CheckUserSignup(application, organization, form.Username, form.Password, form.Name, form.FirstName, form.LastName, form.Email, form.Phone, form.Affiliation)
if msg != "" {
c.ResponseError(msg)
return
}
if application.IsSignupItemVisible("Email") && application.GetSignupItemRule("Email") != "No verification" && form.Email != "" {
2021-06-17 00:49:02 +08:00
checkResult := object.CheckVerificationCode(form.Email, form.EmailCode)
if len(checkResult) != 0 {
c.ResponseError(fmt.Sprintf("Email: %s", checkResult))
2021-06-17 00:49:02 +08:00
return
}
}
2021-06-17 00:49:02 +08:00
var checkPhone string
if application.IsSignupItemVisible("Phone") && form.Phone != "" {
2021-06-17 00:49:02 +08:00
checkPhone = fmt.Sprintf("+%s%s", form.PhonePrefix, form.Phone)
checkResult := object.CheckVerificationCode(checkPhone, form.PhoneCode)
if len(checkResult) != 0 {
c.ResponseError(fmt.Sprintf("Phone: %s", checkResult))
2021-06-17 00:49:02 +08:00
return
}
}
2021-06-17 00:49:02 +08:00
id := util.GenerateId()
if application.GetSignupItemRule("ID") == "Incremental" {
lastUser := object.GetLastUser(form.Organization)
2022-02-14 22:58:13 +08:00
lastIdInt := -1
if lastUser != nil {
lastIdInt = util.ParseInt(lastUser.Id)
}
2021-06-17 00:49:02 +08:00
id = strconv.Itoa(lastIdInt + 1)
}
2021-02-11 22:56:08 +08:00
2021-06-17 00:49:02 +08:00
username := form.Username
if !application.IsSignupItemVisible("Username") {
username = id
2021-02-11 22:56:08 +08:00
}
initScore, err := getInitScore()
if err != nil {
c.ResponseError(fmt.Errorf("get init score failed, error: %w", err).Error())
return
}
2021-06-17 00:49:02 +08:00
user := &object.User{
2021-06-21 10:22:47 +08:00
Owner: form.Organization,
Name: username,
CreatedTime: util.GetCurrentTime(),
Id: id,
Type: "normal-user",
Password: form.Password,
DisplayName: form.Name,
Avatar: organization.DefaultAvatar,
Email: form.Email,
Phone: form.Phone,
Address: []string{},
Affiliation: form.Affiliation,
2021-12-28 17:48:24 +08:00
IdCard: form.IdCard,
Region: form.Region,
Score: initScore,
2021-06-21 10:22:47 +08:00
IsAdmin: false,
IsGlobalAdmin: false,
IsForbidden: false,
2021-11-06 15:52:03 +08:00
IsDeleted: false,
2021-06-21 10:22:47 +08:00
SignupApplication: application.Name,
Properties: map[string]string{},
Karma: 0,
2021-06-17 00:49:02 +08:00
}
2022-03-13 00:30:18 +08:00
if len(organization.Tags) > 0 {
tokens := strings.Split(organization.Tags[0], "|")
if len(tokens) > 0 {
user.Tag = tokens[0]
}
}
if application.GetSignupItemRule("Display name") == "First, last" {
if form.FirstName != "" || form.LastName != "" {
user.DisplayName = fmt.Sprintf("%s %s", form.FirstName, form.LastName)
user.FirstName = form.FirstName
user.LastName = form.LastName
}
}
affected := object.AddUser(user)
2021-12-12 19:59:55 +08:00
if !affected {
c.ResponseError(fmt.Sprintf("Failed to create user, user information is invalid: %s", util.StructToJson(user)))
return
}
2021-06-17 00:49:02 +08:00
2021-12-18 01:08:03 +08:00
object.AddUserToOriginalDatabase(user)
2021-12-12 19:59:55 +08:00
2021-06-20 09:46:06 +08:00
if application.HasPromptPage() {
// The prompt page needs the user to be signed in
c.SetSessionUsername(user.GetId())
2021-06-20 09:46:06 +08:00
}
2021-06-17 00:49:02 +08:00
object.DisableVerificationCode(form.Email)
object.DisableVerificationCode(checkPhone)
record := object.NewRecord(c.Ctx)
record.Organization = application.Organization
record.User = user.Name
util.SafeGoroutine(func() { object.AddRecord(record) })
2022-07-30 17:40:30 +08:00
userId := user.GetId()
2021-06-17 00:49:02 +08:00
util.LogInfo(c.Ctx, "API: [%s] is signed up as new user", userId)
2021-08-08 16:00:19 +08:00
c.ResponseOk(userId)
2021-02-11 22:56:08 +08:00
}
2021-08-07 22:02:56 +08:00
// Logout
2021-02-11 22:56:08 +08:00
// @Title Logout
// @Tag Login API
2021-02-11 22:56:08 +08:00
// @Description logout the current user
// @Success 200 {object} controllers.Response The Response object
// @router /logout [get,post]
2021-02-11 22:56:08 +08:00
func (c *ApiController) Logout() {
user := c.GetSessionUsername()
2021-02-11 22:56:08 +08:00
util.LogInfo(c.Ctx, "API: [%s] logged out", user)
application := c.GetSessionApplication()
c.SetSessionUsername("")
c.SetSessionData(nil)
2021-02-11 22:56:08 +08:00
if application == nil || application.Name == "app-built-in" || application.HomepageUrl == "" {
c.ResponseOk(user)
return
}
c.ResponseOk(user, application.HomepageUrl)
2021-02-11 22:56:08 +08:00
}
2021-08-07 22:02:56 +08:00
// GetAccount
// @Title GetAccount
// @Tag Account API
// @Description get the details of the current account
// @Success 200 {object} controllers.Response The Response object
// @router /get-account [get]
2021-02-11 22:56:08 +08:00
func (c *ApiController) GetAccount() {
2021-05-17 23:25:28 +08:00
userId, ok := c.RequireSignedIn()
if !ok {
2021-02-11 22:56:08 +08:00
return
}
2021-05-17 23:25:28 +08:00
user := object.GetUser(userId)
2021-06-16 00:18:56 +08:00
if user == nil {
2021-08-08 11:06:45 +08:00
c.ResponseError(fmt.Sprintf("The user: %s doesn't exist", userId))
2021-06-16 00:18:56 +08:00
return
}
managedAccounts := c.Input().Get("managedAccounts")
if managedAccounts == "1" {
user = object.ExtendManagedAccountsWithUser(user)
}
2021-11-06 21:14:53 +08:00
organization := object.GetMaskedOrganization(object.GetOrganizationByUser(user))
resp := Response{
Status: "ok",
Sub: user.Id,
Name: user.Name,
Data: user,
Data2: organization,
}
c.Data["json"] = resp
c.ServeJSON()
2021-02-11 22:56:08 +08:00
}
feat: added avatar tailoring and uploading Signed-off-by: Kininaru <shiftregister233@outlook.com> fixed type errors Signed-off-by: Kininaru <shiftregister233@outlook.com> fixed the wrong folder Signed-off-by: Kininaru <shiftregister233@outlook.com> rewrite login check logic, added unix time to avatar url Signed-off-by: Kininaru <shiftregister233@outlook.com> fixed a bug about strconv Signed-off-by: Kininaru <shiftregister233@outlook.com> supported oss Signed-off-by: Kininaru <shiftregister233@outlook.com> disabled oss provide qiniu Signed-off-by: Kininaru <shiftregister233@outlook.com> Fixed avatar url error Signed-off-by: Kininaru <shiftregister233@outlook.com> Fixed avatar length bug Signed-off-by: Kininaru <shiftregister233@outlook.com> Fixed avatar length bug Signed-off-by: Kininaru <shiftregister233@outlook.com> fixed oss.conf Signed-off-by: Kininaru <shiftregister233@outlook.com> Put uploading avatar into UserEditPage Signed-off-by: Kininaru <shiftregister233@outlook.com> removed avatar dir Signed-off-by: Kininaru <shiftregister233@outlook.com> removed avatar in main.go Signed-off-by: Kininaru <shiftregister233@outlook.com> Made CropperDiv a reusable component, and updated README for OSS config Signed-off-by: Kininaru <shiftregister233@outlook.com> Convert ts to js Signed-off-by: Kininaru <shiftregister233@outlook.com> removed ts Signed-off-by: Kininaru <shiftregister233@outlook.com> fix: set avatar link to string 255 Signed-off-by: Kininaru <shiftregister233@outlook.com> fix: updated yarn lock Signed-off-by: Kininaru <shiftregister233@outlook.com> add: Casbin license Signed-off-by: Kininaru <shiftregister233@outlook.com>
2021-03-14 15:50:36 +08:00
2022-08-09 16:50:49 +08:00
// GetUserinfo
// UserInfo
// @Title UserInfo
// @Tag Account API
// @Description return user information according to OIDC standards
// @Success 200 {object} object.Userinfo The Response object
// @router /userinfo [get]
func (c *ApiController) GetUserinfo() {
userId, ok := c.RequireSignedIn()
if !ok {
return
}
scope, aud := c.GetSessionOidc()
host := c.Ctx.Request.Host
resp, err := object.GetUserInfo(userId, scope, aud, host)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = resp
c.ServeJSON()
}
// GetCaptcha ...
// @Tag Login API
// @Title GetCaptcha
// @router /api/get-captcha [get]
func (c *ApiController) GetCaptcha() {
applicationId := c.Input().Get("applicationId")
isCurrentProvider := c.Input().Get("isCurrentProvider")
captchaProvider, err := object.GetCaptchaProviderByApplication(applicationId, isCurrentProvider)
if err != nil {
c.ResponseError(err.Error())
return
}
if captchaProvider != nil {
if captchaProvider.Type == "Default" {
id, img := object.GetCaptcha()
c.ResponseOk(Captcha{Type: captchaProvider.Type, CaptchaId: id, CaptchaImage: img})
return
} else if captchaProvider.Type != "" {
c.ResponseOk(Captcha{
Type: captchaProvider.Type,
SubType: captchaProvider.SubType,
ClientId: captchaProvider.ClientId,
ClientSecret: captchaProvider.ClientSecret,
ClientId2: captchaProvider.ClientId2,
ClientSecret2: captchaProvider.ClientSecret2,
})
return
}
}
c.ResponseOk(Captcha{Type: "none"})
}