liujie
11 小时以前 fddf3d913d47f391f84f9e460cb76d427ef02c44
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package com.ruoyi.auth.service;
 
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.auth.enums.SmsSceneEnum;
import com.ruoyi.common.core.constant.SecurityConstants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.enums.UserStatus;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.system.api.RemoteAccountUserService;
import com.ruoyi.system.api.domain.AccountMember;
import com.ruoyi.system.api.model.AccountResetPasswordRequest;
 
/**
 * 忘记密码(重置密码)编排服务
 *
 * 身份校验:登录手机号 + 短信验证码(scene=reset);校验通过后由 ruoyi-user 侧 BCrypt 加密落库。
 *
 * @author hugray
 */
@Service
public class PasswordResetService
{
    private static final Logger log = LoggerFactory.getLogger(PasswordResetService.class);
 
    /** 手机号正则 */
    private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");
 
    @Autowired
    private SmsCodeService smsCodeService;
 
    @Autowired
    private RemoteAccountUserService remoteAccountUserService;
 
    /**
     * 重置密码
     *
     * @param phone 手机号(账号标识)
     * @param code 短信验证码
     * @param password 新密码(明文)
     */
    public void resetPassword(String phone, String code, String password)
    {
        // STEP 1: 入参兜底校验(Controller 已校验,此处做服务层兜底)
        if (StringUtils.isEmpty(phone) || !PHONE_PATTERN.matcher(phone).matches())
        {
            throw new ServiceException("请输入正确手机号");
        }
        if (StringUtils.isEmpty(code))
        {
            throw new ServiceException("请输入验证码");
        }
        if (StringUtils.isEmpty(password))
        {
            throw new ServiceException("请输入新密码");
        }
 
        // STEP 2: 先查询会员与状态,避免无谓消费验证码(与 phoneCodeLogin 口径一致)
        AccountMember member = getRegisteredMember(phone);
        checkMemberStatus(member);
 
        // STEP 3: 校验并消费短信验证码(scene=reset,一次性)
        smsCodeService.verifyAndConsume(phone, SmsSceneEnum.RESET.getCode(), code);
 
        // STEP 4: 调用 ruoyi-user 内部接口落库(服务内 BCrypt 加密,只更新 password 一列)
        AccountResetPasswordRequest request = new AccountResetPasswordRequest();
        request.setPhone(phone);
        request.setPassword(password);
        R<Boolean> resetResult = remoteAccountUserService.resetPassword(request, SecurityConstants.INNER);
        if (R.FAIL == resetResult.getCode())
        {
            throw new ServiceException(resetResult.getMsg());
        }
        log.info("[PASSWORD_RESET] reset success, phone={}", maskPhone(phone));
    }
 
    /**
     * 按手机号查询会员,不存在时抛出「未注册」业务异常
     *
     * @param phone 手机号
     * @return 会员信息
     */
    private AccountMember getRegisteredMember(String phone)
    {
        R<AccountMember> memberResult = remoteAccountUserService.getMemberByPhone(phone, SecurityConstants.INNER);
        if (R.FAIL == memberResult.getCode())
        {
            throw new ServiceException(memberResult.getMsg());
        }
        AccountMember member = memberResult.getData();
        if (StringUtils.isNull(member))
        {
            throw new ServiceException("该手机号未注册,请先注册");
        }
        return member;
    }
 
    /**
     * 校验会员状态,停用账号拒绝重置密码
     *
     * @param member C端会员信息
     */
    private void checkMemberStatus(AccountMember member)
    {
        if (UserStatus.DISABLE.getCode().equals(member.getStatus()))
        {
            throw new ServiceException("账号已停用,请联系管理员");
        }
    }
 
    /**
     * 手机号脱敏,形如 138****0000
     */
    private String maskPhone(String phone)
    {
        if (StringUtils.isEmpty(phone) || phone.length() < 7)
        {
            return phone;
        }
        return phone.substring(0, 3) + "****" + phone.substring(phone.length() - 4);
    }
}