AuthServiceImpl.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. package com.flow.service.impl;
  2. import com.baomidou.mybatisplus.core.toolkit.StringUtils;
  3. import com.flow.common.core.exception.BaseException;
  4. import com.flow.common.core.util.ApplicationContextUtil;
  5. import com.flow.common.core.util.SecurityContextUtil;
  6. import com.flow.dao.AuthDao;
  7. import com.flow.entity.Menu;
  8. import com.flow.entity.User;
  9. import com.flow.model.*;
  10. import com.flow.service.AuthService;
  11. import com.wf.captcha.ArithmeticCaptcha;
  12. import lombok.extern.slf4j.Slf4j;
  13. import org.json.JSONObject;
  14. import org.springframework.beans.factory.annotation.Autowired;
  15. import org.springframework.data.redis.core.StringRedisTemplate;
  16. import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  17. import org.springframework.security.core.Authentication;
  18. import org.springframework.security.core.context.SecurityContextHolder;
  19. import org.springframework.security.core.userdetails.UserDetails;
  20. import org.springframework.security.core.userdetails.UserDetailsService;
  21. import org.springframework.security.core.userdetails.UsernameNotFoundException;
  22. import org.springframework.security.oauth2.common.OAuth2AccessToken;
  23. import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
  24. import org.springframework.security.oauth2.provider.*;
  25. import org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter;
  26. import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
  27. import org.springframework.security.oauth2.provider.token.TokenStore;
  28. import org.springframework.stereotype.Service;
  29. import org.springframework.web.context.request.RequestContextHolder;
  30. import org.springframework.web.context.request.ServletRequestAttributes;
  31. import javax.servlet.http.HttpServletRequest;
  32. import java.nio.charset.StandardCharsets;
  33. import java.security.KeyFactory;
  34. import java.security.PrivateKey;
  35. import java.security.spec.PKCS8EncodedKeySpec;
  36. import java.util.Base64;
  37. import javax.crypto.Cipher;
  38. import java.util.*;
  39. import java.util.concurrent.TimeUnit;
  40. import java.util.stream.Collectors;
  41. @Slf4j
  42. @Service
  43. public class AuthServiceImpl implements AuthService {
  44. @Autowired
  45. private ClientDetailsService clientDetailsService;
  46. @Autowired
  47. private TokenStore tokenStore;
  48. @Autowired
  49. private StringRedisTemplate redisTemplate;
  50. @Autowired
  51. private AuthDao authDao;
  52. @Autowired
  53. private UserDetailsService userDetailsService;
  54. @Autowired
  55. private AuthorizationServerTokenServices tokenServices;
  56. private static final String PRIVATE_KEY = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALE9Y/QdMET28R4z\n" +
  57. "fhDHTdTyhWYLrEipY9G4jm3wnTMQNC50CBco+PLwTRDdxfzTRQ0FPHaBR9FE2s42\n" +
  58. "oAsoOcnVITqoJQN5c57Pyxr3kZD13gFfulKNkus9+cIFMG1vksaRjnOaWa2kbYBX\n" +
  59. "14mv6RCqGz+vRziePBoONUbiQXdlAgMBAAECgYBjSDdAXEVYrFdeiouYjHwdyAhP\n" +
  60. "pERKo5BFvzMRhJIaM353cwnBJ3NkapVQ2Fn6iMIKTB+VZk+7eu1yTAkUluDfLowd\n" +
  61. "REZS4ipOBY5UuNnjbXmSOoUQw6vRnox0X4x6S1vd4FBHgpVe1VkiE7Nz5U7Clyd5\n" +
  62. "yw2P1lHwMyB/guAH4QJBAN3dGkMASj0jm23maHOfehp/zlACB8HpMKuV4z/bEg45\n" +
  63. "nC9Hw5NloUHrXdzEXP1+S46MCH2THflxDVYtnZTRLO0CQQDMgp3Jrn7kkKtNceZF\n" +
  64. "R08hLbVmfNlatgONgFJ5JnR+GTQ6o2gwM6SLyoBkfAIiEDpr6c6nBXTU09GOYxBk\n" +
  65. "+h1ZAkB32pXxVBrG5JF20V3j+GcyIZEGz9H5A0xzpUlambIrVRv2vsH8wo5W2hue\n" +
  66. "w8Woe629mBCOJgevVU9rGsFiP44RAkEApbTYAQjAjJakFpZJjKzg8vNEXoye2R9N\n" +
  67. "9aOaL8v27A2kAjdRPm050IL+UW0hlVQs4i+KYE7NgX03+PVP3WHD0QJBANLo4PRw\n" +
  68. "7Y+dLPAzuazsD3/5SYaSh+KSD/+tVbc6CFvLyfFUKp/a4PzzvGaLo/Ky/ffOY5k0\n" +
  69. "hmavbHCKcg+r+hg=";
  70. @Override
  71. public ImageCode getImageCode() {
  72. // 算术验证码:三个参数分别为宽、高、位数
  73. ArithmeticCaptcha captcha = new ArithmeticCaptcha(111, 36, 2);
  74. // code保存到redis
  75. String code = captcha.text().toLowerCase();
  76. String uuid = UUID.randomUUID().toString();
  77. redisTemplate.opsForValue().set("image_code:" + uuid, code, 2L, TimeUnit.MINUTES);
  78. // 返回结果
  79. return new ImageCode(captcha.toBase64(), uuid);
  80. }
  81. // 盐值登录
  82. @Override
  83. public AccessToken saltLogin(SaltLogin salt) {
  84. log.info("盐值登录");
  85. if (StringUtils.isBlank(salt.getSalt())) {
  86. throw new BaseException("盐值不能为空");
  87. }
  88. log.info("盐值: " + salt.getSalt());
  89. String saltData = salt.getSalt();
  90. AccessToken accessToken = null;
  91. long now = System.currentTimeMillis();
  92. String decryptedData = null;
  93. try {
  94. decryptedData = decrypt(saltData);
  95. } catch (Exception e) {
  96. throw new BaseException("盐值解析异常,请联系管理员" + e.getMessage());
  97. }
  98. log.info("解密后的数据: " + decryptedData);
  99. if (StringUtils.isBlank(decryptedData)) {
  100. throw new BaseException("盐值数据为空,请联系管理员");
  101. } else {
  102. JSONObject jsonObject = new JSONObject(decryptedData);
  103. String user = jsonObject.getString("user");
  104. long time = jsonObject.getLong("time");
  105. String form = jsonObject.getString("form");
  106. // 判断时间戳是否过期
  107. // if (now - time < 10000) {
  108. // throw new BaseException("请求超时,请重试");
  109. // } else {
  110. //
  111. // }
  112. if (StringUtils.isNotBlank(user)) {
  113. accessToken = loginByUsername(user);
  114. }
  115. }
  116. return accessToken;
  117. }
  118. // RSA解密
  119. public String decrypt(String encryptedData) throws Exception {
  120. String privateKeyBase64 = PRIVATE_KEY.replaceAll("\\s", "");
  121. // 将Base64编码的私钥转换为PrivateKey对象
  122. byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyBase64);
  123. // 生成PrivateKey对象
  124. PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
  125. KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  126. PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
  127. // 创建Cipher对象进行解密
  128. Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
  129. cipher.init(Cipher.DECRYPT_MODE, privateKey);
  130. // 解密
  131. encryptedData = encryptedData.replaceAll(" ", "+");
  132. byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData);
  133. byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
  134. // 将解密后的字节转换为字符串
  135. return new String(decryptedBytes, StandardCharsets.UTF_8);
  136. }
  137. // 获取时间戳
  138. @Override
  139. public Long getTimeStamp() {
  140. return System.currentTimeMillis();
  141. }
  142. public AccessToken loginByUsername(String username) {
  143. UserDetails userDetails = userDetailsService.loadUserByUsername(username);
  144. ClientDetails clientDetails = clientDetailsService.loadClientByClientId("client");
  145. // 直接创建OAuth2认证
  146. OAuth2Request oauth2Request = new OAuth2Request(
  147. Collections.emptyMap(),
  148. clientDetails.getClientId(),
  149. null,
  150. true,
  151. clientDetails.getScope(),
  152. null,
  153. null,
  154. null,
  155. null
  156. );
  157. Authentication userAuth = new UsernamePasswordAuthenticationToken(
  158. userDetails, null, userDetails.getAuthorities());
  159. OAuth2Authentication oauth2Authentication = new OAuth2Authentication(oauth2Request, userAuth);
  160. // 直接生成token
  161. OAuth2AccessToken token = tokenServices.createAccessToken(oauth2Authentication);
  162. return new AccessToken(token);
  163. }
  164. @Override
  165. public AccessToken login(LoginForm loginForm) {
  166. OAuth2AccessToken oAuth2AccessToken = null;
  167. String uuid = loginForm.getUuid();
  168. String code = loginForm.getCode();
  169. if (StringUtils.isBlank(code) || StringUtils.isBlank(uuid)) {
  170. throw new BaseException("验证码不能为空");
  171. }
  172. String redisCode = redisTemplate.opsForValue().get("image_code:" + uuid);
  173. if (StringUtils.isBlank(redisCode)) {
  174. throw new BaseException("验证码不存在或已过期");
  175. }
  176. if (!code.equalsIgnoreCase(redisCode)) {
  177. throw new BaseException("验证码错误");
  178. }
  179. HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
  180. request.setAttribute("login_type", "social_login");
  181. ClientDetails clientDetails = clientDetailsService.loadClientByClientId("client");
  182. Map<String, String> requestParameters = new HashMap<>(5);
  183. requestParameters.put("grant_type", "password");
  184. requestParameters.put("username", loginForm.getUsername());
  185. requestParameters.put("password", loginForm.getPassword());
  186. TokenRequest tokenRequest = new TokenRequest(
  187. requestParameters,
  188. clientDetails.getClientId(), clientDetails.getScope(),
  189. requestParameters.get("grant_type")
  190. );
  191. try {
  192. ResourceOwnerPasswordTokenGranter granter = ApplicationContextUtil.getBean(ResourceOwnerPasswordTokenGranter.class);
  193. oAuth2AccessToken = granter.grant(tokenRequest.getGrantType(), tokenRequest);
  194. } catch (InvalidGrantException ex) {
  195. throw new BaseException("用户名或密码错误");
  196. }
  197. return new AccessToken(oAuth2AccessToken);
  198. }
  199. @Override
  200. public void logout() {
  201. String accessToken = SecurityContextUtil.getAccessToken();
  202. if (StringUtils.isNotBlank(accessToken)) {
  203. OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(SecurityContextUtil.getAccessToken());
  204. tokenStore.removeAccessToken(oAuth2AccessToken);
  205. if (Objects.nonNull(oAuth2AccessToken.getRefreshToken())) {
  206. tokenStore.removeRefreshToken(oAuth2AccessToken.getRefreshToken());
  207. }
  208. SecurityContextHolder.getContext().setAuthentication(null);
  209. SecurityContextHolder.clearContext();
  210. }
  211. }
  212. @Override
  213. public User info() {
  214. String userId = SecurityContextUtil.getUserId();
  215. Optional<User> optional = Optional.ofNullable(authDao.queryUserByUserId(userId));
  216. return optional.orElse(null);
  217. }
  218. @Override
  219. public Permission permissions() {
  220. String userId = SecurityContextUtil.getUserId();
  221. List<Menu> menus = "admin".equals(userId) ?
  222. authDao.getMenuAll() :
  223. authDao.getMenuByUserId(userId);
  224. // 按钮权限
  225. Set<String> buttonList = menus.stream().filter(b -> b.getType() == 2)
  226. .map(Menu::getPermission)
  227. .collect(Collectors.toSet());
  228. // 构建菜单
  229. List<Menu> menuList = menus.stream().filter(m -> m.getType() != 2).collect(Collectors.toList());
  230. List<Route> routeList = this.buildMenu(menuList);
  231. // 权限信息
  232. Permission permission = new Permission();
  233. permission.setRoutes(routeList);
  234. permission.setButtons(buttonList);
  235. return permission;
  236. }
  237. @Override
  238. public List<Route> buildMenu(List<Menu> menus) {
  239. return menus.stream()
  240. .filter(m -> m.getPid() == 0)
  241. .sorted(Comparator.comparingInt(Menu::getSort))
  242. .map(m -> {
  243. Route route = new Route(m);
  244. route.setChildren(buildMenu(m, menus));
  245. return route;
  246. }).collect(Collectors.toList());
  247. }
  248. private List<Route> buildMenu(Menu root, List<Menu> allListTree) {
  249. return allListTree.stream().filter((treeEntity) -> treeEntity.getPid().equals(root.getId()))
  250. .sorted(Comparator.comparingInt(Menu::getSort))
  251. .map((treeEntity) -> {
  252. Route routeDTO = new Route(treeEntity);
  253. routeDTO.setChildren(this.buildMenu(treeEntity, allListTree));
  254. return routeDTO;
  255. }).collect(Collectors.toList());
  256. }
  257. }