- 项目软件要对外提供部分定制接口,为了保证软件数据的安全性,决定要设置token令牌来校验请求方是否合法。考虑诸多种方案后,决定使用比较流行的JWT来实现。
- 实现思路:客户端每次访问接口的时候,要在header中携带token令牌,然后在项目的拦截器中使用相应的策略配置拦截这些对外接口的请求(例如这一类接口的url统一配置为/api/开头),拦截到请求后从header中得到token进行校验,校验通过后即可放行。通过不了返回相应状态码,客户端得到状态码携带账号和密码向服务端申请token,服务端验证账号密码合法后生成token返回,token具有时效性。
- 有了思路之后,开始进行开发,首先,pom.xml中配置jwt包,注意,jwt包需要依赖一个codec的jar包,版本过低的话会出现NoSuchMethodError,详情见上篇文章。
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
public class TokenManager {
//私钥
private static final String SECRET = "Axmk89Li3Aji9M";
//过期时间1分钟
private static final int expiresTime = 60000;
public static String createToken(Long userId){
//获取加上过期时间后的时间
Date nowDate = new Date();
System.out.println(nowDate);
Date expiresDate = new Date(System.currentTimeMillis()+expiresTime);
Map<String,Object> map = new HashMap<String,Object>();
map.put("alg", "HS256");
map.put("typ", "JWT");
String token = JWT.create().withHeader(map) //请求头
.withClaim("iss", "Service") //签发方
.withClaim("aud", "Client") //接收方
.withClaim("userId", null==userId?null:userId.longValue()) //存储信息,用户ID
.withIssuedAt(nowDate) //当前时间
.withExpiresAt(expiresDate) //过期时间
.sign(Algorithm.HMAC256(SECRET)); //私钥
return token;
}
public static boolean verifyToken(String token){
try{
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
verifier.verify(token);
//DecodedJWT verify = verifier.verify(token);
//return verify.getClaims(); //能返回数据集合(用于在jwt中存储一些数据)的,但是由于这一版本只需要核验token是否合法,所以只需要返回true和false;
return true;
}catch(Exception e){
log.error(e.getMessage(), e);
return false;
}
}
}
- 有了token工具类之后,在拦截器中配置拦截url为/api/开头的请求,然后从header中得到token进行校验,校验通过即放行,不通过返回相应的状态码。
//以下为验证token的
if(uri.startsWith("api/")){
try{
String token = request.getHeader("token");
//如果token不为空,则可以进入下一步核验
if(!StringUtils.isBlank(token)){
if(!TokenManager.verifyToken(token)){
log.info("token验证未通过,token为:"+token);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().print("{\"code\":" + Constants.ERR_CODE_USER_NOT_LOGIN + ",\"msg\":\"未登录或登录超时,请重新登录!\"}");
return false;
}
return true;
}
return false;
}catch(Exception e){
log.error(e.getMessage(), e);
return false;
}
}
- 然后编写token获取接口,让客户端传账号和密码过来,校验通过后生成token,这个就不赘述了。一个简单的jwt生成token实现验证就完成了,其实还可以在token中传一些非敏感信息,拿到token后取出进行更加仔细的核验。