| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- package com.ruoyi.web.controller.system;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import com.ruoyi.common.constant.Constants;
- import com.ruoyi.common.core.domain.entity.SysUser;
- import com.ruoyi.framework.manager.AsyncManager;
- import com.ruoyi.framework.manager.factory.AsyncFactory;
- import com.ruoyi.framework.shiro.service.SysLoginService;
- import com.ruoyi.framework.shiro.util.SMSUtils;
- import com.ruoyi.system.service.ISysLogininforService;
- import com.ruoyi.system.service.ISysUserService;
- import org.apache.shiro.SecurityUtils;
- import org.apache.shiro.authc.AuthenticationException;
- import org.apache.shiro.authc.UsernamePasswordToken;
- import org.apache.shiro.subject.Subject;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.ModelMap;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.PostMapping;
- import org.springframework.web.bind.annotation.ResponseBody;
- import com.ruoyi.common.core.controller.BaseController;
- import com.ruoyi.common.core.domain.AjaxResult;
- import com.ruoyi.common.core.text.Convert;
- import com.ruoyi.common.utils.ServletUtils;
- import com.ruoyi.common.utils.StringUtils;
- import com.ruoyi.framework.web.service.ConfigService;
- import java.io.IOException;
- import java.security.NoSuchAlgorithmException;
- /**
- * 登录验证
- *
- * @author ruoyi
- */
- @Controller
- public class SysLoginController extends BaseController
- {
- /**
- * 是否开启记住我功能
- */
- @Value("${shiro.rememberMe.enabled: false}")
- private boolean rememberMe;
- @Autowired
- private ConfigService configService;
- @Autowired
- private ISysUserService userService;
- @Autowired
- private SysLoginService loginService;
- @Autowired
- private SMSUtils smsUtils;
- @GetMapping("/login")
- public String login(HttpServletRequest request, HttpServletResponse response, ModelMap mmap)
- {
- // 如果是Ajax请求,返回Json字符串。
- if (ServletUtils.isAjaxRequest(request))
- {
- return ServletUtils.renderString(response, "{\"code\":\"1\",\"msg\":\"未登录或登录超时。请重新登录\"}");
- }
- // 是否开启记住我
- mmap.put("isRemembered", rememberMe);
- // 是否开启用户注册
- mmap.put("isAllowRegister", Convert.toBool(configService.getKey("sys.account.registerUser"), false));
- // 是否开启短信验证码登录
- mmap.put("smsLoginEnabled", Convert.toBool(configService.getKey("sys.account.smsLoginEnabled"), false));
- // 是否开启短信验证码前的图形验证码
- mmap.put("smsCaptchaEnabled", Convert.toBool(configService.getKey("sys.account.smsCaptchaEnabled"), true));
- return "login";
- }
- /* @PostMapping("/login")
- @ResponseBody
- public AjaxResult ajaxLogin(String username, String password, Boolean rememberMe)
- {
- UsernamePasswordToken token = new UsernamePasswordToken(username, password, rememberMe);
- Subject subject = SecurityUtils.getSubject();
- try
- {
- subject.login(token);
- return success();
- }
- catch (AuthenticationException e)
- {
- String msg = "用户或密码错误";
- if (StringUtils.isNotEmpty(e.getMessage()))
- {
- msg = e.getMessage();
- }
- return error(msg);
- }
- }*/
- /**
- * 发送短信验证码
- */
- @PostMapping("/sendSmsCode")
- @ResponseBody
- public AjaxResult sendSmsCode(String phone, String captchaCode)
- {
- try
- {
- // 获取图形验证码开关配置
- boolean smsCaptchaEnabled = Convert.toBool(configService.getKey("sys.account.smsCaptchaEnabled"), true);
- // 如果开启了图形验证码,验证图形验证码
- if (smsCaptchaEnabled) {
- if (StringUtils.isEmpty(captchaCode)) {
- return error("请输入图形验证码");
- }
- // 验证图形验证码是否正确
- if (!validateCaptcha(captchaCode)) {
- return error("图形验证码错误");
- }
- }
- // 手机号格式验证
- if (StringUtils.isEmpty(phone)) {
- return error("请输入手机号码");
- }
- if (!phone.matches("^1[3-9]\\d{9}$")) {
- return error("请输入正确的手机号码");
- }
- // 检查手机号是否已注册
- SysUser user = userService.selectUserByPhoneNumber(phone);
- if (user == null) {
- return error("该手机号未注册");
- }
- // 检查发送频率(防止频繁发送)- 60秒内只能发送一次
- HttpServletRequest request = ServletUtils.getRequest();
- Long lastSendTime = (Long) request.getSession().getAttribute("sms_last_send_time_" + phone);
- if (lastSendTime != null && System.currentTimeMillis() - lastSendTime < 60000) {
- long waitTime = 60 - (System.currentTimeMillis() - lastSendTime) / 1000;
- return error("请求过于频繁,请" + waitTime + "秒后再试");
- }
- // 生成验证码
- String smsCode = generateSmsCode();
- // 存储验证码到Session(有效期5分钟)
- request.getSession().setAttribute("sms_code_" + phone, smsCode);
- request.getSession().setAttribute("sms_code_time_" + phone, System.currentTimeMillis());
- request.getSession().setAttribute("sms_last_send_time_" + phone, System.currentTimeMillis());
- // 调用短信服务发送验证码
- boolean sendResult = sendSms(phone, smsCode);
- // boolean sendResult = true;
- if (sendResult)
- {
- System.out.println(smsCode);
- // 记录发送日志,不需要记录日志
- //AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_SUCCESS, "短信验证码发送成功"));
- return success("验证码发送成功");
- }
- else
- {
- return error("验证码发送失败,请稍后重试");
- }
- }
- catch (Exception e)
- {
- return error("验证码发送失败,请稍后重试");
- }
- }
- /**
- * 短信验证码登录
- */
- @PostMapping("/smsLogin")
- @ResponseBody
- public AjaxResult smsLogin(String phone, String smsCode, Boolean rememberMe)
- {
- try
- {
- // 验证短信验证码并获取用户
- SysUser user = loginService.smsLogin(phone, smsCode);
- // 使用固定密码和用户名进行Shiro登录
- UsernamePasswordToken token = new UsernamePasswordToken(user.getLoginName(), "SMS_LOGIN_FIXED_PASSWORD_2025", rememberMe);
- Subject subject = SecurityUtils.getSubject();
- subject.login(token);
- return success();
- }
- catch (Exception e)
- {
- // 直接返回具体的错误信息
- return error(e.getMessage());
- }
- }
- private String generateSmsCode() {
- // 生成6位随机数字
- return String.valueOf((int) ((Math.random() * 9 + 1) * 100000));
- }
- private boolean sendSms(String phone, String smsCode) {
- // 实现短信发送逻辑
- // 这里需要集成实际的短信服务商
- boolean b = false;
- try {
- b = smsUtils.sendMsg(phone, smsCode);
- } catch (IOException e) {
- e.printStackTrace();
- } catch (NoSuchAlgorithmException e) {
- e.printStackTrace();
- }
- return b;
- }
- /**
- * 验证图形验证码
- */
- private boolean validateCaptcha(String captchaCode) {
- try {
- HttpServletRequest request = ServletUtils.getRequest();
- // 调试:打印Session中所有与验证码相关的属性
- java.util.Enumeration<String> attributeNames = request.getSession().getAttributeNames();
- while (attributeNames.hasMoreElements()) {
- String name = attributeNames.nextElement();
- if (name.toLowerCase().contains("captcha") || name.toLowerCase().contains("kaptcha")) {
- Object value = request.getSession().getAttribute(name);
- }
- }
- // 尝试常见的验证码Session key
- String[] possibleKeys = {
- "KAPTCHA_SESSION_KEY",
- "kaptchaCode",
- com.ruoyi.common.constant.ShiroConstants.CURRENT_CAPTCHA,
- "captcha",
- "verifyCode"
- };
- String sessionCaptcha = null;
- String usedKey = null;
- for (String key : possibleKeys) {
- Object value = request.getSession().getAttribute(key);
- if (value != null) {
- sessionCaptcha = value.toString();
- usedKey = key;
- break;
- }
- }
- if (StringUtils.isEmpty(sessionCaptcha)) {
- return false;
- }
- // 验证码比较(忽略大小写)
- boolean isValid = sessionCaptcha.equalsIgnoreCase(captchaCode);
- // 验证后清除Session中的验证码,防止重复使用
- if (isValid && usedKey != null) {
- request.getSession().removeAttribute(usedKey);
- }
- return isValid;
- } catch (Exception e) {
- return false;
- }
- }
- @GetMapping("/unauth")
- public String unauth()
- {
- return "error/unauth";
- }
- }
|