AuthenticationController.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. package com.beifan.foxlibc.modules.controller;
  2. import com.beifan.foxlibc.framework.utils.Assert;
  3. import com.beifan.foxlibc.framework.utils.JvmCache;
  4. import com.beifan.foxlibc.framework.utils.R;
  5. import com.beifan.foxlibc.framework.utils.StringUtils;
  6. import com.beifan.foxlibc.framework.utils.generator.UniqueUtils;
  7. import com.beifan.foxlibc.framework.utils.generator.VerifyCodes;
  8. import com.beifan.foxlibc.framework.utils.security.DoubleCoder;
  9. import com.beifan.foxlibc.framework.utils.time.DateUtils;
  10. import com.beifan.foxlibc.framework.utils.time.TimeUnits;
  11. import com.beifan.foxlibc.modules.configuration.NV_TOKEN;
  12. import com.beifan.foxlibc.modules.pojo.model.SystemSet;
  13. import com.beifan.foxlibc.modules.pojo.model.User;
  14. import com.beifan.foxlibc.modules.pojo.model.UserLogininfo;
  15. import com.beifan.foxlibc.modules.pojo.webio.MakeVerificationCodeIn;
  16. import com.beifan.foxlibc.modules.pojo.webio.ResetPasswdIn;
  17. import com.beifan.foxlibc.modules.pojo.webio.ResetSecPasswdIn;
  18. import com.beifan.foxlibc.modules.pojo.webio.io.AuthenticationCodeIn;
  19. import com.beifan.foxlibc.modules.pojo.webio.io.AuthenticationOut;
  20. import com.beifan.foxlibc.modules.pojo.webio.io.AuthenticationSecUserIn;
  21. import com.beifan.foxlibc.modules.pojo.webio.io.AuthenticationUserIn;
  22. import com.beifan.foxlibc.modules.service.UserOperateService;
  23. import com.beifan.foxlibc.modules.service.UserService;
  24. import lombok.extern.slf4j.Slf4j;
  25. import org.springframework.beans.factory.annotation.Autowired;
  26. import org.springframework.beans.factory.annotation.Value;
  27. import org.springframework.web.bind.annotation.PostMapping;
  28. import org.springframework.web.bind.annotation.RequestBody;
  29. import org.springframework.web.bind.annotation.RequestHeader;
  30. import org.springframework.web.bind.annotation.RestController;
  31. import javax.validation.Valid;
  32. import java.util.Date;
  33. import java.util.Map;
  34. import java.util.Objects;
  35. import java.util.regex.Pattern;
  36. /**
  37. * 认证服务:登录/code生成/解析/验证
  38. *
  39. * @author lts
  40. */
  41. @RestController
  42. @Slf4j
  43. public class AuthenticationController {
  44. @Autowired
  45. private UserService userService;
  46. @Autowired
  47. private UserOperateService userOperateService;
  48. // @Value("${foxlibc.debug}") private boolean __DEBUG__;
  49. @Value("${foxlibc.mlogin:false}")
  50. private boolean __M_LOGIN__;
  51. /**
  52. * 缓存
  53. */
  54. private final JvmCache jvmCache = new JvmCache();
  55. /* 密码校验规则 */
  56. static String PWD_VALID_RGX =
  57. "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[`!@#$%^&*()_+{}\":?><,./';\\[\\]=-\\\\|])(?=\\S+$).{8,20}$";
  58. /**
  59. * 生成appToken
  60. */
  61. @NV_TOKEN
  62. @PostMapping("/application-token")
  63. public R<AuthenticationOut> applicationToken(@Valid @RequestBody AuthenticationCodeIn authenticationCodeIn) {
  64. Assert.throwIfBool(userService.application(authenticationCodeIn.getAppid(), authenticationCodeIn.getAppSecret()),
  65. "appid或app secret不正确");
  66. // authenticationService.useEnv(JwtConst.APP);
  67. // String appToken = authenticationService.createToken(Maps.ofMap(JwtConst.APP, authenticationCodeIn.getAppid()));
  68. String appToken = UniqueUtils.uuid().toLowerCase();
  69. Date expireTime = DateUtils.plus(new Date(), 1, TimeUnits.DAYS);
  70. /* 记录登录信息 */
  71. // Date expireTime = authenticationService.getExpireTime(appToken);
  72. String appid = authenticationCodeIn.getAppid();
  73. UserLogininfo userLogininfo = new UserLogininfo(appid, null, expireTime, appToken, null, null, null);
  74. userService.saveUserLogininfo(userLogininfo);
  75. SystemSet systemSet = userService.systemSetting();
  76. Boolean verificationCode = systemSet.getVerificationCode();
  77. return R.ok(
  78. "appToken", appToken,
  79. "expireTime", DateUtils.format(expireTime),
  80. "verificationCode", verificationCode
  81. );
  82. }
  83. /**
  84. * 验证token
  85. */
  86. @NV_TOKEN
  87. @PostMapping("/valid/token")
  88. public R<AuthenticationOut> validToken(@RequestHeader Map<String, String> headers) {
  89. String token = headers.get("authorization");
  90. String authId = headers.get("authid");
  91. /* WRAN: 异常信息中的 -C401 是指定返回Code。
  92. 如果删除了前端将不能通过 401 判断用户是否过期 */
  93. // Assert.throwIfBool(!jvmCache.contains(CacheConst.TOKEN_BLACKLIST(code)), "-C401 TOKEN已被禁用");
  94. /* 如果验证失败,抛出异常 */
  95. // Assert.throwIfBool(authenticationService.validate(code), "-C401 TOKEN已过期");
  96. UserLogininfo userLogininfo = userService.queryUserLogininfo(token);
  97. Date expireTime = userLogininfo.getExpireTime();
  98. Assert.throwIfBool(!DateUtils.gteq(new Date(), expireTime), "-C401 TOKEN已过期");
  99. if (Objects.nonNull(authId)) {
  100. userOperateService.operateLog(userLogininfo.getUserId(), authId);
  101. }
  102. return R.ok();
  103. }
  104. /**
  105. * 生成验证码
  106. */
  107. @NV_TOKEN
  108. @PostMapping("/verification-code")
  109. public R<String> verificationCode(@Valid @RequestBody MakeVerificationCodeIn makeVerificationCodeIn) {
  110. String code;
  111. SystemSet systemSet = userService.systemSetting();
  112. int vlen = Integer.parseInt(systemSet.getVerificationCodeLength());
  113. /* true 只有数字,false 数字加字符 */
  114. if (SystemSet.ONLY_NUMBER.equals(systemSet.getVerificationCodeType())) {
  115. code = VerifyCodes.randomSimpleVerifyCode(vlen);
  116. } else {
  117. code = VerifyCodes.randomComplexVerifyCode(vlen);
  118. }
  119. Date codeExpireTime = DateUtils.plus(new Date(), 60, TimeUnits.SECONDS);
  120. // jvmCache.set(CacheConst.VERIFICATION_CODE(makeVerificationCodeIn.getAppToken()), code, (60 * 3));
  121. String appToken = makeVerificationCodeIn.getAppToken();
  122. UserLogininfo userLogininfo = userService.queryUserLogininfo(appToken);
  123. userLogininfo.setVerificationCode(code);
  124. userLogininfo.setCodeExpireTime(codeExpireTime);
  125. userService.updateUserLogininfo(userLogininfo, appToken);
  126. return R.ok(code);
  127. }
  128. /**
  129. * 用户登录
  130. */
  131. @NV_TOKEN
  132. @PostMapping("/sign-in")
  133. public R<AuthenticationOut> signin(@RequestHeader("Authorization") String appToken, @Valid @RequestBody AuthenticationUserIn authenticationUserIn) {
  134. // String sessionid = getSessionId();
  135. String username = authenticationUserIn.getUsername();
  136. SystemSet systemSet = userService.systemSetting();
  137. /* 验证码校验 */
  138. // String verificationCode = jvmCache.get(CacheConst.VERIFICATION_CODE(appToken));
  139. UserLogininfo userLogininfo = userService.queryUserLogininfo(appToken);
  140. if (systemSet.getVerificationCode()) {
  141. String verificationCode = userLogininfo.getVerificationCode();
  142. Assert.throwIfBool(verificationCode != null && verificationCode.equals(authenticationUserIn.getVerificationCode()), "验证码错误");
  143. boolean isCheckFull = systemSet.getVerificationCodeAa() ?
  144. Objects.equals(verificationCode, authenticationUserIn.getVerificationCode()) :
  145. Objects.equals(verificationCode.toLowerCase(), authenticationUserIn.getVerificationCode().toLowerCase());
  146. Assert.throwIfBool(isCheckFull, "验证码不正确");
  147. Date codeExpireTime = userLogininfo.getCodeExpireTime();
  148. Assert.throwIfBool(!DateUtils.gteq(new Date(), codeExpireTime), "-C401 验证码已过期");
  149. }
  150. // 查询用户
  151. User u = userService.queryUserByUsername(username);
  152. Assert.throwIfBool(!"0".equals(u.getUserStatus()), "当前用户状态已被禁用, 不允许登录");
  153. String userid;
  154. try {
  155. /* 验证用户名密码是否可以登录 */
  156. userid = userService.sign(username, authenticationUserIn.getPassword());
  157. // 验证成功则清零失败次数
  158. userService.updateFailCount(username, 0);
  159. } catch (Exception e) {
  160. // 验证失败 更新失败次数
  161. if (u.getFailCount() < 4) {
  162. userService.updateFailCount(username, u.getFailCount() + 1);
  163. } else {
  164. // 超过次数则禁用用户,并且错误次数重置为0
  165. userService.updateStatus(username, "0");
  166. userService.updateFailCount(username, 0);
  167. }
  168. // 并且抛出异常
  169. throw e;
  170. }
  171. /* 生成token */
  172. // authenticationService.useEnv(JwtConst.USR);
  173. // String token = authenticationService.createToken(Maps.ofMap(JwtConst.USR_ID, userid));
  174. // Date tokenDate = authenticationService.getExpireTime(token);
  175. String token = UniqueUtils.uuid().toLowerCase();
  176. Date tokenDate = DateUtils.plus(new Date(), 1, TimeUnits.DAYS);
  177. UserLogininfo appLoginInfo = userService.queryUserLogininfo(appToken);
  178. appLoginInfo.setVerificationCode(null);
  179. appLoginInfo.setCodeExpireTime(null);
  180. appLoginInfo.setUserId(userid);
  181. appLoginInfo.setToken(token);
  182. appLoginInfo.setExpireTime(tokenDate);
  183. /* 如果不允许其他地方登陆的话,删除其他地方登录过的缓存 */
  184. if (Boolean.FALSE.equals(systemSet.getAllowMultipleMachineLogins())) {
  185. userService.deleteUserLogininfoByUserId(userid);
  186. }
  187. /* 保存登录信息 */
  188. userService.updateUserLogininfo(appLoginInfo, appToken);
  189. return R.ok(
  190. "token", token,
  191. "userid", userid,
  192. "date", tokenDate
  193. );
  194. }
  195. /**
  196. * 刷新token
  197. */
  198. @PostMapping("/flush-token")
  199. public R<Void> flushToken(@RequestHeader("Authorization") String token) {
  200. // String sessionid = getSessionId();
  201. // String env = authenticationService.getEnv(token);
  202. UserLogininfo userLogininfo = userService.queryUserLogininfo(token);
  203. Date expireTime = DateUtils.plus(new Date(), 1, TimeUnits.DAYS);
  204. userLogininfo.setExpireTime(expireTime);
  205. userService.updateUserLogininfo(userLogininfo, token);
  206. return R.ok("expireTime", DateUtils.format(expireTime));
  207. }
  208. /**
  209. * 退出登录
  210. */
  211. @PostMapping("/sign-out")
  212. public R<Void> signout(@RequestHeader("Authorization") String token) {
  213. /* 添加到黑名单 */
  214. // Date expireTime = authenticationService.getExpireTime(token);
  215. // jvmCache.set(CacheConst.TOKEN_BLACKLIST(token), 0, expireTime);
  216. /* 删除登录日志中的数据 */
  217. userService.deleteUserLogininfoByToken(token);
  218. return R.ok();
  219. }
  220. /**
  221. * 获取系统设置
  222. */
  223. @PostMapping("/system/setting")
  224. public R<SystemSet> systemSet() {
  225. return R.ok(userService.systemSetting());
  226. }
  227. /**
  228. * 用户登录
  229. */
  230. @NV_TOKEN
  231. @PostMapping("/sec-sign-in")
  232. public R<AuthenticationOut> secsignin(@Valid @RequestBody AuthenticationSecUserIn authenticationUserIn) {
  233. String userId = authenticationUserIn.getUserId();
  234. SystemSet systemSet = userService.systemSetting();
  235. UserLogininfo userLogininfos = userService.queryUserLogininfosByUserIdPS(userId);
  236. if (systemSet.getVerificationCode()) {
  237. String verificationCode = userLogininfos.getVerificationCode();
  238. Assert.throwIfBool(verificationCode != null && verificationCode.equals(authenticationUserIn.getVerificationCode()), "验证码错误");
  239. boolean isCheckFull = systemSet.getVerificationCodeAa() ?
  240. Objects.equals(verificationCode, authenticationUserIn.getVerificationCode()) :
  241. Objects.equals(verificationCode.toLowerCase(), authenticationUserIn.getVerificationCode().toLowerCase());
  242. Assert.throwIfBool(isCheckFull, "验证码不正确");
  243. Date codeExpireTime = userLogininfos.getCodeExpireTime();
  244. Assert.throwIfBool(!DateUtils.gteq(new Date(), codeExpireTime), "-C401 验证码已过期");
  245. }
  246. /* 验证用户名密码是否可以登录 */
  247. String userid = userService.secsign(userId, authenticationUserIn.getPassword());
  248. return R.ok(
  249. "userid", userid
  250. );
  251. }
  252. // /**
  253. // * 获取系统设置
  254. // */
  255. // @PostMapping("/authQuery")
  256. // public R<SystemSet> authQuery(@RequestHeader("Authorization") String token)
  257. // {
  258. // String userid = authenticationService.claimsValue(token, JwtConst.USR_ID);
  259. // return R.ok(userService.authQuery(userid));
  260. // }
  261. //
  262. /**
  263. * 修改用户密码
  264. */
  265. @PostMapping("/reset-passwd")
  266. public R<Void> resetPasswd(@Valid @RequestBody ResetPasswdIn resetPasswdIn) {
  267. String userid = userService.idsign(resetPasswdIn.getUserId(), resetPasswdIn.getOriginPassword());
  268. SystemSet systemSet = userService.systemSetting();
  269. String pwdMatch = systemSet.getPwdCons();
  270. /* 修改密码 */
  271. User user = userService.userQuery(userid);
  272. user.setUserPwd(resetPasswdIn.getNewPassword());
  273. Assert.throwIfBool(Pattern.matches(pwdMatch, user.getUserPwd()), "密码不符合规则");
  274. String pwd = StringUtils.toLowerCase(DoubleCoder.MD5(resetPasswdIn.getNewPassword()));
  275. userService.updateUserPwd(userid, pwd);
  276. return R.ok();
  277. }
  278. /**
  279. * 修改用户密码
  280. */
  281. @PostMapping("/reset-secpasswd")
  282. public R<Void> resetSecPasswd(@Valid @RequestBody ResetSecPasswdIn resetPasswdIn) {
  283. String userid = resetPasswdIn.getUserId();
  284. /* 修改密码 */
  285. User user = userService.userQuery(userid);
  286. user.setUserPwd(resetPasswdIn.getNewPassword());
  287. SystemSet systemSet = userService.systemSetting();
  288. String pwdMatch = systemSet.getPwdCons();
  289. Assert.throwIfBool(Pattern.matches(pwdMatch, user.getUserPwd()), "密码不符合规则");
  290. String pwd = StringUtils.toLowerCase(DoubleCoder.MD5(resetPasswdIn.getNewPassword()));
  291. userService.updateUserSecPwd(userid, pwd);
  292. return R.ok();
  293. }
  294. // private String getSessionId() { return WebRequests.getHttpServletRequest().getSession().getId(); }
  295. }