feat: [auth] JwtService

This commit is contained in:
tjq 2023-03-25 23:33:34 +08:00
parent a919524135
commit 2628c312d2
7 changed files with 151 additions and 63 deletions

View File

@ -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";
}
}

View File

@ -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<String, Object> body);
Map<String, Object> parse(String jwt);
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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";
}
}

View File

@ -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;
/**
* <a href="https://music.163.com/#/song?id=167975">GoodSong</a>
*/
private static final String BASE_SECURITY =
"CengMengXiangZhangJianZouTianYa" +
"KanYiKanShiJieDeFanHua" +
"NianShaoDeXinZongYouXieQingKuang" +
"RuJinWoSiHaiWeiJia"
;
@Override
public String build(Map<String, Object> body) {
final String secret = secretProvider.fetchSecretKey();
return innerBuild(secret, jwtExpireTime, body);
}
static String innerBuild(String secret, int expireSeconds, Map<String, Object> 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<String, Object> parse(String jwt) {
return innerParse(secretProvider.fetchSecretKey(), jwt);
}
static Map<String, Object> innerParse(String secret, String jwtStr) {
final Jws<Claims> claimsJws = Jwts.parserBuilder()
.setSigningKey(genSecretKey(secret))
.build()
.parseClaimsJws(jwtStr);
Map<String, Object> 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);
}
}

View File

@ -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<String, Object> 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<String, Object> 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;
}
}