diff --git a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/jwt/DefaultTokenProvider.java b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/jwt/DefaultTokenProvider.java deleted file mode 100644 index c4c46df1..00000000 --- a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/jwt/DefaultTokenProvider.java +++ /dev/null @@ -1,17 +0,0 @@ -package tech.powerjob.server.auth.jwt; - -import org.springframework.stereotype.Component; - -/** - * PowerJob 默认实现 - * - * @author tjq - * @since 2023/3/20 - */ -@Component -public class DefaultTokenProvider implements TokenProvider { - @Override - public String fetchToken() { - return "ZQQ"; - } -} diff --git a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/jwt/JwtService.java b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/jwt/JwtService.java index 2e4067f8..b6a661fe 100644 --- a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/jwt/JwtService.java +++ b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/jwt/JwtService.java @@ -1,6 +1,6 @@ package tech.powerjob.server.auth.jwt; -import tech.powerjob.server.auth.PowerJobUser; +import java.util.Map; /** * JWT 服务 @@ -10,5 +10,7 @@ import tech.powerjob.server.auth.PowerJobUser; */ public interface JwtService { - String generateToken(PowerJobUser user); + String build(Map body); + + Map parse(String jwt); } diff --git a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/jwt/JwtServiceImpl.java b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/jwt/JwtServiceImpl.java deleted file mode 100644 index 228a5521..00000000 --- a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/jwt/JwtServiceImpl.java +++ /dev/null @@ -1,42 +0,0 @@ -package tech.powerjob.server.auth.jwt; - -import io.jsonwebtoken.JwtBuilder; -import io.jsonwebtoken.Jwts; -import io.swagger.v3.oas.annotations.servers.Server; -import org.springframework.beans.factory.annotation.Value; -import tech.powerjob.server.auth.PowerJobUser; - -import javax.annotation.Resource; -import java.util.Date; -import java.util.UUID; - -/** - * JWT 默认实现 - * - * @author tjq - * @since 2023/3/20 - */ -@Server -public class JwtServiceImpl implements JwtService { - - @Resource - private TokenProvider tokenProvider; - - private int jwtExpireTime; - - @Override - public String generateToken(PowerJobUser user) { - - JwtBuilder jwtBuilder = Jwts.builder() - .setHeaderParam("typ", "JWT") - .setHeaderParam("alg", "HS256") - .claim("userId", user.getId()) - .claim("username", user.getUsername()) - .setSubject("PowerJob") - .setExpiration(new Date(System.currentTimeMillis() + 1000L * jwtExpireTime)) - .setId(UUID.randomUUID().toString()) - .signWith(null); - - return null; - } -} diff --git a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/jwt/TokenProvider.java b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/jwt/SecretProvider.java similarity index 78% rename from powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/jwt/TokenProvider.java rename to powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/jwt/SecretProvider.java index a5228869..349f393e 100644 --- a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/jwt/TokenProvider.java +++ b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/jwt/SecretProvider.java @@ -7,7 +7,7 @@ package tech.powerjob.server.auth.jwt; * @author tjq * @since 2023/3/20 */ -public interface TokenProvider { +public interface SecretProvider { - String fetchToken(); + String fetchSecretKey(); } diff --git a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/jwt/impl/DefaultSecretProvider.java b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/jwt/impl/DefaultSecretProvider.java new file mode 100644 index 00000000..d3faf327 --- /dev/null +++ b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/jwt/impl/DefaultSecretProvider.java @@ -0,0 +1,18 @@ +package tech.powerjob.server.auth.jwt.impl; + +import org.springframework.stereotype.Component; +import tech.powerjob.server.auth.jwt.SecretProvider; + +/** + * PowerJob 默认实现 + * + * @author tjq + * @since 2023/3/20 + */ +@Component +public class DefaultSecretProvider implements SecretProvider { + @Override + public String fetchSecretKey() { + return "ZQQ"; + } +} diff --git a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/jwt/impl/JwtServiceImpl.java b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/jwt/impl/JwtServiceImpl.java new file mode 100644 index 00000000..b7360630 --- /dev/null +++ b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/jwt/impl/JwtServiceImpl.java @@ -0,0 +1,84 @@ +package tech.powerjob.server.auth.jwt.impl; + +import com.google.common.collect.Maps; +import io.jsonwebtoken.*; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; +import io.swagger.v3.oas.annotations.servers.Server; +import org.springframework.beans.factory.annotation.Value; +import tech.powerjob.server.auth.jwt.JwtService; +import tech.powerjob.server.auth.jwt.SecretProvider; + +import javax.annotation.Resource; +import java.security.Key; +import java.util.Date; +import java.util.Map; +import java.util.UUID; + +/** + * JWT 默认实现 + * + * @author tjq + * @since 2023/3/20 + */ +@Server +public class JwtServiceImpl implements JwtService { + + @Resource + private SecretProvider secretProvider; + + /** + * JWT 客户端过期时间 + */ + @Value("${oms.auth.security.jwt.expire-seconds:604800}") + private int jwtExpireTime; + + /** + * GoodSong + */ + private static final String BASE_SECURITY = + "CengMengXiangZhangJianZouTianYa" + + "KanYiKanShiJieDeFanHua" + + "NianShaoDeXinZongYouXieQingKuang" + + "RuJinWoSiHaiWeiJia" + ; + + @Override + public String build(Map body) { + + final String secret = secretProvider.fetchSecretKey(); + return innerBuild(secret, jwtExpireTime, body); + } + + static String innerBuild(String secret, int expireSeconds, Map body) { + JwtBuilder jwtBuilder = Jwts.builder() + .setHeaderParam("typ", "JWT") + .addClaims(body) + .setSubject("PowerJob") + .setExpiration(new Date(System.currentTimeMillis() + 1000L * expireSeconds)) + .setId(UUID.randomUUID().toString()) + .signWith(genSecretKey(secret), SignatureAlgorithm.HS256); + return jwtBuilder.compact(); + } + + @Override + public Map parse(String jwt) { + return innerParse(secretProvider.fetchSecretKey(), jwt); + } + + static Map innerParse(String secret, String jwtStr) { + final Jws claimsJws = Jwts.parserBuilder() + .setSigningKey(genSecretKey(secret)) + .build() + .parseClaimsJws(jwtStr); + Map ret = Maps.newHashMap(); + claimsJws.getBody().forEach(ret::put); + return ret; + } + + private static Key genSecretKey(String secret) { + byte[] keyBytes = Decoders.BASE64.decode(BASE_SECURITY.concat(secret)); + return Keys.hmacShaKeyFor(keyBytes); + } + +} diff --git a/powerjob-server/powerjob-server-auth/src/test/java/tech/powerjob/server/auth/jwt/JwtServiceImplTest.java b/powerjob-server/powerjob-server-auth/src/test/java/tech/powerjob/server/auth/jwt/JwtServiceImplTest.java new file mode 100644 index 00000000..61c3c2a4 --- /dev/null +++ b/powerjob-server/powerjob-server-auth/src/test/java/tech/powerjob/server/auth/jwt/JwtServiceImplTest.java @@ -0,0 +1,43 @@ +package tech.powerjob.server.auth.jwt; + +import com.google.common.collect.Maps; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; +import tech.powerjob.server.auth.jwt.impl.JwtServiceImpl; + +import java.util.Map; + +/** + * test JWT + * + * @author tjq + * @since 2023/3/25 + */ +@Slf4j +class JwtServiceImplTest { + + @Test + void testEncodeAndDecode() { + Map body = Maps.newHashMap(); + body.put("userId", 277); + body.put("name", "tjq"); + + final String jwtToken = JwtServiceImpl.innerBuild("tjq", 2, body); + log.info("[JWT] token: {}", jwtToken); + final Map retMap = JwtServiceImpl.innerParse("tjq", jwtToken); + log.info("[JWT] parse result: {}", retMap); + + body.forEach((k, v) -> { + assert v.equals(retMap.get(k)); + }); + + // 不匹配情况 + boolean throwExp = false; + try { + JwtServiceImpl.innerParse("zqq", jwtToken); + } catch (Exception e) { + throwExp = true; + } + assert throwExp; + } +} \ No newline at end of file