core: Support change password (#117)

This commit is contained in:
qianmoQ 2022-11-04 21:56:22 +08:00 committed by GitHub
commit 983866063e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 208 additions and 4 deletions

View File

@ -0,0 +1,22 @@
package io.edurt.datacap.server.body;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import javax.validation.constraints.NotBlank;
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class UserPasswordBody
{
@NotBlank
private String oldPassword;
@NotBlank
private String newPassword;
@NotBlank
private String confirmPassword;
}

View File

@ -13,6 +13,8 @@ public enum ServiceState
USER_UNAUTHORIZED(4003, "Insufficient current user permissions"),
USER_EXISTS(4004, "User exists"),
USER_BAD_CREDENTIALS(4005, "The account or password is incorrect"),
USER_PASSWORD_INCORRECT(4006, "The user password is incorrect"),
USER_PASSWORD_DIFFERENT(4007, "Two passwords are different"),
REQUEST_EXCEPTION(5000, "The request is abnormal");
private Integer code;

View File

@ -1,10 +1,14 @@
package io.edurt.datacap.server.controller.user;
import io.edurt.datacap.server.body.UserPasswordBody;
import io.edurt.datacap.server.common.Response;
import io.edurt.datacap.server.entity.UserEntity;
import io.edurt.datacap.server.service.UserService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@ -24,4 +28,10 @@ public class UserController
{
return this.userService.info(id);
}
@PutMapping(value = "changePassword")
public Response<Long> changePassword(@Validated @RequestBody UserPasswordBody configure)
{
return this.userService.changePassword(configure);
}
}

View File

@ -1,5 +1,6 @@
package io.edurt.datacap.server.service;
import io.edurt.datacap.server.body.UserPasswordBody;
import io.edurt.datacap.server.common.JwtResponse;
import io.edurt.datacap.server.common.Response;
import io.edurt.datacap.server.entity.UserEntity;
@ -11,4 +12,6 @@ public interface UserService
Response<JwtResponse> authenticate(UserEntity configure);
Response<UserEntity> info(Long userId);
Response<Long> changePassword(UserPasswordBody configure);
}

View File

@ -1,5 +1,6 @@
package io.edurt.datacap.server.service.impl;
import io.edurt.datacap.server.body.UserPasswordBody;
import io.edurt.datacap.server.common.JwtResponse;
import io.edurt.datacap.server.common.Response;
import io.edurt.datacap.server.common.ServiceState;
@ -92,4 +93,23 @@ public class UserServiceImpl
}
return Response.success(this.userRepository.findById(userId).get());
}
@Override
public Response<Long> changePassword(UserPasswordBody configure)
{
Optional<UserEntity> userOptional = this.userRepository.findById(UserDetailsService.getUser().getId());
if (!userOptional.isPresent()) {
return Response.failure(ServiceState.USER_NOT_FOUND);
}
UserEntity user = userOptional.get();
if (!encoder.matches(configure.getOldPassword(), user.getPassword())) {
return Response.failure(ServiceState.USER_PASSWORD_INCORRECT);
}
if (!configure.getNewPassword().equals(configure.getConfirmPassword())) {
return Response.failure(ServiceState.USER_PASSWORD_DIFFERENT);
}
user.setPassword(encoder.encode(configure.getNewPassword()));
this.userRepository.save(user);
return Response.success(user.getId());
}
}

View File

@ -1,3 +1,8 @@
export default {
profile: 'Public profile'
profile: 'Public profile',
security: 'Security',
changePassword: 'Change the password',
oldPassword: 'Old password',
newPassword: 'New password',
confirmPassword: 'Confirm password'
}

View File

@ -1,3 +1,8 @@
export default {
profile: '个人资料'
profile: '个人资料',
security: '安全设置',
changePassword: '修改密码',
oldPassword: '旧密码',
newPassword: '新密码',
confirmPassword: '确认密码'
}

View File

@ -0,0 +1,6 @@
export interface UserPassword
{
oldPassword: string;
newPassword: string;
confirmPassword: string;
}

View File

@ -95,6 +95,10 @@ const routes: Array<RouteRecordRaw> = [
{
path: 'public',
component: () => import("../views/pages/profile/ProfilePublic.vue")
},
{
path: 'security',
component: () => import("../views/pages/profile/ProfileSecurity.vue")
}
]
}

View File

@ -1,5 +1,6 @@
import {HttpCommon} from "@/common/HttpCommon";
import {ResponseModel} from "@/model/ResponseModel";
import {UserPassword} from "@/model/UserPassword";
const baseUrl = "/api/v1/user";
@ -9,6 +10,11 @@ class UserService
{
return new HttpCommon().get(baseUrl);
}
changePassword(configure: UserPassword): Promise<ResponseModel>
{
return new HttpCommon().put(baseUrl + '/changePassword', configure);
}
}
export default new UserService();

View File

@ -7,7 +7,7 @@
<a-spin :spinning="loading">
<a-layout style="background-color: #ffffff">
<a-layout-content>
<a-form :model="formState" v-bind="layout" @finish="onFinish">
<a-form :model="formState" v-bind="layout">
<a-form-item :name="['name']" :label="$t('common.username')">
<span>{{ formState.username }}</span>
</a-form-item>

View File

@ -0,0 +1,111 @@
<template>
<a-layout-content>
<a-card>
<template #title>
{{ $t('setting.security') }}
</template>
<a-spin :spinning="loading">
<a-layout style="background-color: #ffffff">
<a-layout-content>
<a-form :model="formState" v-bind="layout">
<a-form-item :name="['password']" :label="$t('common.password')">
<a-button type="link" style="float: right;" @click="handlerShowModal('password')">
{{ $t('setting.changePassword') }}
</a-button>
</a-form-item>
</a-form>
</a-layout-content>
<a-layout-sider style="background-color: #ffffff; margin-left: 60px;">
</a-layout-sider>
</a-layout>
</a-spin>
</a-card>
<a-modal v-if="changePasswordVisible" v-model:visible="changePasswordVisible"
:closable="false" :mask-closable="false"
:title="$t('setting.changePassword')">
<a-form :model="formState" :label-col="{ span: 5 }">
<a-form-item :label="$t('setting.oldPassword')" name="oldPassword">
<a-input type="password" v-model:value="formState.oldPassword"/>
</a-form-item>
<a-form-item :label="$t('setting.newPassword')" name="newPassword">
<a-input type="password" v-model:value="formState.newPassword"/>
</a-form-item>
<a-form-item :label="$t('setting.confirmPassword')" name="confirmPassword">
<a-input type="password" v-model:value="formState.confirmPassword"/>
</a-form-item>
</a-form>
<template #footer>
<a-button danger @click="handlerCloseModal('password')">{{ $t('common.cancel') }}</a-button>
<a-button type="primary" :loading="loading" @click="handlerChangePassword()">{{ $t('common.save') }}</a-button>
</template>
</a-modal>
</a-layout-content>
</template>
<script lang="ts">
import {defineComponent, reactive} from 'vue';
import UserService from "@/services/UserService";
import {UserPassword} from "@/model/UserPassword";
import {message} from "ant-design-vue";
import Common from "@/common/Common";
import router from "@/router";
const layout = {
labelCol: {span: 8},
wrapperCol: {span: 16},
};
export default defineComponent({
setup()
{
const formState = reactive<UserPassword>({
confirmPassword: '',
newPassword: '',
oldPassword: ''
});
return {
formState
}
},
data()
{
return {
changePasswordVisible: false,
loading: false,
layout
}
},
methods: {
handlerShowModal(type: string)
{
if (type === 'password') {
this.changePasswordVisible = true;
}
},
handlerCloseModal(type: string)
{
if (type === 'password') {
this.changePasswordVisible = false;
}
},
handlerChangePassword()
{
this.loading = true;
UserService.changePassword(this.formState)
.then((response) => {
if (response.status) {
message.success('Success');
localStorage.removeItem(Common.token);
this.changePasswordVisible = false;
router.push('/auth/signin');
}
else {
message.error(response.message);
}
})
.finally(() => {
this.loading = false;
});
}
}
});
</script>

View File

@ -4,7 +4,9 @@
<a-card :bodyStyle="{'text-align': 'center'}">
<a-card-meta>
<template #title>
<a-avatar style="background-color: #87d068">{{ username }}</a-avatar>
<router-link to="/profile/index">
<a-avatar style="background-color: #87d068">{{ username }}</a-avatar>
</router-link>
</template>
<template #description>{{ username }}</template>
</a-card-meta>
@ -18,6 +20,14 @@
{{ $t('setting.profile') }}
</router-link>
</a-menu-item>
<a-menu-item key="security">
<template #icon>
<security-scan-outlined/>
</template>
<router-link to="/profile/security">
{{ $t('setting.security') }}
</router-link>
</a-menu-item>
</a-menu>
</a-card>
</template>