001package top.cenze.utils; 002 003import cn.hutool.core.collection.CollectionUtil; 004import cn.hutool.core.util.ObjectUtil; 005import cn.hutool.core.util.StrUtil; 006import lombok.SneakyThrows; 007import lombok.extern.slf4j.Slf4j; 008import org.apache.commons.lang3.StringUtils; 009import org.apache.http.auth.AuthenticationException; 010import top.cenze.utils.crypt.HMacUtil; 011 012import javax.servlet.http.HttpServletRequest; 013import java.util.LinkedHashMap; 014import java.util.List; 015import java.util.regex.Matcher; 016import java.util.regex.Pattern; 017 018/** 019 * @desc: Token工具 020 * @author: chengze 021 * @createByDate: 2023/12/13 11:33 022 */ 023@Slf4j 024public class TokenUtil { 025 026 /** 027 * 解析BearerToken(HttpServletRequest) 028 * bearer token是一种认证方式,是一种安全令牌,拥有 bearer token 的任何一方(被称为 "bearer"),可以以任何方式,和同样持有它的任何一方一样地使用它来访问受 OAuth 2.0保护的资源。 029 * 在java中,一般把bearer token放到请求头的Authorization中,我们可以通过正则来判断token的合法性,并返回头中的有效token 030 * https://blog.csdn.net/Gefangenes/article/details/130778194 031 * https://www.python100.com/html/90I8A2I7EMG0.html 032 * https://blog.csdn.net/weixin_42399342/article/details/112157011 033 * @param request 034 * @return 035 */ 036 public static String resolveBearerTokenFromRequest(HttpServletRequest request) throws AuthenticationException { 037 String authorization = request.getHeader("Authorization"); 038 039 return resolveBearerTokenFromAuthorization(authorization); 040 } 041 042 /** 043 * 解析BearerToken(Authorization) 044 * @param authorization 045 * @return 046 * @throws AuthenticationException 047 */ 048 public static String resolveBearerTokenFromAuthorization(String authorization) throws AuthenticationException { 049 log.info("resolveBearerTokenFromAuthorization authorization: {}", authorization); 050 Pattern authorizationPattern = Pattern.compile("^Bearer (?<token>[a-zA-Z0-9-:._~+/]+=*)$", Pattern.CASE_INSENSITIVE);//<token>的值就是真实的表达式配置的值 051 052 if (!StringUtils.startsWithIgnoreCase(authorization, "bearer")) { 053 return null; 054 } 055 056 Matcher matcher = authorizationPattern.matcher(authorization); 057 if (!matcher.matches()) { 058 throw new AuthenticationException("Bearer token is malformed"); 059 } 060 061 // 从上面的正则表达式中获取token 062 return matcher.group("token"); 063 } 064 065 /** 066 * 生成HS256 JWT Token 067 * @return 068 */ 069 public static String createHS256JWTToken(String appId, String appSecret) { 070 return createHS256JWTToken(appId, appSecret, null); 071 } 072 073 /** 074 * 生成HS256 JWT Token 075 * https://blog.csdn.net/qq_51705526/article/details/123939826?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-8-123939826-blog-122104594.235^v39^pc_relevant_3m_sort_dl_base1&spm=1001.2101.3001.4242.5&utm_relevant_index=11 076 * https://www.jb51.net/article/259817.htm 077 * @param appId 078 * @param appSecret 079 * @return 080 */ 081 @SneakyThrows 082 public static String createHS256JWTToken(String appId, String appSecret, Long iat) { 083 log.info("createHS256JWTToken appId: {}, appSecret: {}, iat: {}", appId, appSecret, iat); 084 LinkedHashMap<String, Object> header = new LinkedHashMap<>(); 085 header.put("alg", "HS256"); 086 header.put("typ", "JWT"); 087 088 if (ObjectUtil.isNull(iat)) { 089 iat = System.currentTimeMillis() / 1000; 090 } 091 LinkedHashMap<String, Object> payload = new LinkedHashMap<>(); 092 payload.put("iat", iat); 093 payload.put("sub", appId); 094 095 String data = Base64Util.urlEncode(header) + "." + Base64Util.urlEncode(payload); 096 log.info("createHS256JWTToken data: {}", data); 097// String data = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjYWlwaSIsImlhdCI6MTUxNjIzOTAyMn0"; 098 099// Mac hmac = Mac.getInstance(HmacAlgorithm.HmacSHA256.getValue()); 100// SecretKeySpec secretKey = new SecretKeySpec(appSecret.getBytes("UTF-8"), HmacAlgorithm.HmacSHA256.getValue()); 101// hmac.init(secretKey); 102// byte[] bytes = hmac.doFinal(data.getBytes("UTF-8")); 103// return Base64.encodeUrlSafe(bytes); 104 return data + "." + HMacUtil.SHA256(data, appSecret); 105 } 106 107 /** 108 * 转BearerToken 109 * @param token 110 * @return 111 */ 112 public static String toBearerToken(String token) { 113 return "Bearer " + token; 114 } 115 116 /** 117 * 验证token(鉴权) 118 * @param token 119 * @param appSecret 120 * @return 121 */ 122 public static boolean validBearerToken(String token, String appSecret) { 123 log.info("validBearerToken token: {}, appSecret: {}", token, appSecret); 124 if (StrUtil.isEmpty(token) || StrUtil.isEmpty(appSecret)) { 125 return false; 126 } 127 128 token = token.replaceAll("Bearer ", ""); 129 if (StrUtil.isEmpty(token)) { 130 return false; 131 } 132 133 List<String> split = StrUtil.split(token, "."); 134 if (CollectionUtil.isEmpty(split) || split.size() < 3) { 135 return false; 136 } 137 138 String sign = HMacUtil.SHA256(split.get(0) + "." + split.get(1), appSecret); 139 return split.get(2).equals(sign); 140 } 141}