mirror of
https://github.com/PowerJob/PowerJob.git
synced 2025-07-17 00:00:04 +08:00
feat: [auth] JwtService
This commit is contained in:
parent
a919524135
commit
2628c312d2
@ -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";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
package tech.powerjob.server.auth.jwt;
|
package tech.powerjob.server.auth.jwt;
|
||||||
|
|
||||||
import tech.powerjob.server.auth.PowerJobUser;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JWT 服务
|
* JWT 服务
|
||||||
@ -10,5 +10,7 @@ import tech.powerjob.server.auth.PowerJobUser;
|
|||||||
*/
|
*/
|
||||||
public interface JwtService {
|
public interface JwtService {
|
||||||
|
|
||||||
String generateToken(PowerJobUser user);
|
String build(Map<String, Object> body);
|
||||||
|
|
||||||
|
Map<String, Object> parse(String jwt);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,7 +7,7 @@ package tech.powerjob.server.auth.jwt;
|
|||||||
* @author tjq
|
* @author tjq
|
||||||
* @since 2023/3/20
|
* @since 2023/3/20
|
||||||
*/
|
*/
|
||||||
public interface TokenProvider {
|
public interface SecretProvider {
|
||||||
|
|
||||||
String fetchToken();
|
String fetchSecretKey();
|
||||||
}
|
}
|
@ -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";
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user