JwtUtil.java 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. package com.free.utils;
  2. import com.auth0.jwt.algorithms.Algorithm;
  3. import com.auth0.jwt.interfaces.Claim;
  4. import com.auth0.jwt.interfaces.DecodedJWT;
  5. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  6. import com.baomidou.mybatisplus.core.toolkit.StringUtils;
  7. import com.free.config.CustomizationException;
  8. import com.free.config.ExceptionEnum;
  9. import com.free.entity.system.LoginRecord;
  10. import com.free.service.system.LoginRecordService;
  11. import com.auth0.jwt.JWT;
  12. import com.auth0.jwt.JWTCreator;
  13. import java.time.LocalDateTime;
  14. import java.util.Date;
  15. import java.util.HashMap;
  16. import java.util.Map;
  17. import javax.annotation.PostConstruct;
  18. import javax.servlet.http.HttpServletRequest;
  19. import org.springframework.beans.factory.annotation.Autowired;
  20. import org.springframework.stereotype.Component;
  21. import org.springframework.web.context.request.RequestContextHolder;
  22. import org.springframework.web.context.request.ServletRequestAttributes;
  23. @Component
  24. public class JwtUtil {
  25. public static final String TOKEN_HEADER = "Authorization";
  26. public static final String TOKEN_PREFIX = "Free ";
  27. // 过期时间, 半个小时
  28. private static final long EXPIRE_MIN = 30;
  29. private static final long EXPIRE_TIME = EXPIRE_MIN * 60 * 1000;
  30. // 密钥
  31. private static final String SECRET = "Ziyouyanfa!@#";
  32. @Autowired
  33. private LoginRecordService lrs;
  34. private static JwtUtil jwtUtil = new JwtUtil();
  35. @PostConstruct
  36. public void init() {
  37. jwtUtil = this;
  38. jwtUtil.lrs = this.lrs;
  39. }
  40. /**
  41. * 生成签名
  42. *
  43. * @param map 数据
  44. * @param secret 密码
  45. * @return 加密后的token
  46. */
  47. public static String sign(Map<String, Object> map) {
  48. Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
  49. Algorithm algorithm = Algorithm.HMAC256(SECRET); // 使用HS256算法
  50. JWTCreator.Builder builder = JWT.create();
  51. for (Map.Entry<String, Object> entry : map.entrySet()) {
  52. String k = entry.getKey();
  53. String v = (String) entry.getValue();
  54. builder.withClaim(k, v);
  55. }
  56. String token = builder.withExpiresAt(date)
  57. .sign(algorithm);
  58. StringBuilder sb = new StringBuilder();
  59. sb.append(TOKEN_PREFIX);
  60. sb.append(token);
  61. String returnToken = sb.toString();
  62. // 创建登录数据
  63. createLoginRecord(token);
  64. return returnToken;
  65. }
  66. /**
  67. * 注销用户,退出登录
  68. * 将token置空,在校验的时候会处理没有token的情况
  69. *
  70. * @param token
  71. */
  72. public static void logOff(String token) {
  73. Map<String, Object> map = getDetails(token);
  74. String user_id = (String) map.get("id");
  75. String type = (String) map.get("type");
  76. QueryWrapper<LoginRecord> qw = new QueryWrapper<>();
  77. qw.eq("user_id", user_id);
  78. qw.eq("type", type);
  79. LoginRecord record = jwtUtil.lrs.getOne(qw);
  80. // 没找到数据不需要处理
  81. if (null == record) {
  82. return;
  83. }
  84. // token不一致,不需要处理
  85. String dbToken = record.getToken();
  86. if (null == dbToken || !dbToken.equals(token)) {
  87. return;
  88. }
  89. // token置空
  90. LoginRecord lr = new LoginRecord();
  91. lr.setToken(null);
  92. lr.setId(record.getId());
  93. jwtUtil.lrs.updateById(lr);
  94. }
  95. /**
  96. * 创建登录数据
  97. *
  98. * @param token jwt
  99. */
  100. public static void createLoginRecord(String token) {
  101. Map<String, Object> map = getDetails(token);
  102. String user_id = (String) map.get("id");
  103. String type = (String) map.get("type");
  104. // 第一次登录是创建,以后都是更新, 每个用户都有1个登录数据,但是能否使用要看过期时间
  105. QueryWrapper<LoginRecord> qw = new QueryWrapper<>();
  106. qw.eq("user_id", user_id);
  107. qw.eq("type", type);
  108. LoginRecord histroy = jwtUtil.lrs.getOne(qw);
  109. // 准备数据
  110. LocalDateTime last_time = LocalDateTime.now();
  111. LocalDateTime expire_time = LocalDateTime.now().plusMinutes(EXPIRE_MIN);
  112. HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
  113. String ip = request.getRemoteAddr();
  114. if (null == histroy) {
  115. // 创建数据
  116. LoginRecord lr = new LoginRecord();
  117. lr.setExpire_time(expire_time);
  118. lr.setLast_time(last_time);
  119. lr.setToken(token);
  120. lr.setType(type);
  121. lr.setUser_id(user_id);
  122. lr.setLast_ip(ip);
  123. jwtUtil.lrs.save(lr);
  124. } else {
  125. // 修改数据
  126. LoginRecord lr = new LoginRecord();
  127. lr.setExpire_time(expire_time);
  128. lr.setLast_time(last_time);
  129. lr.setToken(token);
  130. lr.setLast_ip(ip);
  131. lr.setId(histroy.getId());
  132. jwtUtil.lrs.updateById(lr);
  133. }
  134. }
  135. /**
  136. * token续期
  137. *
  138. * @param token jwt
  139. */
  140. public static void renewal(String token) {
  141. Map<String, Object> map = getDetails(token);
  142. String user_id = (String) map.get("id");
  143. String type = (String) map.get("type");
  144. QueryWrapper<LoginRecord> qw = new QueryWrapper<>();
  145. qw.eq("user_id", user_id).eq("type", type);
  146. LoginRecord histroy = jwtUtil.lrs.getOne(qw);
  147. // 准备数据
  148. LocalDateTime expire_time = LocalDateTime.now().plusMinutes(EXPIRE_MIN);
  149. LocalDateTime last_time = LocalDateTime.now();
  150. HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
  151. String ip = request.getRemoteAddr();
  152. if (null == histroy) {
  153. // 没有数据,转至创建
  154. createLoginRecord(token);
  155. } else {
  156. // 修改过期时间,使用时间,使用ip
  157. LoginRecord lr = new LoginRecord();
  158. lr.setExpire_time(expire_time);
  159. lr.setId(histroy.getId());
  160. lr.setLast_ip(ip);
  161. lr.setLast_time(last_time);
  162. lr.setToken(token);
  163. jwtUtil.lrs.updateById(lr);
  164. }
  165. }
  166. /**
  167. * 校验token是否正确
  168. *
  169. * @param token 令牌
  170. * @return 是否正确
  171. */
  172. public static void verify(String token) {
  173. // 解开token,查看数据
  174. Map<String, Object> map = getDetails(token);
  175. String user_id = (String) map.get("id");
  176. String type = (String) map.get("type");
  177. QueryWrapper<LoginRecord> qw = new QueryWrapper<>();
  178. qw.eq("user_id", user_id).eq("type", type);
  179. LoginRecord histroy = jwtUtil.lrs.getOne(qw);
  180. if (null == histroy) {
  181. throw new CustomizationException(ExceptionEnum.NO_LOGIN_RECORD);
  182. }
  183. // 获取数据库的token
  184. String dbToken = histroy.getToken();
  185. if (null == dbToken) {
  186. throw new CustomizationException(ExceptionEnum.ACCOUNT_IS_LOGOUT);
  187. }
  188. // 取出过期时间,和当前时间进行比较
  189. LocalDateTime nowTime = LocalDateTime.now();
  190. boolean is_after = histroy.getExpire_time().isAfter(nowTime);
  191. if (!is_after) {
  192. throw new CustomizationException(ExceptionEnum.TOKEN_INVALID);
  193. }
  194. // token对比,如果时间允许,但是token码不一致,则说明在其他地点登录
  195. if (!dbToken.equals(token)) {
  196. throw new CustomizationException(ExceptionEnum.OTHER_PLACE_LOGIN);
  197. }
  198. // 如果需要校准 ip,再加上即可
  199. }
  200. /**
  201. * 获得token中的信息
  202. *
  203. * @return token中包含的名称
  204. */
  205. public static Map<String, Object> getDetails(String token) {
  206. if (null == token) {
  207. token = getToken();
  208. }
  209. try {
  210. DecodedJWT jwt = JWT.decode(token);
  211. Map<String, Claim> map = jwt.getClaims();
  212. Map<String, Object> returnMap = new HashMap<>();
  213. for (Map.Entry<String, Claim> entry : map.entrySet()) {
  214. String k = entry.getKey();
  215. String v = jwt.getClaim(k).asString();
  216. returnMap.put(k, v);
  217. }
  218. return returnMap;
  219. } catch (Exception e) {
  220. return null;
  221. }
  222. }
  223. /**
  224. * 根据请求头获取token
  225. *
  226. * @return
  227. */
  228. public static String getToken() {
  229. HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
  230. String tokenHeader = request.getHeader(TOKEN_HEADER);
  231. if (StringUtils.isBlank(tokenHeader)) {
  232. throw new CustomizationException(ExceptionEnum.TOKEN_NOT_FOUND);
  233. }
  234. String token = tokenHeader.replace(JwtUtil.TOKEN_PREFIX, "");
  235. if (StringUtils.isBlank(tokenHeader)) {
  236. throw new CustomizationException(ExceptionEnum.TOKEN_NOT_FOUND);
  237. }
  238. return token;
  239. }
  240. }