zhizhijie
13 小时以前 fbc1c1590e7e81a550beb50c7cf65c663c7c5b41
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
package com.trafficaudit.security.controller;
 
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.trafficaudit.common.Result;
import com.trafficaudit.security.captcha.CaptchaService;
import com.trafficaudit.security.utils.JwtUtils;
import com.trafficaudit.system.entity.User;
import com.trafficaudit.system.mapper.UserMapper;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;
 
import org.springframework.beans.factory.annotation.Value;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
@RestController
@RequestMapping("/api/auth")
public class LoginController {
 
    @Resource
    private JwtUtils jwtUtils;
 
    @Resource
    private CaptchaService captchaService;
 
    @Resource
    private UserMapper userMapper;
 
    @Resource
    private PasswordEncoder passwordEncoder;
 
    @Value("${app.captcha.required:true}")
    private boolean captchaRequired;
 
    @PostMapping("/login")
    public Result<Map<String, Object>> login(@RequestBody Map<String, Object> params) {
        String username = (String) params.get("username");
        String password = (String) params.get("password");
        String captchaId = (String) params.get("captchaId");
        List<String> clickIds = strList(params.get("captchaClickIds"));
 
        if (captchaRequired) {
            CaptchaService.ConsumeResult cr = captchaService.consume(captchaId, clickIds);
            if (cr == CaptchaService.ConsumeResult.NOT_FOUND) {
                return Result.error(4002, "验证码不存在或已过期,请刷新重试");
            }
            if (cr == CaptchaService.ConsumeResult.NOT_VERIFIED) {
                return Result.error(4003, "请先完成行为验证");
            }
            if (cr == CaptchaService.ConsumeResult.WRONG) {
                return Result.error(4001, "行为验证未通过,请重新验证");
            }
        }
 
        if (username == null || username.trim().isEmpty() || password == null || password.isEmpty()) {
            return Result.error(401, "用户名或密码错误");
        }
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
                .eq(User::getUsername, username.trim()));
        if (user == null || !Integer.valueOf(1).equals(user.getStatus())) {
            return Result.error(401, "用户名或密码错误");
        }
        String encoded = user.getPassword();
        boolean ok;
        try {
            ok = encoded != null && passwordEncoder.matches(password, encoded);
        } catch (IllegalArgumentException e) {
            // 库中密码不是合法 BCrypt 时回退为明文对比(避免旧数据无法登录)
            ok = encoded != null && encoded.equals(password);
        }
        if (!ok) {
            return Result.error(401, "用户名或密码错误");
        }
        String token = jwtUtils.generateToken(username.trim());
        Map<String, Object> data = new HashMap<>();
        data.put("token", token);
        data.put("username", username.trim());
        data.put("realName", user.getRealName());
        data.put("modules", user.getModules() == null ? "" : user.getModules());
        return Result.ok(data);
    }
 
    /** 用户修改自己的密码:需提供原密码,新密码至少 6 位 */
    @PostMapping("/change-password")
    public Result<Void> changePassword(@RequestHeader(value = "Authorization", required = false) String auth,
                                       @RequestBody Map<String, Object> params) {
        String username = jwtUtils.resolveUsername(auth);
        if (username == null) {
            return Result.error(401, "未登录或登录已过期");
        }
        String oldPassword = (String) params.get("oldPassword");
        String newPassword = (String) params.get("newPassword");
        if (oldPassword == null || oldPassword.isEmpty()) {
            return Result.error(400, "请输入原密码");
        }
        if (newPassword == null || newPassword.length() < 6) {
            return Result.error(400, "新密码长度不能少于 6 位");
        }
        if (newPassword.equals(oldPassword)) {
            return Result.error(400, "新密码不能与原密码相同");
        }
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
        if (user == null) {
            return Result.error(404, "用户不存在");
        }
        String encoded = user.getPassword();
        boolean ok;
        try {
            ok = encoded != null && passwordEncoder.matches(oldPassword, encoded);
        } catch (IllegalArgumentException e) {
            // 库中密码不是合法 BCrypt 时回退为明文对比(与登录一致)
            ok = encoded != null && encoded.equals(oldPassword);
        }
        if (!ok) {
            return Result.error(400, "原密码错误");
        }
        user.setPassword(passwordEncoder.encode(newPassword));
        userMapper.updateById(user);
        return Result.ok(null);
    }
 
    @GetMapping("/captcha-config")
    public Result<Map<String, Object>> captchaConfig() {
        Map<String, Object> data = new HashMap<>();
        data.put("required", captchaRequired);
        return Result.ok(data);
    }
 
    @SuppressWarnings("unchecked")
    private List<String> strList(Object o) {
        if (o instanceof List) {
            return (List<String>) o;
        }
        return Collections.emptyList();
    }
}