feat: 支持手机号登录(演示环境不开放)

1.在个人中心-安全设置中绑手机号后,才支持手机号登录
2.SMS4J(短信聚合框架,轻松集成多家短信服务,解决接入多个短信 SDK 的繁琐流程)
This commit is contained in:
2023-10-27 21:32:25 +08:00
parent 2f2905efdc
commit 4d70bc84db
27 changed files with 780 additions and 126 deletions

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2022-present Charles7c 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.
*/
package top.charles7c.cnadmin.auth.model.request;
import java.io.Serializable;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import lombok.Data;
import io.swagger.v3.oas.annotations.media.Schema;
import org.hibernate.validator.constraints.Length;
import top.charles7c.cnadmin.common.constant.RegexConsts;
/**
* 手机号登录信息
*
* @author Charles7c
* @since 2023/10/26 22:37
*/
@Data
@Schema(description = "手机号登录信息")
public class PhoneLoginRequest implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 手机号
*/
@Schema(description = "手机号", example = "13811111111")
@NotBlank(message = "手机号不能为空")
@Pattern(regexp = RegexConsts.MOBILE, message = "手机号格式错误")
private String phone;
/**
* 验证码
*/
@Schema(description = "验证码", example = "8888")
@NotBlank(message = "验证码不能为空")
@Length(max = 4, message = "验证码非法")
private String captcha;
}

View File

@@ -41,6 +41,15 @@ public interface LoginService {
*/
String accountLogin(String username, String password);
/**
* 手机号登录
*
* @param phone
* 手机号
* @return 令牌
*/
String phoneLogin(String phone);
/**
* 邮箱登录
*

View File

@@ -85,6 +85,14 @@ public class LoginServiceImpl implements LoginService {
return this.login(user);
}
@Override
public String phoneLogin(String phone) {
UserDO user = userService.getByPhone(phone);
CheckUtils.throwIfNull(user, "此手机号未绑定本系统账号");
this.checkUserStatus(user);
return this.login(user);
}
@Override
public String emailLogin(String email) {
UserDO user = userService.getByEmail(email);

View File

@@ -40,6 +40,16 @@ public interface UserMapper extends DataPermissionMapper<UserDO> {
@Select("SELECT * FROM `sys_user` WHERE `username` = #{username}")
UserDO selectByUsername(@Param("username") String username);
/**
* 根据手机号查询
*
* @param phone
* 手机号
* @return 用户信息
*/
@Select("SELECT * FROM `sys_user` WHERE `phone` = #{phone}")
UserDO selectByPhone(@Param("phone") String phone);
/**
* 根据邮箱查询
*

View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 2022-present Charles7c 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.
*/
package top.charles7c.cnadmin.system.model.request;
import java.io.Serializable;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import lombok.Data;
import io.swagger.v3.oas.annotations.media.Schema;
import org.hibernate.validator.constraints.Length;
import top.charles7c.cnadmin.common.constant.RegexConsts;
/**
* 用户手机号修改信息
*
* @author Charles7c
* @since 2023/10/27 20:11
*/
@Data
@Schema(description = "用户手机号修改信息")
public class UserPhoneUpdateRequest implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 新手机号
*/
@Schema(description = "新手机号", example = "13811111111")
@NotBlank(message = "新手机号不能为空")
@Pattern(regexp = RegexConsts.MOBILE, message = "手机号格式错误")
private String newPhone;
/**
* 验证码
*/
@Schema(description = "验证码", example = "8888")
@NotBlank(message = "验证码不能为空")
@Length(max = 4, message = "验证码非法")
private String captcha;
/**
* 当前密码(加密后)
*/
@Schema(description = "当前密码(加密后)",
example = "SYRLSszQGcMv4kP2Yolou9zf28B9GDakR9u91khxmR7V++i5A384kwnNZxqgvT6bjT4zqpIDuMFLWSt92hQJJA==")
@NotBlank(message = "当前密码不能为空")
private String currentPassword;
}

View File

@@ -79,6 +79,18 @@ public interface UserService extends BaseService<UserVO, UserDetailVO, UserQuery
*/
void updatePassword(String oldPassword, String newPassword, Long id);
/**
* 修改手机号
*
* @param newPhone
* 新手机号
* @param currentPassword
* 当前密码
* @param id
* ID
*/
void updatePhone(String newPhone, String currentPassword, Long id);
/**
* 修改邮箱
*
@@ -118,6 +130,15 @@ public interface UserService extends BaseService<UserVO, UserDetailVO, UserQuery
*/
UserDO getByUsername(String username);
/**
* 根据手机号查询
*
* @param phone
* 手机号
* @return 用户信息
*/
UserDO getByPhone(String phone);
/**
* 根据邮箱查询
*

View File

@@ -210,6 +210,17 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserVO,
.set(UserDO::getPwdResetTime, now).eq(UserDO::getId, id).update();
}
@Override
public void updatePhone(String newPhone, String currentPassword, Long id) {
UserDO user = super.getById(id);
CheckUtils.throwIfNotEqual(SecureUtils.md5Salt(currentPassword, id.toString()), user.getPassword(), "当前密码错误");
Long count = baseMapper.lambdaQuery().eq(UserDO::getPhone, newPhone).count();
CheckUtils.throwIf(count > 0, "手机号已绑定其他账号,请更换其他手机号");
CheckUtils.throwIfEqual(newPhone, user.getPhone(), "新手机号不能与当前手机号相同");
// 更新手机号
baseMapper.lambdaUpdate().set(UserDO::getPhone, newPhone).eq(UserDO::getId, id).update();
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateEmail(String newEmail, String currentPassword, Long id) {
@@ -244,6 +255,11 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserVO,
return baseMapper.selectByUsername(username);
}
@Override
public UserDO getByPhone(String phone) {
return baseMapper.selectByPhone(phone);
}
@Override
public UserDO getByEmail(String email) {
return baseMapper.selectByEmail(email);