需求背景
Joget默认的网络服务插件是平台级且完全开放的, 如果你在基础设置里面设置了域名白名单为 *, 且服务器部署在外网 ,这会导致你的网络接口可以被所有人请求到.
如果有黑客恶意攻击,可能会有不可预知的风险.因此,我们在这里引入了JWT http://jwt.io 作为网络服务的安全机制.
JWT简介
参见 https://jwt.io/introduction/
如何使用
1.引入Maven依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.8.2</version>
</dependency>
2.Jwt工具类
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import org.joget.commons.util.LogUtil;
import java.util.Date;
public class JWTUtil {
/**
* 创建token
* @param expire_time 单位秒,过期时间
* @return
*/
public static String createToken(String id,Long expire_time){
Date expiresDate = new Date(System.currentTimeMillis() + expire_time*1000 );
String token = "";
try {
Algorithm algorithm = Algorithm.HMAC256("secret");
token = JWT.create()
.withKeyId(id)
.withExpiresAt(expiresDate)
.withIssuer("zihao")
.sign(algorithm);
} catch (JWTCreationException exception){
//Invalid Signing configuration / Couldn't convert Claims.
}
return token;
}
/**
* 解析token
* @return
*/
public static DecodedJWT verifyToken(String token){
try {
Algorithm algorithm = Algorithm.HMAC256("secret");
JWTVerifier verifier = JWT.require(algorithm)
.build(); //Reusable verifier instance
DecodedJWT jwt = verifier.verify(token);
return jwt;
} catch (JWTVerificationException e){
//Invalid signature/claims
//LogUtil.info("JWTUtil",e.getMessage());
}
return null;
}
public static void main(String[] args) {
String id = "uuid";
String token = JWTUtil.createToken(id,1L);
// try {
// Thread.sleep(2L*1000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
DecodedJWT jwt = JWTUtil.verifyToken(token);
String keyId = jwt.getKeyId();
String jwtIssuer = jwt.getIssuer();
System.out.println("keyId : "+ keyId);
System.out.println("issuer : " + jwtIssuer);
}
}
3. 完善你自己的网络服务接口
- 接口需要通过参数控制获取token,同时生成UID
- 接口附带token请求需要验证token的有效期和UID(UID和Token放在Header中)
if (get_jwt_token.equalsIgnoreCase("get_jwt_token")){
String uid = UUID.randomUUID().toString();
String token = JWTUtil.createToken(uid,120L);
result.put("errcode", "0");
result.put("errmsg", "请求成功");
result.put("uid", uid);
result.put("jwt_token", token);
result.write(response.getWriter());
return;
}else if (StringUtils.isEmpty(request.getHeader("jwt-token"))){
result.put("errcode", "40001");
result.put("errmsg", "缺少TOKEN");
result.write(response.getWriter());
return;
}
if (!StringUtils.isEmpty(jwt_token)){
DecodedJWT jwt = JWTUtil.verifyToken(jwt_token);
//如果jwt为空,则秘钥过期
if (StringUtils.isEmpty(jwt)){
result.put("errcode", "40001");
result.put("errmsg", "TOKEN已过期");
result.write(response.getWriter());
return;
}else {
String id = jwt.getKeyId();
String uid = request.getHeader("uid");
//LogUtil.info( getClass().getName(), "id : " + id);
//LogUtil.info( getClass().getName(), "uid : " + uid);
if (StringUtils.isEmpty(uid) ||
!uid.equals(id)){
result.put("errcode", "40001");
result.put("errmsg", "UID不正确");
result.write(response.getWriter());
return;
}
LogUtil.info( getClass().getName(), "token verify success ! ");
}
}