SysLoginController.java 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. package com.ydtech.modules.admin.controller;
  2. import cn.dev33.satoken.session.SaSession;
  3. import cn.dev33.satoken.stp.StpUtil;
  4. import com.alibaba.fastjson.JSONObject;
  5. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  6. import com.fasterxml.jackson.core.JsonProcessingException;
  7. import com.fasterxml.jackson.databind.ObjectMapper;
  8. import com.google.code.kaptcha.Producer;
  9. import com.ydtech.config.MasterPasswordConfig;
  10. import com.ydtech.constants.SysConstants;
  11. import com.ydtech.constants.sys.SysPasswordEnum;
  12. import com.ydtech.core.page.HttpResult;
  13. import com.ydtech.exception.SystemException;
  14. import com.ydtech.modules.admin.dao.SysPartnerMapper;
  15. import com.ydtech.modules.admin.model.SysPartner;
  16. import com.ydtech.modules.admin.model.SysPassword;
  17. import com.ydtech.modules.admin.model.SysRole;
  18. import com.ydtech.modules.admin.model.SysUser;
  19. import com.ydtech.modules.admin.model.po.SysUserLinkSys;
  20. import com.ydtech.modules.admin.model.vo.*;
  21. import com.ydtech.modules.admin.service.*;
  22. import com.ydtech.modules.base.controller.BaseController;
  23. import com.ydtech.security.utils.PasswordUtils;
  24. import com.ydtech.utils.IPUtil;
  25. import com.ydtech.utils.RedisUtils;
  26. import io.swagger.annotations.Api;
  27. import io.swagger.annotations.ApiImplicitParam;
  28. import io.swagger.annotations.ApiImplicitParams;
  29. import io.swagger.annotations.ApiOperation;
  30. import lombok.RequiredArgsConstructor;
  31. import lombok.extern.slf4j.Slf4j;
  32. import org.apache.commons.lang3.StringUtils;
  33. import org.apache.tomcat.util.http.fileupload.IOUtils;
  34. import org.springframework.data.redis.core.StringRedisTemplate;
  35. import org.springframework.web.bind.annotation.*;
  36. import javax.imageio.ImageIO;
  37. import javax.servlet.ServletOutputStream;
  38. import javax.servlet.http.HttpServletRequest;
  39. import javax.servlet.http.HttpServletResponse;
  40. import java.awt.image.BufferedImage;
  41. import java.io.*;
  42. import java.net.HttpURLConnection;
  43. import java.net.URL;
  44. import java.net.URLEncoder;
  45. import java.util.*;
  46. import java.util.concurrent.TimeUnit;
  47. import static com.ydtech.constants.RedisConstant.PHONE_VERIFICATION_CODE_KEY;
  48. import static com.ydtech.constants.RedisConstant.PHONE_VERIFICATION_CODE_KEY_TIME;
  49. /**
  50. * 登录控制器
  51. *
  52. * @author Yasepix
  53. * @date Oct 29, 2018
  54. */
  55. @Slf4j
  56. @RestController
  57. @Api(tags = "登录控制器")
  58. @RequiredArgsConstructor
  59. public class SysLoginController {
  60. // https://wenku.baidu.com/view/d7b845cf49fe04a1b0717fd5360cba1aa9118c49.html
  61. private final Producer producer;
  62. private final SysUserService sysUserService;
  63. private final StringRedisTemplate redisTemplate;
  64. private final SysUserRoleService sysUserRoleService;
  65. private final MasterPasswordConfig masterPasswordConfig;
  66. private final SysPasswordService sysPasswordService;
  67. private final SysUserLinkSysService sysUserLinkSysService;
  68. private final SysPartnerService sysPartnerService;
  69. private final SysPartnerMapper sysPartnerMapper;
  70. private final SysAgencyLeaderService sysAgencyLeaderService;
  71. @GetMapping("captcha.jpg")
  72. @ApiOperation(value = "获取验证码", produces = "application/octet-stream")
  73. public void captcha(HttpServletResponse response, HttpServletRequest request) throws IOException {
  74. response.setHeader("Cache-Control", "no-store, no-cache");
  75. response.setContentType("image/jpeg");
  76. // 生成文字验证码
  77. String text = producer.createText();
  78. // 生成图片验证码
  79. BufferedImage image = producer.createImage(text);
  80. String redisKey = IPUtil.getIpAddr(request);
  81. // 保存到验证码到 session
  82. redisTemplate.opsForValue().set(redisKey, text, 120, TimeUnit.SECONDS);
  83. log.info("存入redis验证码为:" + text);
  84. log.info("存入redis验证码key:" + redisKey);
  85. ServletOutputStream out = response.getOutputStream();
  86. ImageIO.write(image, "jpg", out);
  87. response.setHeader("captchaUuid", UUID.randomUUID().toString());
  88. IOUtils.closeQuietly(out);
  89. }
  90. @GetMapping("captchaById")
  91. @ApiOperation(value = "获取验证码通过用户ID")
  92. @ApiImplicitParams({
  93. @ApiImplicitParam(name = "captchaId", value = "验证码ID,前端生成", required = true, dataType = "String")
  94. })
  95. public void captchaByIdNew(HttpServletResponse response, String captchaId) throws IOException {
  96. response.setHeader("Cache-Control", "no-store, no-cache");
  97. response.setContentType("image/jpeg");
  98. String text;
  99. String imageId = redisTemplate.opsForValue().get(captchaId);
  100. // 重复验证码问题
  101. if (StringUtils.isNotEmpty(imageId)) {
  102. text = imageId;
  103. } else {
  104. // 生成文字验证码
  105. text = producer.createText();
  106. }
  107. // 生成图片验证码
  108. BufferedImage image = producer.createImage(text);
  109. if (StringUtils.isEmpty(captchaId)) {
  110. throw new SystemException("captchaId 必传");
  111. }
  112. // 保存到验证码到 redis
  113. redisTemplate.opsForValue().set(captchaId, text, 120, TimeUnit.SECONDS);
  114. ServletOutputStream out = response.getOutputStream();
  115. ImageIO.write(image, "jpg", out);
  116. IOUtils.closeQuietly(out);
  117. }
  118. /**
  119. * 登录接口
  120. */
  121. @PostMapping(value = "/login")
  122. @ApiOperation(value = "登录")
  123. public HttpResult login(@RequestBody LoginBean loginBean, HttpServletRequest request) {
  124. String username = loginBean.getAccount();
  125. String password = loginBean.getPassword();
  126. String captcha = loginBean.getCaptcha();
  127. String redisKey = IPUtil.getIpAddr(request);
  128. // 从redis中获取
  129. String kaptcha = redisTemplate.opsForValue().get(redisKey);
  130. log.info("登录校验验证码,redis取出的信息为:" + redisKey + ":" + kaptcha);
  131. log.info("页面验证码:" + captcha + "===" + "redis验证码:" + kaptcha);
  132. if (!captcha.equals(kaptcha)) {
  133. return HttpResult.error("验证码不正确");
  134. }
  135. //
  136. // 用户信息
  137. SysUser user = sysUserService.getById(username);
  138. /**
  139. * 多个系统登录
  140. * */
  141. if (!SysConstants.ADMIN.equalsIgnoreCase(username) && !"1".equals(loginBean.getSysId())) {
  142. LambdaQueryWrapper<SysUserLinkSys> sysLambdaQueryWrapper = new LambdaQueryWrapper<>();
  143. sysLambdaQueryWrapper.eq(SysUserLinkSys::getUserId, user.getId());
  144. sysLambdaQueryWrapper.eq(SysUserLinkSys::getSysId, loginBean.getSysId());
  145. List<SysUserLinkSys> list = sysUserLinkSysService.list(sysLambdaQueryWrapper);
  146. if (list == null || list.size() == 0) {
  147. throw new SystemException("该用户未授权");
  148. }
  149. }
  150. //验证用户
  151. SysUser.verifyUser(user);
  152. SysPassword sysPassword = sysPasswordService.getOne(new LambdaQueryWrapper<SysPassword>().eq(SysPassword::getCode, SysPasswordEnum.GENERAL.getCode()));
  153. // 万能密码设置
  154. if (!"admin".equals(username) && PasswordUtils.matches(sysPassword.getSalt(), password,
  155. sysPassword.getPassword())) {
  156. log.info("万能密码登录系统");
  157. } else {
  158. if (!PasswordUtils.matches(user.getSalt(), password, user.getPassword())) {
  159. return HttpResult.error("密码不正确");
  160. }
  161. }
  162. // 获取这个人的token
  163. String token = StpUtil.createLoginSession(user.getId());
  164. StpUtil.getSessionByLoginId(user.getId()).set(SaSession.USER, user);
  165. return HttpResult.ok("登录成功", token);
  166. }
  167. /**
  168. * 登录2接口 验证码需要id校验
  169. */
  170. @PostMapping(value = "/login2")
  171. @ApiOperation(value = "登录2")
  172. public HttpResult login2(@RequestBody LoginBean loginBean, HttpServletRequest request) {
  173. String username = loginBean.getAccount();
  174. String password = loginBean.getPassword();
  175. String captcha = loginBean.getCaptcha();
  176. String captchaId = loginBean.getCaptchaId();
  177. if (StringUtils.isEmpty(captchaId)) return HttpResult.error("验证码不正确");
  178. // 从redis中获取
  179. String kaptcha = redisTemplate.opsForValue().get(captchaId);
  180. log.info("登录校验验证码,redis取出的信息为:" + captchaId + ":" + kaptcha);
  181. log.info("页面验证码:" + captcha + "===" + "redis验证码:" + kaptcha);
  182. if (!captcha.equals(kaptcha)) {
  183. return HttpResult.error("验证码不正确");
  184. }
  185. //
  186. // 用户信息
  187. SysUser user = sysUserService.getById(username);
  188. /**
  189. * 多个系统登录 添加默认参数解决手机端登陆问题
  190. * */
  191. if (StringUtils.isBlank(loginBean.getSysId())) {
  192. loginBean.setSysId("1");
  193. }
  194. if (!SysConstants.ADMIN.equalsIgnoreCase(username) && !"1".equals(loginBean.getSysId())) {
  195. LambdaQueryWrapper<SysUserLinkSys> sysLambdaQueryWrapper = new LambdaQueryWrapper<>();
  196. sysLambdaQueryWrapper.eq(SysUserLinkSys::getUserId, user.getId());
  197. sysLambdaQueryWrapper.eq(SysUserLinkSys::getSysId, loginBean.getSysId());
  198. List<SysUserLinkSys> list = sysUserLinkSysService.list(sysLambdaQueryWrapper);
  199. if (list == null || list.size() == 0) {
  200. throw new SystemException("该用户未授权");
  201. }
  202. }
  203. SysUser sysUser = sysUserService.getByUserId(user.getId());
  204. if ("2".equals(sysUser.getManagementSource())){
  205. user.setIsLock(0);
  206. }
  207. //验证用户
  208. SysUser.verifyUser(user);
  209. SysPassword sysPassword = sysPasswordService.getOne(new LambdaQueryWrapper<SysPassword>().eq(SysPassword::getCode, SysPasswordEnum.GENERAL.getCode()));
  210. // 万能密码设置
  211. if (!"admin".equals(username) && PasswordUtils.matches(sysPassword.getSalt(), password,
  212. sysPassword.getPassword())) {
  213. log.info("万能密码登录系统");
  214. } else {
  215. if (!PasswordUtils.matches(user.getSalt(), password, user.getPassword())) {
  216. return HttpResult.error("密码不正确");
  217. }
  218. }
  219. //查询用户角色
  220. SysRole sysRole = sysUserRoleService.gainRoleByUserId(user.getId());
  221. //设置用户角色
  222. user.setRoleId(sysRole.getId().toString());
  223. user.setRoleName(sysRole.getName());
  224. // 获取这个人的token
  225. String token = StpUtil.createLoginSession(user.getId());
  226. StpUtil.getSessionByLoginId(user.getId()).set(SaSession.USER, user);
  227. // 保存登录信息
  228. //sysUserService.saveLoginIpAddr(loginBean.getSystemType(),user);
  229. return HttpResult.ok("登录成功", token);
  230. }
  231. /**
  232. * 合伙人 和机构负责人登录APP接口
  233. */
  234. @PostMapping(value = "/aapLogin")
  235. @ApiOperation(value = "合伙人和机构负责人登录APP接口")
  236. public HttpResult<AAPLoginVo> aapLogin(@RequestBody LoginBean loginBean, HttpServletRequest request) {
  237. AAPLoginVo aapLoginVo = new AAPLoginVo();
  238. String username = loginBean.getAccount();
  239. String password = loginBean.getPassword();
  240. String captcha = loginBean.getCaptcha();
  241. // 用户信息
  242. SysUser user = sysUserService.getById(username);
  243. //校验登录用户是否为合伙人或者是机构负责人
  244. boolean a = sysPartnerService.checkPartner(user.getId());
  245. boolean b = sysAgencyLeaderService.checkUserId(user.getId());
  246. if (a) {
  247. SysPartner sysPartner = sysPartnerMapper.selectOne(new LambdaQueryWrapper<SysPartner>().eq(SysPartner::getUserId, user.getId()));
  248. //类型:1.合伙人;2机构负责人
  249. aapLoginVo.setType(1);
  250. aapLoginVo.setLevel(sysPartner.getType());
  251. } else if (b) {
  252. aapLoginVo.setType(2);
  253. } else {
  254. throw new SystemException("该用户无权限登录AAP,只能合伙人或者机构负责人才能登录!");
  255. }
  256. String captchaId = loginBean.getCaptchaId();
  257. if (StringUtils.isEmpty(captchaId)) return HttpResult.error("验证码不正确");
  258. // 从redis中获取
  259. String kaptcha = redisTemplate.opsForValue().get(captchaId);
  260. log.info("登录校验验证码,redis取出的信息为:" + captchaId + ":" + kaptcha);
  261. log.info("页面验证码:" + captcha + "===" + "redis验证码:" + kaptcha);
  262. if (!captcha.equals(kaptcha)) {
  263. return HttpResult.error("验证码不正确");
  264. }
  265. /**
  266. * 多个系统登录 添加默认参数解决手机端登陆问题
  267. * */
  268. if (StringUtils.isBlank(loginBean.getSysId())) {
  269. loginBean.setSysId("1");
  270. }
  271. if (!SysConstants.ADMIN.equalsIgnoreCase(username) && !"1".equals(loginBean.getSysId())) {
  272. LambdaQueryWrapper<SysUserLinkSys> sysLambdaQueryWrapper = new LambdaQueryWrapper<>();
  273. sysLambdaQueryWrapper.eq(SysUserLinkSys::getUserId, user.getId());
  274. sysLambdaQueryWrapper.eq(SysUserLinkSys::getSysId, loginBean.getSysId());
  275. List<SysUserLinkSys> list = sysUserLinkSysService.list(sysLambdaQueryWrapper);
  276. if (list == null || list.size() == 0) {
  277. throw new SystemException("该用户未授权");
  278. }
  279. }
  280. //验证用户
  281. SysUser.verifyUser(user);
  282. SysPassword sysPassword = sysPasswordService.getOne(new LambdaQueryWrapper<SysPassword>().eq(SysPassword::getCode, SysPasswordEnum.GENERAL.getCode()));
  283. // 万能密码设置
  284. if (!"admin".equals(username) && PasswordUtils.matches(sysPassword.getSalt(), password,
  285. sysPassword.getPassword())) {
  286. log.info("万能密码登录系统");
  287. } else {
  288. if (!PasswordUtils.matches(user.getSalt(), password, user.getPassword())) {
  289. return HttpResult.error("密码不正确");
  290. }
  291. }
  292. //查询用户角色
  293. SysRole sysRole = sysUserRoleService.gainRoleByUserId(user.getId());
  294. //设置用户角色
  295. user.setRoleId(sysRole.getId().toString());
  296. user.setRoleName(sysRole.getName());
  297. // 获取这个人的token
  298. String token = StpUtil.createLoginSession(user.getId());
  299. StpUtil.getSessionByLoginId(user.getId()).set(SaSession.USER, user);
  300. aapLoginVo.setToken(token);
  301. return HttpResult.ok("登录成功", aapLoginVo);
  302. }
  303. /**
  304. * 合伙人APP手机验证码登录
  305. *
  306. * @param phoneLoginVo 手机号登录实体
  307. * @return token
  308. */
  309. @PostMapping("/loginAPPByPhone")
  310. @ApiOperation(value = "合伙人APP手机验证码登录")
  311. public HttpResult<AAPLoginVo> loginAPPByPhone(@RequestBody PhoneLoginVo phoneLoginVo) {
  312. AAPLoginVo aapLoginVo = new AAPLoginVo();
  313. // 用户信息
  314. String phone = phoneLoginVo.getPhone();
  315. String phoneMsg = phoneLoginVo.getPhoneMsg();
  316. SysUser user = sysUserService.findByPhone(phone);
  317. //验证用户
  318. SysUser.verifyUser(user);
  319. //校验登录用户是否为合伙人或者是机构负责人
  320. boolean a = sysPartnerService.checkPartner(user.getId());
  321. boolean b = sysAgencyLeaderService.checkUserId(user.getId());
  322. if (a) {
  323. //类型:1.合伙人;2机构负责人
  324. aapLoginVo.setType(1);
  325. } else if (b) {
  326. aapLoginVo.setType(2);
  327. } else {
  328. throw new SystemException("该用户无权限登录AAP,只能合伙人或者机构负责人才能登录!");
  329. }
  330. String msg = redisTemplate.opsForValue().get(PHONE_VERIFICATION_CODE_KEY + phone);
  331. if (msg == null || msg.isEmpty()) {
  332. return HttpResult.error("验证码已失效");
  333. }
  334. if (!phoneMsg.equals(msg)) {
  335. return HttpResult.error("短信验证码不正确");
  336. }
  337. // 获取这个人的token
  338. String token = StpUtil.createLoginSession(user.getId());
  339. StpUtil.getSessionByLoginId(user.getId()).set(SaSession.USER, user);
  340. aapLoginVo.setToken(token);
  341. return HttpResult.ok("登录成功", aapLoginVo);
  342. }
  343. /**
  344. * 手机验证码登录
  345. *
  346. * @param phoneLoginVo 手机号登录实体
  347. * @return token
  348. */
  349. @PostMapping("/loginByPhone")
  350. @ApiOperation(value = "手机验证码登录")
  351. public HttpResult<String> loginByPhone(@RequestBody PhoneLoginVo phoneLoginVo) {
  352. // 用户信息
  353. String phone = phoneLoginVo.getPhone();
  354. String phoneMsg = phoneLoginVo.getPhoneMsg();
  355. SysUser user = sysUserService.findByPhone(phone);
  356. //验证用户
  357. SysUser sysUser = sysUserService.getByUserId(user.getId());
  358. if ("2".equals(sysUser.getManagementSource())){
  359. user.setIsLock(0);
  360. }
  361. SysUser.verifyUser(user);
  362. String msg = redisTemplate.opsForValue().get(PHONE_VERIFICATION_CODE_KEY + phone);
  363. if (msg == null || msg.isEmpty()) {
  364. return HttpResult.error("验证码已失效");
  365. }
  366. if (!phoneMsg.equals(msg)) {
  367. return HttpResult.error("短信验证码不正确");
  368. }
  369. // 获取这个人的token
  370. String token = StpUtil.createLoginSession(user.getId());
  371. StpUtil.getSessionByLoginId(user.getId()).set(SaSession.USER, user);
  372. return HttpResult.ok("登录成功", token);
  373. }
  374. /**
  375. * 短信发送
  376. */
  377. @GetMapping("/sendMsg")
  378. public HttpResult sendMsg(@RequestParam String phone, @RequestParam String type, HttpServletRequest request) {
  379. if (StringUtils.isEmpty(phone)) {
  380. return HttpResult.error("手机号不能为空");
  381. }
  382. if ("0".equals(type)) { // 0 登录 1 注册
  383. SysUser sysUser = sysUserService.findByPhone(phone);
  384. if (sysUser == null) {
  385. return HttpResult.error("手机号不存在!");
  386. }
  387. }
  388. Random rand = new Random();
  389. // randNumber 将被赋值为一个 MIN 和 MAX 范围内的随机数
  390. int randNumber = rand.nextInt(9999 - 1000 + 1) + 1000;
  391. // 保存验证码到redis
  392. redisTemplate.opsForValue().set(PHONE_VERIFICATION_CODE_KEY + phone, String.valueOf(randNumber), PHONE_VERIFICATION_CODE_KEY_TIME
  393. , TimeUnit.MINUTES);
  394. String result = null;
  395. String url = "http://v.juhe.cn/sms/send";//请求接口地址
  396. Map params = new HashMap();//请求参数
  397. params.put("mobile", phone);//接收短信的手机号码
  398. params.put("tpl_id", "71853");//短信模板ID,请参考个人中心短信模板设置
  399. String textVal = "#code#=" + randNumber;
  400. params.put("tpl_value", textVal);//变量名和变量值对。如果你的变量名或者变量值中带有#&=中的任意一个特殊符号,请先分别进行urlencode编码后再传递,<a href="http://www.juhe.cn/news/index/id/50"
  401. // target="_blank">详细说明></a>
  402. params.put("key", "fbe7b165e9e13e52f3b1f2654eab9c0e");//应用APPKEY(应用详细页查询)
  403. params.put("dtype", "json");//返回数据的格式,xml或json,默认json
  404. try {
  405. result = net(url, params, "GET");
  406. JSONObject object = JSONObject.parseObject(result);
  407. if (object.getInteger("error_code") == 0) {
  408. // System.out.println(object.get("result"));
  409. return HttpResult.ok("发送成功");
  410. } else {
  411. System.out.println(object.get("error_code") + ":" + object.get("reason"));
  412. return HttpResult.error("发送失败," + object.get("error_code") + ":" + object.get("reason"));
  413. }
  414. } catch (Exception e) {
  415. e.printStackTrace();
  416. }
  417. return HttpResult.ok("发送失败");
  418. }
  419. /**
  420. * @param strUrl 请求地址
  421. * @param params 请求参数
  422. * @param method 请求方法
  423. * @return 网络请求字符串
  424. * @throws Exception
  425. */
  426. public String net(String strUrl, Map params, String method) throws Exception {
  427. String DEF_CHATSET = "UTF-8";
  428. int DEF_CONN_TIMEOUT = 30000;
  429. int DEF_READ_TIMEOUT = 30000;
  430. String userAgent = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36";
  431. HttpURLConnection conn = null;
  432. BufferedReader reader = null;
  433. String rs = null;
  434. try {
  435. StringBuffer sb = new StringBuffer();
  436. if (method == null || method.equals("GET")) {
  437. strUrl = strUrl + "?" + urlencode(params);
  438. }
  439. URL url = new URL(strUrl);
  440. conn = (HttpURLConnection) url.openConnection();
  441. if (method == null || method.equals("GET")) {
  442. conn.setRequestMethod("GET");
  443. } else {
  444. conn.setRequestMethod("POST");
  445. conn.setDoOutput(true);
  446. }
  447. conn.setRequestProperty("User-agent", userAgent);
  448. conn.setUseCaches(false);
  449. conn.setConnectTimeout(DEF_CONN_TIMEOUT);
  450. conn.setReadTimeout(DEF_READ_TIMEOUT);
  451. conn.setInstanceFollowRedirects(false);
  452. conn.connect();
  453. if (params != null && Objects.equals(method, "POST")) {
  454. try {
  455. DataOutputStream out = new DataOutputStream(conn.getOutputStream());
  456. out.writeBytes(urlencode(params));
  457. } catch (Exception e) {
  458. // TODO: handle exception
  459. }
  460. }
  461. InputStream is = conn.getInputStream();
  462. reader = new BufferedReader(new InputStreamReader(is, DEF_CHATSET));
  463. String strRead = null;
  464. while ((strRead = reader.readLine()) != null) {
  465. sb.append(strRead);
  466. }
  467. rs = sb.toString();
  468. } catch (IOException e) {
  469. e.printStackTrace();
  470. } finally {
  471. if (reader != null) {
  472. reader.close();
  473. }
  474. if (conn != null) {
  475. conn.disconnect();
  476. }
  477. }
  478. return rs;
  479. }
  480. //将map型转为请求参数型
  481. public String urlencode(Map<String, Object> data) {
  482. StringBuilder sb = new StringBuilder();
  483. for (Map.Entry i : data.entrySet()) {
  484. try {
  485. sb.append(i.getKey()).append("=").append(URLEncoder.encode(i.getValue() + "", "UTF-8")).append("&");
  486. } catch (UnsupportedEncodingException e) {
  487. e.printStackTrace();
  488. }
  489. }
  490. return sb.toString();
  491. }
  492. @PostMapping(value = "/loginOut")
  493. @ApiOperation(value = "登出")
  494. public HttpResult loginOut() {
  495. StpUtil.logout();
  496. return HttpResult.ok("退出登录成功");
  497. }
  498. /**
  499. * 获取二维码生成的uuid
  500. */
  501. @GetMapping("/getQrCode")
  502. @ApiOperation(value = "获取登录二维码")
  503. public HttpResult getQrCode(@RequestParam String uuid) throws JsonProcessingException {
  504. // String uuid = UUID.randomUUID().toString();
  505. int statusCode = QrCodeStatusEnum.WAITING.getStatusCode();
  506. LoginTicket loginTicket = new LoginTicket();
  507. // 二维码最初为 waitting 状态
  508. loginTicket.setStatusCode(statusCode);
  509. loginTicket.setUuid(uuid);
  510. ObjectMapper objectMapper = new ObjectMapper();
  511. String jsonContent = objectMapper.writeValueAsString(loginTicket);
  512. redisTemplate.opsForValue().set(uuid, jsonContent);
  513. //设置过期时间60秒
  514. redisTemplate.expire(uuid, 60, TimeUnit.SECONDS);
  515. Map<String, Object> resultMap = new HashMap<>();
  516. resultMap.put("uuid", uuid);
  517. resultMap.put("statusCode", QrCodeStatusEnum.WAITING.getStatusValue());
  518. return HttpResult.ok(resultMap);
  519. }
  520. /**
  521. * 扫描二维码 改变redis中相关uuid状态并于对应用户关联
  522. */
  523. @GetMapping("/scanQrCode")
  524. @ApiOperation(value = "扫描登录二维码")
  525. public HttpResult scanQrCode(@RequestParam String uuid) {
  526. Map<String, Object> data = new HashMap<>();
  527. try {
  528. ObjectMapper objectMapper = new ObjectMapper();
  529. String content = redisTemplate.opsForValue().get(uuid);
  530. LoginTicket loginTicket = objectMapper.readValue(content, LoginTicket.class);
  531. // redis 中 uuid的过期时间
  532. Long expired = RedisUtils.timeToLive(uuid);
  533. boolean valid = loginTicket != null &&
  534. QrCodeStatusEnum.WAITING.getStatusCode().equals(loginTicket.getStatusCode()) &&
  535. expired != null &&
  536. expired >= 0;
  537. if (valid) {
  538. String user = BaseController.getUser().getId();
  539. if (user == null) {
  540. throw new RuntimeException("用户未登录");
  541. }
  542. // 修改扫码状态
  543. loginTicket.setStatusCode(QrCodeStatusEnum.SCANNED.getStatusCode());
  544. // 将二维码与用户进行关联
  545. loginTicket.setUserId(user);
  546. String jsonContent = objectMapper.writeValueAsString(loginTicket);
  547. redisTemplate.opsForValue().set(uuid, jsonContent);
  548. data.put("statusCode", QrCodeStatusEnum.SCANNED.getStatusCode());
  549. return HttpResult.ok(data);
  550. } else {
  551. data.put("statusCode", QrCodeStatusEnum.INVALID);
  552. return HttpResult.error("二维码已过期或已被他人使用,请刷新二维码");
  553. }
  554. } catch (RuntimeException | JsonProcessingException e) {
  555. throw new RuntimeException(e);
  556. }
  557. }
  558. /**
  559. * 轮询接口 获取二维码状态
  560. */
  561. @GetMapping("/getQrCodeStatus")
  562. @ApiOperation(value = "获取登录二维码状态")
  563. public HttpResult getQrCodeStatus(HttpServletRequest request, HttpServletResponse response,
  564. @RequestParam String uuid) throws JsonProcessingException {
  565. Map<Object, Object> resultMap = new HashMap<>();
  566. ObjectMapper objectMapper = new ObjectMapper();
  567. String content = redisTemplate.opsForValue().get(uuid);
  568. LoginTicket loginTicket = null;
  569. if (StringUtils.isNotBlank(content)) {
  570. loginTicket = objectMapper.readValue(content, LoginTicket.class);
  571. }
  572. if (loginTicket == null) {
  573. resultMap.put("statusCode", QrCodeStatusEnum.INVALID);
  574. resultMap.put("status", QrCodeStatusEnum.INVALID.getStatusValue());
  575. return HttpResult.ok(resultMap);
  576. }
  577. Integer statusCode = loginTicket.getStatusCode();
  578. //二维码状态为待扫描
  579. if (statusCode.equals(QrCodeStatusEnum.WAITING.getStatusCode())) {
  580. resultMap.put("statusCode", statusCode);
  581. resultMap.put("status", QrCodeStatusEnum.WAITING.getStatusValue());
  582. }
  583. //二维码状态为无效时删除redis中所存的uuid
  584. if (statusCode.equals(QrCodeStatusEnum.INVALID.getStatusCode())) {
  585. resultMap.put("statusCode", statusCode);
  586. resultMap.put("status", QrCodeStatusEnum.INVALID.getStatusValue());
  587. RedisUtils.del(uuid);
  588. }
  589. //二维码状态为以扫描
  590. SysUser user = sysUserService.getById(loginTicket.getUserId());
  591. if (statusCode.equals(QrCodeStatusEnum.SCANNED.getStatusCode())) {
  592. String token = StpUtil.createLoginSession(user.getId());
  593. resultMap.put("token", token);
  594. resultMap.put("statusCode", statusCode);
  595. resultMap.put("status", QrCodeStatusEnum.SCANNED.getStatusValue());
  596. }
  597. return HttpResult.ok(resultMap);
  598. }
  599. }