liusheng
2024-05-16 2f13f59f023fba63aa993172d48c14bcaaafb233
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
package com.ruoyi.framework.web.service;
 
import javax.annotation.Resource;
 
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.exception.user.WxOpenIDNotFindException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.wxopenidConfig.WxOpenIDAuthenticationToken;
import com.ruoyi.system.mapper.SysUserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.exception.user.CaptchaException;
import com.ruoyi.common.exception.user.CaptchaExpireException;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysUserService;
 
/**
 * 登录校验方法
 *
 * @author ruoyi
 */
@Component
public class SysLoginService {
    @Autowired
    private TokenService tokenService;
 
    @Resource
    private AuthenticationManager authenticationManager;
 
    @Autowired
    private RedisCache redisCache;
 
    @Autowired
    private ISysUserService userService;
 
    @Autowired
    private ISysConfigService configService;
 
 
    @Autowired
    private SysUserMapper sysUserMapper;
 
    /**
     * 登录验证
     *
     * @param username 用户名
     * @param password 密码
     * @param code     验证码
     * @param uuid     唯一标识
     * @return 结果
     */
    public String login(String username, String password, String code, String uuid, String openId, String dingUserId) {
        //免登
        if (StringUtils.isNotEmpty(dingUserId)) {
            SysUser sysUser = sysUserMapper.selectUserByDingUserId(dingUserId);
            LoginUser loginUser = new LoginUser();
            loginUser.setUserId(sysUser.getUserId());
            loginUser.setDeptId(sysUser.getDeptId());
            loginUser.setUser(sysUser);
            return tokenService.createToken(loginUser);
        }
 
        SysUser sysUser = sysUserMapper.selectUserByUserName(username);
        if (sysUser.getErrorNums() >= 3) {
            //校验失败次数
            throw new BaseException("你的密码输入错误次数过多,请联系管理员处理");
        }
 
        boolean captchaOnOff = configService.selectCaptchaOnOff();
        // 验证码开关
        if (captchaOnOff) {
            validateCaptcha(username, code, uuid);
        }
        // 用户验证
        Authentication authentication = null;
        try {
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
        } catch (Exception e) {
            if (e instanceof BadCredentialsException) {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                sysUserMapper.updateErrorNums(sysUser);
                throw new UserPasswordNotMatchException();
            } else {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
                throw new ServiceException(e.getMessage());
            }
        }
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
 
        SysUser user = loginUser.getUser();
        //更新openid
        String userOpenId = user.getOpenId();
 
        if (StringUtils.isEmpty(openId)) {
            recordLoginInfo(loginUser.getUserId());
        } else {
            if (StringUtils.isNotEmpty(userOpenId)) {
                //当本次登录的微信OPENID不等于第一次绑定的微信OPENID就不允许登录,防止同一个账号多微信登录
                if (!userOpenId.equals(openId)) {
                    AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, "该账户已经绑定其他设备,须先解除绑定再登录,请跟系统管理员联系!"));
                    throw new ServiceException("该账户已经绑定其他设备,须先解除绑定再登录,请跟系统管理员联系!");
                } else {
                    recordLoginInfo(loginUser.getUserId());
                }
            } else {
                recordLoginInfo(loginUser.getUserId(), openId);
            }
        }
        //清除失败次数
        sysUserMapper.cleanErrorNums(username);
        // 生成token
        return tokenService.createToken(loginUser);
    }
 
    /**
     * 校验验证码
     *
     * @param username 用户名
     * @param code     验证码
     * @param uuid     唯一标识
     * @return 结果
     */
    public void validateCaptcha(String username, String code, String uuid) {
        String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
        String captcha = redisCache.getCacheObject(verifyKey);
        redisCache.deleteObject(verifyKey);
        if (captcha == null) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
            throw new CaptchaExpireException();
        }
        if (!code.equalsIgnoreCase(captcha)) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
            throw new CaptchaException();
        }
    }
 
    /**
     * 微信OpenID登录验证
     *
     * @param openid 微信OpenID
     * @return 结果
     */
 
    public AjaxResult wxopenidLogin(String openid) {
 
        // 用户验证
        Authentication authentication = null;
        try {
 
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager.authenticate(new WxOpenIDAuthenticationToken(openid));
        } catch (Exception e) {
 
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(openid, Constants.LOGIN_FAIL, e.getMessage()));
            throw new WxOpenIDNotFindException();
 
        }
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(openid, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        AjaxResult ajax = AjaxResult.success();
 
        // 生成token
        String token = tokenService.createToken(loginUser);
        ajax.put(Constants.TOKEN, token);
        return ajax;
    }
 
    /**
     * 记录登录信息
     *
     * @param userId 用户ID
     */
    public void recordLoginInfo(Long userId) {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
        sysUser.setLoginDate(DateUtils.getNowDate());
        userService.updateUserProfile(sysUser);
    }
 
 
    public void recordLoginInfo(Long userId, String openId) {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setOpenId(openId);
        sysUser.setLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
        sysUser.setLoginDate(DateUtils.getNowDate());
        userService.updateUserProfile(sysUser);
    }
 
}