From 78418429c10db7a11620c296030fee53853ac223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?= <41315874+fumiama@users.noreply.github.com> Date: Sat, 18 Mar 2023 17:14:13 +0800 Subject: [PATCH] finish SecureSetting --- backend/api/main.go | 60 +++++++++++++++++++ backend/api/upload.go | 9 +-- backend/api/user.go | 50 +++++++++++++--- frontend/vben/src/api/sys/model/userModel.ts | 16 +++++ frontend/vben/src/api/sys/user.ts | 36 ++++++++++- frontend/vben/src/store/modules/user.ts | 4 +- .../src/views/page/settings/contact/index.vue | 17 ++++-- .../views/page/settings/password/index.vue | 23 ++++--- 8 files changed, 186 insertions(+), 29 deletions(-) diff --git a/backend/api/main.go b/backend/api/main.go index ecc50b7..7fe8d4b 100644 --- a/backend/api/main.go +++ b/backend/api/main.go @@ -84,6 +84,66 @@ func init() { } writeresult(w, codeSuccess, n, messageOk, typeSuccess) }} + + apimap["/api/setPassword"] = &apihandler{"POST", func(w http.ResponseWriter, r *http.Request) { + type setpasswordbody struct { + Token string `json:"token"` + Password string `json:"password"` + } + token := r.Header.Get("Authorization") + user := usertokens.Get(token) + if user == nil { + writeresult(w, codeError, nil, errInvalidToken.Error(), typeError) + return + } + var body setpasswordbody + defer r.Body.Close() + err := json.NewDecoder(r.Body).Decode(&body) + if err != nil { + writeresult(w, codeError, nil, err.Error(), typeError) + return + } + err = setUserPassword(*user.ID, body.Token, body.Password) + if err != nil { + writeresult(w, codeError, nil, err.Error(), typeError) + return + } + type message struct { + M string `json:"msg"` + } + writeresult(w, codeSuccess, &message{M: "成功, 请重新登录"}, messageOk, typeSuccess) + _ = logout(token) + }} + + apimap["/api/setContact"] = &apihandler{"POST", func(w http.ResponseWriter, r *http.Request) { + type setcontactbody struct { + Token string `json:"token"` + Contact string `json:"contact"` + } + token := r.Header.Get("Authorization") + user := usertokens.Get(token) + if user == nil { + writeresult(w, codeError, nil, errInvalidToken.Error(), typeError) + return + } + var body setcontactbody + defer r.Body.Close() + err := json.NewDecoder(r.Body).Decode(&body) + if err != nil { + writeresult(w, codeError, nil, err.Error(), typeError) + return + } + err = setUserContact(*user.ID, body.Token, body.Contact) + if err != nil { + writeresult(w, codeError, nil, err.Error(), typeError) + return + } + user.Cont = hideContact(body.Contact) + type message struct { + M string `json:"msg"` + } + writeresult(w, codeSuccess, &message{M: "成功, 已将消息报告给课程组长"}, messageOk, typeSuccess) + }} } // Handler serves all backend /api call diff --git a/backend/api/upload.go b/backend/api/upload.go index f7df0ec..2e4b10b 100644 --- a/backend/api/upload.go +++ b/backend/api/upload.go @@ -7,6 +7,7 @@ import ( "os" "strconv" "strings" + "time" "github.com/fumiama/imgsz" "github.com/sirupsen/logrus" @@ -69,24 +70,24 @@ func UploadHandler(w http.ResponseWriter, r *http.Request) { writeresult(w, codeError, nil, err.Error(), typeError) return } - avf := userf + "avatar." + format + avf := userf + "avatar" + time.Now().Format("_20060102_15_04_05") + "." + format err = os.WriteFile(avf, data, 0644) if err != nil { writeresult(w, codeError, nil, err.Error(), typeError) return } - err = global.UserDB.UpdateUserInfo(*user.ID, "", avf[6:], "") + /*err = global.UserDB.UpdateUserInfo(*user.ID, "", avf[6:], "") if err != nil { writeresult(w, codeError, nil, err.Error(), typeError) return } + user.Avtr = avf[6:] + usertokens.Set(token, user)*/ writeresult(w, codeSuccess, &upload{ Message: messageOk, Code: codeSuccess, URL: avf[6:], }, messageOk, typeSuccess) - user.Avtr = avf[6:] - usertokens.Set(token, user) logrus.Infoln("[file.UploadHandler] save avatar to", avf[6:]) return } diff --git a/backend/api/user.go b/backend/api/user.go index e57fd31..cbc5047 100644 --- a/backend/api/user.go +++ b/backend/api/user.go @@ -1,10 +1,13 @@ package api import ( + "crypto/md5" + "encoding/hex" "errors" "strings" "time" + base14 "github.com/fumiama/go-base16384" "github.com/fumiama/paper-manager/backend/global" ) @@ -29,12 +32,7 @@ type getUserInfoResult struct { Contact string `json:"contact"` } -func getUserInfo(token string) (*getUserInfoResult, error) { - user := usertokens.Get(token) - if user == nil { - return nil, errInvalidToken - } - cont := user.Cont +func hideContact(cont string) string { if len(cont) > 7 { sb := strings.Builder{} sb.WriteString(cont[:3]) @@ -42,7 +40,15 @@ func getUserInfo(token string) (*getUserInfoResult, error) { sb.WriteByte('*') } sb.WriteString(cont[len(cont)-4:]) - cont = sb.String() + return sb.String() + } + return cont +} + +func getUserInfo(token string) (*getUserInfoResult, error) { + user := usertokens.Get(token) + if user == nil { + return nil, errInvalidToken } return &getUserInfoResult{ UserID: *user.ID, @@ -59,7 +65,7 @@ func getUserInfo(token string) (*getUserInfoResult, error) { Roles: []role{{RoleName: user.Role.Nick(), Value: user.Role.String()}}, Date: time.Unix(user.Date, 0).Format(chineseDateLayout), Last: time.Unix(user.Last, 0).Format(chineseDateLayout), - Contact: cont, + Contact: hideContact(user.Cont), }, nil } @@ -80,3 +86,31 @@ func getUsersCount(token string) (int, error) { } return global.UserDB.GetUsersCount() } + +func setUserPassword(id int, token, npwd string) error { + user, err := global.UserDB.GetUserByID(id) + if err != nil { + return err + } + h := md5.New() + h.Write(base14.StringToBytes(user.Pswd)) + h.Write(base14.StringToBytes(npwd)) + if token != hex.EncodeToString(h.Sum(make([]byte, 0, 16))) { + return errInvalidToken + } + return global.UserDB.UpdateUserPassword(id, npwd) +} + +func setUserContact(id int, token, ncont string) error { + user, err := global.UserDB.GetUserByID(id) + if err != nil { + return err + } + h := md5.New() + h.Write(base14.StringToBytes(user.Cont)) + h.Write(base14.StringToBytes(ncont)) + if token != hex.EncodeToString(h.Sum(make([]byte, 0, 16))) { + return errInvalidToken + } + return global.UserDB.UpdateUserContact(id, ncont) +} diff --git a/frontend/vben/src/api/sys/model/userModel.ts b/frontend/vben/src/api/sys/model/userModel.ts index cecb453..dd1bf2c 100644 --- a/frontend/vben/src/api/sys/model/userModel.ts +++ b/frontend/vben/src/api/sys/model/userModel.ts @@ -14,6 +14,22 @@ export interface ResetPasswordParams { mobile: string } +/** + * @description: Set password interface parameters + */ +export interface SetPasswordParams { + token: string + password: string +} + +/** + * @description: Set Contact interface parameters + */ +export interface SetContactParams { + token: string + contact: string +} + /** * @description: Register interface parameters */ diff --git a/frontend/vben/src/api/sys/user.ts b/frontend/vben/src/api/sys/user.ts index d266f79..5d00b48 100644 --- a/frontend/vben/src/api/sys/user.ts +++ b/frontend/vben/src/api/sys/user.ts @@ -4,6 +4,8 @@ import { LoginResultModel, GetUserInfoModel, ResetPasswordParams, + SetPasswordParams, + SetContactParams, RegisterParams, ResetPasswordResultModel, RegisterResultModel, @@ -17,6 +19,8 @@ enum Api { Login = '/login', Logout = '/logout', ResetPassword = '/resetPassword', + SetPassword = '/setPassword', + SetContact = '/setContact', Register = '/register', GetUserInfo = '/getUserInfo', GetUsersCount = '/getUsersCount', @@ -54,6 +58,36 @@ export function resetPasswordApi(params: ResetPasswordParams, mode: ErrorMessage ) } +/** + * @description: set password api, borrowing the ResetPasswordResultModel as they're the same + */ +export function setPasswordApi(params: SetPasswordParams, mode: ErrorMessageMode = 'modal') { + return defHttp.post( + { + url: Api.SetPassword, + params, + }, + { + errorMessageMode: mode, + }, + ) +} + +/** + * @description: set contact api, borrowing the ResetPasswordResultModel as they're the same + */ +export function setContactApi(params: SetContactParams, mode: ErrorMessageMode = 'modal') { + return defHttp.post( + { + url: Api.SetContact, + params, + }, + { + errorMessageMode: mode, + }, + ) +} + /** * @description: register api */ @@ -95,7 +129,7 @@ export function getUsersCount() { }*/ export function doLogout() { - return defHttp.get({ url: Api.Logout }) + return defHttp.get({ url: Api.Logout }, { errorMessageMode: 'none' }) } /*export function testRetry() { diff --git a/frontend/vben/src/store/modules/user.ts b/frontend/vben/src/store/modules/user.ts index 49dc38e..8320ca4 100644 --- a/frontend/vben/src/store/modules/user.ts +++ b/frontend/vben/src/store/modules/user.ts @@ -143,9 +143,7 @@ export const useUserStore = defineStore({ if (this.getToken) { try { await doLogout() - } catch { - console.log('注销Token失败') - } + } catch {} } this.setToken(undefined) this.setSessionTimeout(false) diff --git a/frontend/vben/src/views/page/settings/contact/index.vue b/frontend/vben/src/views/page/settings/contact/index.vue index 586c510..fdb3706 100644 --- a/frontend/vben/src/views/page/settings/contact/index.vue +++ b/frontend/vben/src/views/page/settings/contact/index.vue @@ -13,6 +13,9 @@ import { defineComponent } from 'vue' import { PageWrapper } from '/@/components/Page' import { BasicForm, useForm } from '/@/components/Form' + import { setContactApi } from '/@/api/sys/user' + import { useMessage } from '/@/hooks/web/useMessage' + import md5 from 'md5' import { formSchema } from './contact.data' export default defineComponent({ @@ -27,16 +30,18 @@ schemas: formSchema, }) + const { createMessage } = useMessage() + async function handleSubmit() { try { const values = await validate() const { contactOld, contactNew } = values - - // TODO custom api - console.log(contactOld, contactNew) - // const { router } = useRouter() - // router.push(pageEnum.BASE_LOGIN) - } catch (error) {} + const { msg } = await setContactApi({ + token: md5(contactOld + contactNew), + contact: contactNew, + }) + createMessage.success(msg) + } catch (_) {} } return { register, resetFields, handleSubmit } diff --git a/frontend/vben/src/views/page/settings/password/index.vue b/frontend/vben/src/views/page/settings/password/index.vue index 7103591..17e9ad0 100644 --- a/frontend/vben/src/views/page/settings/password/index.vue +++ b/frontend/vben/src/views/page/settings/password/index.vue @@ -13,12 +13,18 @@ import { defineComponent } from 'vue' import { PageWrapper } from '/@/components/Page' import { BasicForm, useForm } from '/@/components/Form' - + import { setPasswordApi } from '/@/api/sys/user' + import { useMessage } from '/@/hooks/web/useMessage' + import { useUserStore } from '/@/store/modules/user' import { formSchema } from './pwd.data' + import md5 from 'md5' + export default defineComponent({ name: 'ChangePassword', components: { BasicForm, PageWrapper }, setup() { + const { createMessage } = useMessage() + const [register, { validate, resetFields }] = useForm({ size: 'large', baseColProps: { span: 24 }, @@ -31,12 +37,15 @@ try { const values = await validate() const { passwordOld, passwordNew } = values - - // TODO custom api - console.log(passwordOld, passwordNew) - // const { router } = useRouter() - // router.push(pageEnum.BASE_LOGIN) - } catch (error) {} + const { msg } = await setPasswordApi({ + token: md5(passwordOld + passwordNew), + password: passwordNew, + }) + createMessage.success(msg) + useUserStore().logout(true) + } catch (error) { + createMessage.error((error as unknown as Error).message) + } } return { register, resetFields, handleSubmit }