AuthAccessTokenServiceImpl.java 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. package com.dk.oauth.service.impl;
  2. import com.alibaba.fastjson.JSONObject;
  3. import com.baomidou.mybatisplus.core.metadata.IPage;
  4. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  5. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  6. import com.dk.common.infrastructure.constant.Constant;
  7. import com.dk.common.infrastructure.constant.OauthConstants;
  8. import com.dk.common.infrastructure.enums.ErrorCodeEnum;
  9. import com.dk.common.response.ResponseCodeEnum;
  10. import com.dk.common.response.ResponseResultUtil;
  11. import com.dk.common.response.ResponseResultVO;
  12. import com.dk.common.util.DateUtils;
  13. import com.dk.common.util.HttpUtils;
  14. import com.dk.oauth.config.WxConfig;
  15. import com.dk.oauth.dto.AuthAccessTokenDto;
  16. import com.dk.oauth.entity.*;
  17. import com.dk.oauth.mapper.AuthAccessTokenMapper;
  18. import com.dk.oauth.mapper.CompanyMapper;
  19. import com.dk.oauth.mapper.UserMapper;
  20. import com.dk.oauth.service.IAuthAccessTokenService;
  21. import com.dk.oauth.shiro.jwt.JWTGenerator;
  22. import com.dk.oauth.util.AESSecurityUtil;
  23. import com.dk.oauth.util.UUID;
  24. import lombok.extern.slf4j.Slf4j;
  25. import org.apache.oltu.oauth2.as.issuer.OAuthIssuerImpl;
  26. import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
  27. import org.apache.shiro.SecurityUtils;
  28. import org.slf4j.Logger;
  29. import org.slf4j.LoggerFactory;
  30. import org.springframework.beans.factory.annotation.Autowired;
  31. import org.springframework.beans.factory.annotation.Value;
  32. import org.springframework.data.redis.core.StringRedisTemplate;
  33. import org.springframework.stereotype.Service;
  34. import org.springframework.transaction.annotation.Transactional;
  35. import javax.annotation.Resource;
  36. import javax.servlet.http.HttpServletRequest;
  37. import javax.servlet.http.HttpServletResponse;
  38. import java.io.File;
  39. import java.util.Date;
  40. import java.util.HashMap;
  41. import java.util.Map;
  42. import java.util.concurrent.TimeUnit;
  43. /**
  44. * (AuthAccessToken)表服务实现类
  45. *
  46. * @author dapeng
  47. * @since 2022-07-01 09:41:05
  48. */
  49. @Slf4j
  50. @Service("authAccessTokenService")
  51. public class AuthAccessTokenServiceImpl extends ServiceImpl<AuthAccessTokenMapper, AuthAccessToken> implements IAuthAccessTokenService {
  52. private final Logger logger = LoggerFactory.getLogger(this.getClass());
  53. @Resource
  54. private AuthAccessTokenMapper authAccessTokenMapper;
  55. @Resource
  56. private UserMapper userMapper;
  57. @Resource
  58. private CompanyMapper companyMapper;
  59. @Value("${aes-key}")
  60. private String AESKey;
  61. @Resource
  62. private StringRedisTemplate stringRedisTemplate;
  63. @Autowired
  64. private WxConfig config;
  65. /**
  66. * 分页查询
  67. *
  68. * @param
  69. * @return
  70. */
  71. @Override
  72. public ResponseResultVO pageQuery(AuthAccessTokenDto authAccessTokenDto) {
  73. if (null == authAccessTokenDto.getPage()) {
  74. authAccessTokenDto.setPage(new Page(0, 10));
  75. }
  76. IPage<AuthAccessTokenDto> authAccessTokenDtos = authAccessTokenMapper.pageQuery(authAccessTokenDto.getPage(), authAccessTokenDto);
  77. return ResponseResultUtil.success(authAccessTokenDtos);
  78. }
  79. /**
  80. * @desc : 查询用户最新token
  81. * @author : 洪旭东
  82. * @date : 2022-08-02 17:30
  83. */
  84. public String getCurrentToken(Long userId) {
  85. return authAccessTokenMapper.getCurrentToken(userId);
  86. }
  87. /**
  88. * @desc : 登录凭证校验
  89. * @author : 姜永辉
  90. * @date : 2022/5/12 9:33
  91. */
  92. public ResponseResultVO<JSONObject> loginWechat(Map<String, Object> map) {
  93. ResponseResultVO<JSONObject> res = HttpUtils.get(config.getCode2Session()
  94. + "appid=" + config.getAppId()
  95. + "&secret=" + config.getAppSecret()
  96. + "&js_code=" + map.get("code")
  97. + "&grant_type=authorization_code");
  98. if (res.getData() != null && res.getData().get("errcode") != null) {
  99. return ResponseResultUtil.error(ResponseCodeEnum.OPERATE_FAIL.getCode(),
  100. res.getData().get("errmsg") == null ? res.getData().getString("errcode")
  101. : "微信服务器异常:" + res.getData().getString("errmsg"));
  102. }
  103. return res;
  104. }
  105. /**
  106. * @desc : 获取token
  107. * @author : 洪旭东
  108. * @date : 2024-02-20 14:04
  109. */
  110. public ResponseResultVO token(HttpServletRequest request) {
  111. UserLogin userLogin = userMapper.getByPhone(request.getParameter("phone"));
  112. if (userLogin == null || (!userLogin.getUserPwd().equals(request.getParameter("password")))) {
  113. //无用户 或 密码错误
  114. return ResponseResultUtil.error(ErrorCodeEnum.USER_PASSWORD_ERROR.getCode(), ErrorCodeEnum.USER_PASSWORD_ERROR.getMessage());
  115. }
  116. userLogin.checkUserLogin();
  117. try {
  118. // 设置应用代码
  119. userLogin.setAppCode(Constant.AppCode.WEB.getCode());
  120. return createToken(userLogin);
  121. } catch (Exception e) {
  122. log.error("获取accessToken发生异常=", e);
  123. return ResponseResultUtil.error(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
  124. }
  125. }
  126. /**
  127. * @desc : 小程序通过微信openid登录
  128. * @author : 洪旭东
  129. * @date : 2024-02-20 14:04
  130. */
  131. @Transactional(rollbackFor = Exception.class)
  132. public ResponseResultVO wxToken(UserWxLogin userWxLogin) {
  133. // todo
  134. userWxLogin.setUserWxid("1");
  135. UserLogin userLogin = userMapper.getByWxid(userWxLogin.getUserWxid());
  136. if (userLogin == null) {
  137. //无用户
  138. return ResponseResultUtil.error(ErrorCodeEnum.USER_NOT_EXIST.getCode(), ErrorCodeEnum.USER_NOT_EXIST.getMessage());
  139. }
  140. userLogin.checkUserLogin();
  141. try {
  142. // 设置应用代码
  143. userLogin.setAppCode(Constant.AppCode.WEIXIN.getCode());
  144. return createToken(userLogin);
  145. } catch (Exception e) {
  146. log.error("获取accessToken发生异常=", e);
  147. return ResponseResultUtil.error(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
  148. }
  149. }
  150. /**
  151. * @desc : 注册
  152. * @author : 洪旭东
  153. * @date : 2024-02-20 13:55
  154. */
  155. @Transactional(rollbackFor = Exception.class)
  156. public ResponseResultVO<?> register(UserWxLogin userWxLogin) {
  157. UserLogin userLogin = userMapper.getByWxid(userWxLogin.getUserWxid());
  158. //通过openid查到用户,但手机号为空
  159. if (userLogin != null && userLogin.getUserPhone() == null) {
  160. //将其他微信用户的相同电话清空
  161. userMapper.cleanPhone(userWxLogin.getUserPhone());
  162. //更新当前手机号
  163. userMapper.updatePhone(userLogin.getUserId(), userWxLogin.getUserPhone());
  164. }
  165. if (userLogin == null) {
  166. //openid没查到,用手机号再查一次
  167. userLogin = userMapper.getByPhone(userWxLogin.getUserPhone());
  168. } else if (userLogin.getUserWxid() == null) {
  169. //通过手机号查到了用户,但是openid是空,更新上当前的openid
  170. userMapper.updateWxid(userLogin.getUserId(), userWxLogin.getUserWxid());
  171. }
  172. //用户无法通过openid或手机号查到 或 通过手机号查到了,但openid不同
  173. if (userLogin == null || !userWxLogin.getUserWxid().equals(userLogin.getUserWxid())) {
  174. //将其他微信用户的相同电话清空
  175. userMapper.cleanPhone(userWxLogin.getUserPhone());
  176. //注册
  177. userMapper.insert(userWxLogin);
  178. userLogin = userMapper.getByWxid(userWxLogin.getUserWxid());
  179. }
  180. userLogin.checkUserLogin();
  181. try {
  182. return createToken(userLogin);
  183. } catch (Exception e) {
  184. log.error("获取accessToken发生异常=", e);
  185. return ResponseResultUtil.error(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
  186. }
  187. }
  188. /**
  189. * @desc : 验证当前扫码登录是否匹配到openid
  190. * @author : 洪旭东
  191. * @date : 2024-02-20 14:04
  192. */
  193. public ResponseResultVO<?> checkLoginOpenId(String uuid) {
  194. String openId = stringRedisTemplate.opsForValue().get(Constant.RedisConstant.REDIS_LOGIN_UUID.getName() + uuid);
  195. if (openId != null && !"".equals(openId)) {
  196. UserLogin userLogin = userMapper.getByWxid(openId);
  197. if (userLogin == null) {
  198. stringRedisTemplate.opsForValue().set(Constant.RedisConstant.REDIS_LOGIN_UUID.getName() + uuid, "", 5, TimeUnit.MINUTES);
  199. //无用户
  200. return ResponseResultUtil.error(ErrorCodeEnum.USER_NOT_EXIST.getCode(), ErrorCodeEnum.USER_NOT_EXIST.getMessage());
  201. }
  202. userLogin.checkUserLogin();
  203. try {
  204. return createToken(userLogin);
  205. } catch (OAuthSystemException e) {
  206. e.printStackTrace();
  207. log.error("获取accessToken发生异常=", e);
  208. return ResponseResultUtil.error(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
  209. }
  210. } else {
  211. return ResponseResultUtil.error(ResponseCodeEnum.NO_LOGIN);
  212. }
  213. }
  214. /**
  215. * @desc : 登录验证成功,生成token
  216. * @author : 洪旭东
  217. * @date : 2024-02-20 10:31
  218. */
  219. private ResponseResultVO<?> createToken(UserLogin userLogin) throws OAuthSystemException {
  220. String clientId = "dkic";
  221. AuthAccessToken authAccessToken = new AuthAccessToken();
  222. // region 开始生成Access Token
  223. String username = "";
  224. String userId = "";
  225. username = userLogin.getUserName();
  226. userId = String.valueOf(userLogin.getUserId());
  227. // endregion
  228. //当前公司
  229. CompanyResponse company = null;
  230. String accessToken = "";
  231. if (userLogin.getCurrentCp() != null) {
  232. company = companyMapper.getByCpId(userLogin.getCurrentCp());
  233. if (company != null) {
  234. JWTGenerator jwtGenerator = new JWTGenerator();
  235. jwtGenerator.setSalt(username);
  236. jwtGenerator.setUsername(username);
  237. jwtGenerator.setUserId(userId);
  238. jwtGenerator.setClientId(clientId);
  239. jwtGenerator.setCpId(company.getCpId().toString());
  240. jwtGenerator.setCpCode(company.getCpCode());
  241. OAuthIssuerImpl oAuthIssuer = new OAuthIssuerImpl(jwtGenerator);
  242. accessToken = oAuthIssuer.accessToken();
  243. log.info("服务器生成的accessToken=" + accessToken);
  244. // 保存token
  245. authAccessToken.setId(UUID.uuid32());
  246. authAccessToken.setClientId(clientId);
  247. authAccessToken.setTokenId(accessToken);
  248. authAccessToken.setCreateDate(new Date());
  249. authAccessToken.setCpId(company.getCpId().toString());
  250. authAccessToken.setCpCode(company.getCpCode());
  251. authAccessToken.setTokenExpiredSeconds(OauthConstants.EXPIRES_IN);
  252. log.info("---->>>SecurityUtils.getSubject().isAuthenticated() = " + SecurityUtils.getSubject().isAuthenticated());
  253. // endregion
  254. // region 加密accessToken
  255. try {
  256. accessToken = AESSecurityUtil.encrypt(AESKey, accessToken);
  257. } catch (Exception e) {
  258. logger.error("sorry,accessToken({}) encode faild!!", accessToken);
  259. }
  260. }
  261. }
  262. UserLoginSuccess userLoginSuccess = new UserLoginSuccess()
  263. .setByUserLogin(userLogin)
  264. .setAccessToken(accessToken)
  265. .setCompany(company)
  266. // .setMenuList(userMapper.getMenuByUser(userLogin.getAppCode(),userId,company.getCpId(),"zh_CN"))
  267. ;
  268. return ResponseResultUtil.success(userLoginSuccess);
  269. }
  270. /**
  271. * @desc : 生成微信临时二维码
  272. * @author : 洪旭东
  273. * @date : 2024-02-20 17:00
  274. */
  275. public ResponseResultVO<?> getQrCode(String uuid) {
  276. //获取access token
  277. String accessToken = stringRedisTemplate.opsForValue().get(Constant.RedisConstant.REDIS_WECHAT_ACCESS_TOKEN.getName());
  278. if (accessToken == null) {
  279. ResponseResultVO<JSONObject> tokenRes = HttpUtils.get(config.getAccessToken() + "appid=" + config.getOffiAccountAppId() + "&secret=" + config.getOffiAccountAppSecret());
  280. if (tokenRes.getCode() == ResponseCodeEnum.SUCCESS.getCode()) {
  281. stringRedisTemplate.opsForValue().set(Constant.RedisConstant.REDIS_WECHAT_ACCESS_TOKEN.getName(), tokenRes.getData().getString("access_token"), 5, TimeUnit.MINUTES);
  282. accessToken = tokenRes.getData().getString("access_token");
  283. } else {
  284. return tokenRes;
  285. }
  286. }
  287. //生成临时二维码
  288. String ticket;
  289. JSONObject json = new JSONObject();
  290. //有效期30天,最大可设置30天
  291. json.put("expire_seconds", 2592000);
  292. json.put("action_name", "QR_STR_SCENE");
  293. JSONObject scene = new JSONObject();
  294. scene.put("scene_str", "dkic-scan-login-" + uuid);
  295. JSONObject actionInfo = new JSONObject();
  296. actionInfo.put("scene", scene);
  297. json.put("action_info", actionInfo);
  298. ResponseResultVO<JSONObject> ticketRes = HttpUtils.post(config.getQrcodeCreate() + accessToken, json);
  299. if (ticketRes.getCode() == ResponseCodeEnum.SUCCESS.getCode()) {
  300. ticket = ticketRes.getData().getString("ticket");
  301. } else {
  302. return ticketRes;
  303. }
  304. stringRedisTemplate.opsForValue().set(Constant.RedisConstant.REDIS_LOGIN_UUID.getName() + uuid, "", 5, TimeUnit.MINUTES);
  305. return ResponseResultUtil.success(config.getShowQrCode() + ticket);
  306. }
  307. /**
  308. * @desc : 生成微信小程序二维码
  309. * @author : 姜永辉
  310. * @date : 2024-02-20 17:00
  311. */
  312. public ResponseResultVO<?> getWxQrCode(Map<String, Object> map) {
  313. System.out.println("getWxQrCode:" + map);
  314. //获取access token
  315. String accessToken = stringRedisTemplate.opsForValue().get(Constant.RedisConstant.REDIS_WECHAT_QRCODE_ACCESS_TOKEN.getName());
  316. if (accessToken == null) {
  317. ResponseResultVO<JSONObject> tokenRes = HttpUtils.get(config.getAccessToken()
  318. + "appid=" + config.getAppId()
  319. + "&secret=" + config.getAppSecret());
  320. if (tokenRes.getCode() == ResponseCodeEnum.SUCCESS.getCode()) {
  321. stringRedisTemplate.opsForValue().set(Constant.RedisConstant.REDIS_WECHAT_QRCODE_ACCESS_TOKEN.getName(),
  322. tokenRes.getData().getString("access_token"), 5, TimeUnit.MINUTES);
  323. accessToken = tokenRes.getData().getString("access_token");
  324. } else {
  325. return tokenRes;
  326. }
  327. }
  328. //二维码参数
  329. Map<String, Object> param = new HashMap<>();
  330. param.put("page", "pages/welcome/welcome");
  331. param.put("scene", "s=" + map.get("openid"));
  332. param.put("check_path", false);
  333. //生成二维码接口地址
  334. String url = config.getUnlimitedQRCode() + accessToken;
  335. //文件名称
  336. String fileName=java.util.UUID.randomUUID().toString() + ".png";
  337. //文件相对路径 - 返回
  338. String relativePath="/qr_code/"+ fileName;
  339. //文件绝对路径 - 写
  340. String absolutelyPath = this.createDirByPath("qr_code") + fileName;
  341. ResponseResultVO<String> responseResultVO = HttpUtils.postReturnFile(url, param, absolutelyPath);
  342. if(responseResultVO.getCode()==ResponseCodeEnum.SUCCESS.getCode()){
  343. return ResponseResultUtil.success(relativePath);
  344. }else{
  345. return responseResultVO;
  346. }
  347. }
  348. private String createDirByPath(String type) {
  349. /**
  350. * @date_time 2020-07-31 09:42
  351. * @author H_x_d
  352. * @description 根据类型创建目录文件夹
  353. * @param [type]
  354. * @return java.lang.String
  355. */
  356. String path = type + "/" + DateUtils.formatNow("yyyy-MM-dd") + "/";
  357. String base = config.getUploadPath();
  358. File baseDir = new File(base);
  359. if (!baseDir.exists()) {
  360. baseDir.mkdir();
  361. }
  362. String[] paths = path.split("/");
  363. for (int i = 0; i < paths.length; i++) {
  364. base = base + "/" + paths[i];
  365. File dir = new File(base);
  366. if (!dir.exists()) {
  367. dir.mkdir();
  368. }
  369. }
  370. return base + "/";
  371. }
  372. }